一涩金、原型
在JS設(shè)計出來的時候,只是為了實現(xiàn)一樣網(wǎng)頁的簡單交互暇仲,并沒有想過把JS設(shè)計成為一門面向?qū)ο蟮恼Z言步做。后來的發(fā)展,JAVA和C++等語言都有了自己的Class用于繼承奈附,所以JS也想要實現(xiàn)繼承全度,所以就出現(xiàn)了原型prototype
二、原形鏈
function Person(){
}
var p = new Person()
對應的原型鏈結(jié)構(gòu)為
每個構(gòu)造函數(shù)都有一個原型屬性prototype
每個對象都有 __proto__
屬性斥滤,指向了創(chuàng)建該對象的構(gòu)造函數(shù)的原型将鸵。其實這個屬性指向了 [[prototype]]勉盅,但是 [[prototype]] 是內(nèi)部屬性,我們并不能訪問到咨堤,所以使用 _proto_
來訪問菇篡。
對象可以通過 __proto__
來尋找不屬于該對象的屬性漩符,__proto__
將對象連接起來組成了原型鏈
默認的原型鏈就是:
當前對象-->構(gòu)造函數(shù).prototype-->Object.prototype-->null
注意: 原型和實例上都有一個constructor
構(gòu)造器指向構(gòu)造函數(shù)
Function.prototype.constructor === new Function().constructor
三.構(gòu)造函數(shù)繼承
構(gòu)造繼承
原型繼承
實例繼承(閉包繼承)
拷貝繼承
組合繼承
寄生組合繼承
優(yōu)缺點考慮方向: 實例化的次數(shù)一喘,是否父類子類實例,是否可以復用
1.構(gòu)造繼承
使用父類的構(gòu)造函數(shù)來增強子類實例嗜暴,等于賦值父類的實例屬性給子類
function Animal(){
this.species = "動物";
}
function Cat(name){
Animal.call(this)
Animal.apply(this)
//相當于 Animal()
//this.species = '動物' this指向Cat內(nèi)部
console.log(this)//Cat
this.name = name;
}
var cat = new Cat("大毛")
缺點:
1.實例并不是父類的實例凸克,只是子類的實例
2.只能繼承父類的實例屬性和方法,不能繼承原型屬性和方法
2.原型繼承
使用構(gòu)造函數(shù)的prototype
指向父對象的一個實例,需要注意把子構(gòu)造函數(shù)的constructor
構(gòu)造器重新指向自己闷沥,因為使用prototype指向了父構(gòu)造函數(shù)的prototype,會出現(xiàn)原型鏈紊亂
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛","黃色");
alert(cat1.species); // 動物
原型繼承升級版
function Animal(){ }
Animal.prototype.species = "動物";
Cat.prototype = Animal.prototype;
Cat.prototype.constructor = Cat;
var cat1 = new Cat("大毛");
alert(cat1.species); // 動物
缺點:
1.無法實現(xiàn)多繼承
2.創(chuàng)建子類實例時萎战,無法想父類構(gòu)造函數(shù)傳參
3.實例繼承
為父類實例添加新特性,作為子類實例返回
function Cat(name){
var instance = new Animal();
instance.name = name || '';
return instance;
}
var cat1 = new Cat('大毛')
缺點
1.實例是父類的實例舆逃,不是子類的實例
2.不支持多繼承
4.拷貝繼承
把父對象的所有屬性和方法蚂维,拷貝進子對象
function Animal(){}
Animal.prototype.species = "動物";
function Cat(name){
this.name = name;
}
function extend(Child, Parent) {
var p = Parent.prototype;
var c = Child.prototype;
for (var i in p) {
c[i] = p[i];
}
}
extebd(Cat, Animal)
var cat1 = new Cat('大毛')
alert(cat1.species)
缺點:
1.效率低,內(nèi)存占用高(因為需要拷貝父類的屬性)
2.無法拷貝對象和數(shù)組
5.組合繼承
通過調(diào)用父類構(gòu)造路狮,繼承父類的屬性并保留可以傳參虫啥,然后通過將父類實例作為子類原型,實現(xiàn)函數(shù)復用
function Animal(){ this.species = '動物'}
function Cat(name){
Animal.apply(this)
this.name = name
}
Cat.prototype = new Animal()
Cat.prototype.constructor = Cat
var cat1 = new Cat('大毛')
優(yōu)點:
1.可以繼承實例屬性和方法也可以繼承原型方法
2.即是子類的實例奄妨,也是父類的實例
3.可傳參
4.函數(shù)可復用
缺點: 調(diào)用了兩次父類構(gòu)造函數(shù)涂籽,生成了兩份實例
寄生組合繼承
通過計生方式,去掉父類的實例屬性砸抛,這樣评雌,在調(diào)用兩次父類的構(gòu)造函數(shù)的時候,就不會初始化兩次實例
function Cat(name){
Animal.call(this)
this.name = name
}
(function(){
//創(chuàng)建一個沒有實例方法的類
var Supe = function(){}
Super.prototype = Animal.prototype
//將實例作為子類的原形
Cat.prototype = new Super()
Cat.prototype.constructor = Cat
}())
var cat = new Cat('大毛')
優(yōu)點
1.比起組合繼承直焙,減少了一次實例化父類景东,節(jié)省內(nèi)存
四、非構(gòu)造函數(shù)的繼承
object()繼承
淺拷貝
深拷貝
1.objecc()繼承
實現(xiàn)object()
函數(shù)奔誓,把子對象的prototype屬性
耐薯,指向父對象,使得父子對象連在一起
function object(o){
function F(){}
F.prototype = o
return new F()
}
var guangzhou = object(Chinese)
2.淺拷貝
把父對象的屬性丝里,全部拷貝給子對象曲初,也能實現(xiàn)繼承
function copy(p){
var c = {}
for(var i in p){//[]則遍歷牽引值 {}則遍歷屬性名
c[i] = p[i]
}
return c
}
3.深拷貝
深拷貝,能夠?qū)崿F(xiàn)真正意義上的數(shù)組和對象的拷貝杯聚,只需要遞歸地調(diào)用淺拷貝
function deepCopy(p,c){
var c = c || {}
for(var i in p){
if(typeof i === 'object'){ //typeof arr && typeof object => object
var c[i] = (p[i].constructor === Array) ? []: {}
deepCopy(p[i], c[i])
}else{
c[i] = p[i]
}
}
return c
}