JS繼承方法總結,帶實例

三個概念

  • 構造函數 / 原型對象 / 實例對象
    以內置對象Array爲例,Array是用於構造數組的全局對象。Array構造函數創建的實例數組對象可以繼承使用所有Array.prototype的屬性和方法。
  • 每個函數都有一個prototype屬性,指向一個對象。
function Phone(name,size){
   this.name = name;
   this.size = size;
   this.info = '4G';
   this.main = ['camera','NFC','blueteeth','line'];
   this.call = function(){
       console.log('don\'t forget call me plz')
   }
};

Phone.prototype.send = function(){
   console.log('send message to her')
}

var phone = new Phone('samsung',5.8);
   console.log(phone.name + phone.size);
   phone.call();
   phone.send();

構造函數內部,this指的是一個新生成的空對象,所有針對this的操作,都會發生在這個空對象上。構造函數之所以叫“構造函數”,就是說這個函數的目的,就是操作一個空對象(即this對象),將其“構造”爲需要的樣子。

var world = new Func()命令的過程:

  1. 創建一個空對象,作爲將要返回的對象實例。
  2. 將這個空對象的原型,指向構造函數的prototype屬性。
  3. 將這個空對象賦值給函數內部的this關鍵字。
  4. 執行構造函數內部的代碼。

JS繼承

  • 原型鏈繼承,用一個實例對象a覆蓋構造函數本來指向的原型對象,此時該構造函數生成的實例對象x就可以訪問a的實例方法和a的原型對象A的屬性和方法
  • 原型鏈繼承的缺點,如果一個實例不小心修改了原型對象上引用類型的值,會導致其它實例也跟着受影響。(當實例中存在和原型對象上同名的屬性時,加載實例對象的值。)
function Iphone(name,size){
   this.name = name;
   this.size = size;
}

Iphone.prototype = new Phone();

var iphone = new Iphone('8 Plus');
   console.log(iphone.info);   // 4G
   iphone.call();		       // don't forget call me plz
   iphone.send(); 			   // send message to her

  • 構造函數繼承,子類的構造函數中,通過 apply ( )call ( )的形式,調用父類構造函數,子類構造函數每實例化一個對象(a和b),相當於父類構造函數新生成一個對象(x1和x2,兩個一樣的副本)
  • 每個子類實例都會拷貝一份父類構造函數中的方法,作爲實例自己的方法。方法過多的時候,佔用內存大。當需求改變,要改動其中的一個方法時,之前所有的實例,他們的該方法都不能及時作出更新。
  • Person.call(this)代表:stu1 去調用 Person 方法時,Person 內部的 this 指向就指向了 stu1(正常情況下this所指是新建的空對象,this.name = Jack,現在是stu1.name = Jack)。那麼Person 內部this 上的所有屬性和方法,都被拷貝到了 stu1 上,stu2 也是同理。
  1. 借用構造函數的方式可以在子類型的構造函數中向超類型構造函數傳遞參數。
  2. 爲了確保子類型的熟悉不會被父類的構造函數重寫,可以在調用父類構造函數之後,再添加子類型的屬性。
function Oppo(name){
   this.name = 'myname';
   this.info = '5G';
   Phone.call(this,name);
   // this.info = '5G';   寫在父類構造函數後面才能覆蓋父類的屬性
};
var oppo1 = new Oppo('oppo1');
    oppo1.main.push('finger');
    console.log(oppo1.name);
    console.log(oppo1.info);   // 4G
    console.log(oppo1.main);
    // [ 'camera', 'NFC', 'blueteeth', 'line', 'finger' ]
    
var oppo2 = new Oppo('oppo2');
    console.log(oppo2.name);
    console.log(oppo2.main);
    // [ 'camera', 'NFC', 'blueteeth', 'line' ]

  • 組合繼承,把公有的方法掛載到父類的原型對象上,既能保證子類實例對象有各自的引用對象副本(構造函數),也能避免父類公有方法太多時產生的問題(原型鏈)。
function Huawei(name){
    this.name = name;
    Phone.call(this);
}

Phone.prototype.takePhoto = function(){
    console.log('take a picture');
}
Phone.prototype.weChat = function(){
    console.log('caht with your friend');
}

Huawei.prototype = new Phone();
Huawei.prototype.constructor = Huawei;

var honor1 = new Huawei('honor1');
    console.log(honor1.name);
    honor1.takePhoto();
    honor1.main.push('finger');
    console.log(honor1.main);


var honor2 = new Huawei('honor2');
    console.log(honor2.main);

  • 深 / 淺拷貝

  • 引用對象 / 值對象

  • 複製數組:arr.slice()
    該方法不修改原數組,只會返回一個淺複製了原數組中的元素的一個新數組。原數組的元素會按照下述規則拷貝:
    如果該元素是個對象引用 (不是實際的對象),slice 會拷貝這個對象引用到新的數組裏。兩個對象引用都引用了同一個對象。如果被引用的對象發生改變,則新的和原來的數組中的這個元素也會發生改變。
    對於字符串、數字及布爾值來說(不是 String、Number 或者 Boolean 對象),slice 會拷貝這些值到新的數組裏。在別的數組裏修改這些字符串或數字或是布爾值,將不會影響另一個數組。

  • this

  • call / apply / bind

  • 實例對象的__proto__屬性(前後各兩個下劃線),返回該對象的原型

  • 獲取實例對象obj的原型對象的方法

參考

http://javascript.ruanyifeng.com/oop/basic.html
https://www.cnblogs.com/sarahwang/p/9098044.html
https://blog.csdn.net/liuyan19891230/article/details/50774439

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章