L - JavaScript繼承

類式繼承(原型鏈繼承)

實現

function A(){
    this.a='a';
    this.arr=[1,2];
}
A.prototype.funA=function(){
    console.log("我是A的方法");
    
}
function B(){
    this.b='b';
}
B.prototype.funB=function(){
    console.log("我是B的方法");
}
B.prototype=new A();

var b1=new B();

因爲A的實例可以訪問A.prototype,因此咱們能夠設置B.prototype指向A的實例。因此B的實例能夠訪問A的實例以及A.prototype,實現繼承app

缺點:

1.因爲對象類型的賦值是引用賦值,若是父類A實例化過程當中有引用類型,那麼子類B的實例的這個屬性都指向同一內存空間。函數

function A(){
    this.a='a';
    this.arr=[1,2];
}
A.prototype.funA=function(){
    console.log("我是A的方法");
    
}
function B(){
    this.b='b';
}
B.prototype.funB=function(){
    console.log("我是B的方法");
}
B.prototype=new A();

var b1=new B();
var b2=new B();

b1.arr.push(3);
console.log(b1.arr);    // [1, 2, 3]
console.log(b2.arr);    // [1, 2, 3]

2.若是父類的實例須要傳入一些參數,那麼兩個子類實例初始化時某一屬性值相同this

function A(year){
    this.year=year;
}
function B(){
    this.b='b';
}
B.prototype=new A(18);

var b1=new B();
var b2=new B();
console.log(b1.color);    // 18
console.log(b2.color);    // 18

3.B.prototype中constructor指向不正確,由於B.prototype指向了一個A的實例,因此本應指向B的constructor指向了Aprototype

function A(year){
    this.year=year;
}
function B(){
    this.b='b';
}
B.prototype=new A(18);

var b1=new B();

b1.constructor===A    // true

構造函數繼承(借用構造函數繼承)

實現

function A(color){
    this.a='a';
    this.arr=[1,2];
    this.color=color;
}
A.prototype.funA=function(){
    console.log("我是A的方法");
    
}
function B(color){
    A.call(this,color);
}
B.prototype.funB=function(){
    console.log("我是B的方法");
}

var b1=new B("red");

console.log(b1)    // {a: "a", arr: Array(2), color: "red"}

優勢

解決了引用賦值問題,也能夠自定義一些屬性了,constructor也指向B了,即解決了類式繼承的第一個、第二個問題以及第三個問題code

缺點

很明顯,B除了調用了A這個函數外並無和A扯上什麼關係,原型鏈是不通的(沒法訪問到應該做爲父類的A的prototype屬性),我甚至並不以爲這是一種繼承方式,但它爲下面兩種方法奠基了基礎對象

b1.__proto__===B.prototype   // true
b1.__proto__.__proto__===Object.prototype    // true

組合繼承

說白了,就是將上述兩種方法的長處組合到一塊兒,利用原型鏈實現原型屬性和方法的繼承,經過借用構造函數實現對實例屬性的繼承繼承

實現

function A(color){
    this.a='a';
    this.arr=[1,2];
    this.color=color;
}
A.prototype.funA=function(){
    console.log("我是A的方法");
    
}
function B(color,age){
    // 經過借用構造函數實現對實例屬性的繼承
    A.apply(this,[color]);
    this.age=age;
}

// 利用原型鏈實現原型屬性和方法的繼承
B.prototype=new A();
B.prototype.constructor=B;

var b1=new B('red',18);

優勢

既經過在原型上定義方法實現了函數複用,又可以保證每一個實例都有它本身的屬性內存

缺點

調用了兩次父類的構造函數原型鏈

寄生組合式繼承(此方法最好)

實現

function A(color){
    this.a='a';
    this.arr=[1,2];
    this.color=color;
}
A.prototype.funA=function(){
    console.log("我是A的方法");
    
}
function B(color,age){
    A.apply(this,[color]);
    this.age=age;
}

B.prototype=Object.create(A.prototype);
B.prototype.constructor=B;

var b1=new B('red',18);

優勢

只需訪問一次父類的構造函數,避免了在子類的prototype上建立沒必要要、多餘的屬性原型

相關文章
相關標籤/搜索