JS 詳解對象的繼承

在學習這篇博文前,請先移步個人另一篇博文:JS 一張圖理解prototype、proto和constructor的關係,先弄清楚「原型鏈」,這樣對於理解繼承會很是有效。

注意:博文中提到的「屬性」,指的是「屬性+方法」,這裏統稱爲「屬性」;html

1、構造函數繼承

var obj = new Object();   使用構造函數new一個對象實例(因此程序員每天都在談對象,哈哈哈)程序員

特色:app

  • 實例對象繼承父類的共有屬性和私有屬性

來個實例加深理解:

function Animal() {
    this.type = '動物';
}
Animal.prototype.getType = function(){
    console.log(this.type);
}
let animal = new Animal();
console.log(animal.type);  // 動物
animal.getType(); // 動物

2、原型鏈繼承

Child.prototype = new Parent();   將父類的實例做爲子類的原型ssh

特色:函數

  • 子類的prototype上的全部屬性將被徹底覆蓋,因此子類的prototype屬性應該在覆蓋後從新定義;
  • 子類的constructor指向父類,爲了構造函數的完整性,須要從新指定子類的constructor屬性,方法:Child.prototype.constructor = Child;
  • 修改子類與父類同名的屬性,不會修改父類的屬性;這是由於父類的屬性在子類的原型鏈上,且這些屬性至關因而子類的__prototype__或者更加上一級。(這裏若是理解不了,說明沒理解透 JS 一張圖理解prototype、proto和constructor的關係 這篇文章)
原型繼承,並非把父類的屬性和方法COPY一份給子類,而是讓子類的原型和父類原型之間搭建一個連接的橋樑,之後子類(或者子類的實例),能夠經過原型鏈的查找機制,找到父類原型上的方法,從而調取這些方法使用便可。

來個實例加深理解:

function Animal() {
    this.type = '動物';
}
Animal.prototype.getType = function(){
    console.log(this.type);
}
function Cat(){
    this.vary = '';
}
Cat.prototype.getVary = function(){
    console.log(this.vary);
}
Cat.prototype = new Animal();
var cat = new Cat();
// cat.getVary() // 報錯:cat.getVary is not a function [緣由:Cat.prototype = new Animal()的操做覆蓋了原型鏈]
console.log(cat.constructor); // Animal 這個constructor實質調用的是Animal.prototype.constructor

// 修改Cat類的constructor爲Cat
Cat.prototype.constructor = Cat;
console.log(cat.constructor); // Cat

cat.getType(); // 動物
// 修改Cat類prototype上的getType方法,看是否影響Animal類的getType方法
Cat.prototype.getType = function(){
    console.log('我是貓科類');
}
var animal = new Animal();
animal.getType(); // 動物

 3、call、apply、bind繼承

在子類的構造體中,使用call、apply、bind方法,讓父類方法中的this指向子類的實例,也就是改變this的上下文環境。學習

特色:this

  • 子類構造體繼承父類的私有屬性(繼承完成後,子類和父類是不要緊的)

先來個call實現原理,很重要的哦

Function.prototype.call2 = function () {
  var ary = [...arguments].slice(1);
  if (!arguments[0]) {
    this(...ary);
  } else {
    var obj = Object(arguments[0]); // 將參數變成一個對象
    obj.__proto__.fn = this;
    obj.fn(...ary);
    delete obj.__proto__.fn;
  }
};

來個實例加深理解:

function Animal() {
    this.type = '動物';
}
Animal.prototype.getType = function(){
    console.log(this.type);
}
function Cat(){
    Animal.call(this);
    this.vary = '';
}
Cat.prototype.getVary = function(){
    console.log(this.vary);
}
var cat = new Cat();
console.log(cat.type); // 動物
// cat.getType(); // Uncaught TypeError: cat.getType is not a function
cat.type = '貓科動物';
var animal = new Animal();
console.log(animal.type); // 動物

 4、寄生組合繼承

var child = Object.create(obj, props); spa

  • obj:一個對象,應該是新建立的對象的原型。
  • props:可選。該參數對象是一組屬性與值,該對象的屬性名稱將是新建立的對象的屬性名稱,值是屬性描述符

我先來一段Object.create的實現方式(看懂原理很重要)prototype

Object.create =  function (o) {
    var F = function () {};
    F.prototype = o;
    return new F();
};

咱們這裏只分析參數obj的騷操做,能夠看出來,Object.create是內部定義一個對象,而且讓F.prototype對象賦值爲引進的對象/函數 o,並return出一個對象的實例。code

只要看懂了原理,咱們能夠參考「原型鏈繼承」的方式去理解這種繼承方法;

來個實例加深理解:

function Animal() {
    this.type = '動物';
}
Animal.prototype.getType = function(){
    console.log(this.type);
}

var cat = Object.create(new Animal(), {
    vary: {
        value: '貓科動物'
    }
});
console.log(cat.constructor); // Animal 這個constructor實質調用的是Animal.prototype.constructor
console.log(cat.type); // 動物
cat.getType(); // 動物
console.log(cat.vary); // '貓科動物'
相關文章
相關標籤/搜索