js 中的繼承

繼承就是讓一個對象擁有另外一個對象的屬性和方法app

1、原型鏈繼承(兩種)

  一、Son.prototype = Father.prototype (原型繼承)函數

  (1)Son的實例對象只能繼承Father實例中原型的方法,沒法繼承Father自己的屬性。this

function Father(){
    this.age = 50;
    this.h = 15
}
Father.prototype.eat = function(){
    console.log(this.age); // 25 
    console.log(this.h); // undefined
}
function Son(){
    this.age = 25;
}
Son.prototype = Father.prototype;
var son = new Son()
son.eat()
// son繼承Father原型中的eat函數,因此this.age指向Son,故 25
// this.h 彈出undefined 說明沒法繼承Father自己的屬性

  二、Son.prototype = new Father() (實例化對象繼承)spa

  原理:就是把構造函數Father()的實例化對象father的屬性和方法繼承到構造函數Son()的原型上。修改的屬性是實例化對象father的屬性,每次實例化一個構造函數Son(),都是從father上繼承,故屬性相通。prototype

  (1)優先查找自身屬性,若是有的話優先使用,若是沒有則從繼承中查找code

  (2)繼承的構造函數的不一樣實例化對象的屬性不會互相影響;不一樣的Son實例對象會共享繼承Father的實例化對象father的屬性。這樣的話修改一個Son實例化對象son的arr,Son實例化對象son1的arr也會改變,修改被繼承Fathe實例化對象father的屬性時會影響繼承者Son繼承的屬性對象

function Father(){
    this.age = 50;
    this.arr = [1,2,3]
    this.h = 15;
}
Father.prototype.eat = function(){
    console.log(this.age); 
    console.log(this.h);
}
function Son(){
    this.age = 25;    
}
var father = new Father();
Son.prototype = father;
var son = new Son();
son.eat();
// 25 說明當son優先查找自身屬性
// 15 說明son繼承Father實例對象的屬性
son.arr.push(4)
console.log(son.arr); // [1,2,3,4]
console.log(father.arr)  // [1,2,3]
var son1 = new Son()
console.log(son1.arr);// [1,2,3,4] 說明不一樣的Son實例對象會共享繼承Father的實例化對象father的屬性
father.arr.push(5)
console.log(father.arr)// [1,2,3,5]
console.log(son.arr);// [1,2,3,4,5] 說明修改被繼承Fathe實例化對象father的屬性時會影響繼承者Son繼承的屬性

  對於繼承後 Son.prototype.constructor指向的問題,是否須要修改能夠查看 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/constructorblog

 

2、構造函數繼承

  在繼承構造函數裏經過call或者apply或bind修改被繼承函數的this。繼承

  一、繼承屬性會覆蓋自身屬性,ip

  二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響

  三、沒法繼承原型上的方法,

function Father(){
    this.age = 50;
    this.hello = "你好";
    this.arr = [1,2,3];
}
Father.prototype.cat = function(){
    console.log(cat);
}
function Son(){
    // 三種方式
    this.age = 25;
    Father.call(this);
    // Father.bind(this)();
    // Father.apply(this);
}
var son = new Son(15)
console.log(son.age); // 50 // 說明繼承屬性會覆蓋自身屬性
console.log(son.hello); // 你好
try{
    son.cat()
}catch(e){
    console.log(e); 
// TypeError: son.cat is not a function
}
son.arr.push(4);
console.log(son.arr); // [1,2,3,4]
var son1 = new Son(25);
console.log(son1.arr); // [1,2,3]
// 這說明構造函數Son的不一樣實例化對象的屬性是不相通,修改實例化對象  

3、組合式繼承 (原型鏈與構造函數)

  在原型鏈繼承中Son.prototype = Father.prototype只能繼承Fanther的原型上的方法,在構造函數繼承中,Fathe.call(this)只能繼承構造函數的屬性,二者結合。

  一、繼承屬性會覆蓋自身屬性

  二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響

function Father(){
	this.age = 50;
	this.hello = "你好";
	this.arr = [1,2,3];
};
Father.prototype.eat=function(){
	console.log("這是Father構造函數原型上方法");
}
function Son(){
	this.age = 25;
	Father.call(this)
};
Son.prototype = Father.prototype;

var son = new Son();
console.log(son.age); // 50 說明繼承的屬性會覆蓋自身的屬性
console.log(son.hello); //你好
son.arr.push(4)
son.eat()
var son1 = new Son();
console.log(son.arr); //[1,2,3,4]
console.log(son1.arr); // [1,2,3]
// 說明同一構造函數的不一樣實例化對象之間屬性不相通;

  弊端:經過Father.call() 和Father.prototype ,父類構造函數Father被調用了兩次。繼承屬性會覆蓋原屬性

 

4、原型式繼承 (我的認爲這種方式和原型鏈Son.prototype = new Father()的原理是一致的,各類表現也是一致)

  一、優先查找自身屬性,若是有的話優先使用,若是沒有則從繼承中查找

  二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響;

function Father(){
    this.age = 50;
    this.hello = "你好";
    this.arr = [1,2,3]
};
Father.prototype.eat = function(){
    console.log("這是Father原型上的方法");
}
function content(obj){
    function Son(){
        this.age = 25;
    };
    Son.prototype = obj; // 傳入繼承構造函數Father的實例化對象father
    return new Son();
}
var father = new Father();
var son = content(father);
console.log(son.hello); //你好 說明繼承構造函數Father實例化對象father上的屬性。
console.log(son.age); // 25 // 說明優先查找自身是否有某屬性,有的話優先調用自身屬性
son.eat() // 這是Father原型上的方法  說明繼承了構造函數Father實例化對象father上的方法

son.arr.push(4)
var son1 = content(father)
console.log(son.arr); // [1,2,3,4]
console.log(son1.arr); // [1,2,3,4] 說明這個不一樣實例間繼承的屬性是相通的

 

5、寄生式繼承(在原型式繼承的基礎上,對Son實例化的外面添加函數封裝而已,表現一致)

  一、優先查找自身屬性,若是有的話優先使用,若是沒有則從繼承中查找

  二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響;

function Father(){
    this.age = 50;
    this.hello = "你好";
    this.arr = [1,2,4];
};
Father.prototype.eat = function(){
    console.log("這是Father構造函數原型上的方法");
}
function content(obj){
    function Son(){
        this.age = 25;
    };
    Son.prototype = obj;
    return new Son();
}
function subObject(obj){
    var son = content(obj)
    son.name = 'son 名字' // 可直接對son添加屬性
    return son
}
var father = new Father()
var son1 = subObject(father) 
console.log(son1.age);//25
console.log(son1.hello);//你好
console.log(son1.name); // son 名字
son1.eat(); // 這是構造函數原型上的方法
son1.arr.push(4)
var son2 = content(father)
console.log(son1.arr); // [1,2,3,4]
console.log(son2.arr); // [1,2,3,4] 說明這個不一樣實例間繼承的屬性是相通的

 

6、寄生組合式繼承  (構造函數繼承與寄生式繼承組合)

  一、寄生屬性會覆蓋原屬性

  二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響

  三、與組合式繼承相比效果相同,可是更加複雜。

function Father(){
    this.age = 50;
    this.hello = "你好";
    this.arr = [1,2,3];
};
function content(obj){
    function Son(){
        this.age = 25;
    };
    Son.prototype = obj;
    return new Son();
};
var son = content(Father.prototype)
// var son = content(new Father()) 效果一致

function Sub(){
    Father.call(this);
    // Father.apple(this);
    // Father.bind(this)();
};
Sub.prototype = son; 
son.constructor = Sub;
var sub = new Sub();
console.log(sub.age); // 50 說明繼承的屬性會覆蓋自身的屬性
console.log(sub.hello); // 你好
sub.arr.push(4)
console.log(sub.arr); // [1,2,3,4]
var sub1 = new Sub();
console.log(sub1.arr); // [1,2,3]
// 說明同一構造函數的不一樣實例化對象之間屬性不相通;

 

 7、Object.assign()  

  與組合式繼承基本相同,除了Son.prototype = Object.create(Father.prototype),對原型繼承的方式不同

  一、寄生屬性會覆蓋原屬性

  二、繼承的構造函數的不一樣實例化對象的屬性不會互相影響

// Father - 父類(superclass)
function Father() {
  this.age = 50;
  this.arr = [1,2,3]
}

// 父類的方法
Father.prototype.move = function(x, y) {
  console.info('Father moved.');
};

// Son - 子類(subclass)
function Son() {
    this.age = 25;
  Father.call(this); // call super constructor.
}

// 子類續承父類
Son.prototype = Object.create(Father.prototype);
// Son.prototype.constructor = Son;

var son = new Son();
console.log(son.age); // 50 說明繼承屬性覆蓋原屬性
son.move(); // Father moved
son.arr.push(4)
console.log(son.arr); // [1,2,3,4]
var son1 = new Son();
console.log(son1.arr); // [1,2,3]
// 說明不一樣實例之間數據不相通,可複用
相關文章
相關標籤/搜索