手寫JavaScript:繼承、拷貝、instanceOf

繼承

繼承目前有八種以上的方式實現(xiàn):原型鏈繼承、構(gòu)造函數(shù)繼承、組合繼承、寄生式、組合寄生式繼承、ES6類繼承extends等等。

組合寄生式繼承:最成熟和完美的繼承方式,解決了組合式兩次調(diào)用父類的構(gòu)造函數(shù)造成浪費的缺點。組合式繼承還有個問題,子類不是父類的實例,而子類的原型是父類的實例。寄生式繼承依托于原型繼承,寄生就像蟲子一樣,依托于某個對象,在其內(nèi)部生長(添加新方法和屬性),它是對原型繼承的第二次封裝。

思路:我們通過原型繼承拿到父類的副本,但還不能直接賦值給子類,因為父類原型對象復制得到的副本中constructor指向不是子類對象,所以在寄生式繼承中對這個副本做一次增強,修復其constructor屬性指向不明確的問題,最后得到的副本賦值給子類的原型。

核心代碼

function inheritPrototype(subType, superType){
// 創(chuàng)建對象,創(chuàng)建父類原型的一個副本
  var prototype = Object.create(superType.prototype); 
// 增強對象,彌補因重寫子類原型而失去的默認的constructor屬性
  prototype.constructor = subType;    
// 指定對象,將新創(chuàng)建的對象賦值給子類的原型                
  subType.prototype = prototype;                      
}

繼承實例

// 父類初始化實例屬性和原型屬性
function SuperType(name){
  this.name = name;
  this.colors = ["red", "blue", "green"];
}
SuperType.prototype.sayName = function(){
  alert(this.name);
};

// 定義子類,借用構(gòu)造函數(shù)傳遞增強子類實例屬性(支持傳參和避免篡改)
function SubType(name, age){
  //構(gòu)造函數(shù)式繼承
  SuperType.call(this, name);
  //子類新增屬性
  this.age = age;
}

// 將父類原型指向子類
inheritPrototype(SubType, SuperType);

// 新增子類原型方法
SubType.prototype.sayAge = function(){
  alert(this.age);
}
//測試
var instance1 = new SubType("xyc", 23);
var instance2 = new SubType("lxy", 23);

instance1.colors.push("2"); // ["red", "blue", "green", "2"]
instance1.colors.push("3"); // ["red", "blue", "green", "3"]


拷貝

參考文章: js 深拷貝vs淺拷貝

數(shù)據(jù)類型的賦值

  • 基本類型
  1. 基本數(shù)據(jù)類型存放在棧中(系統(tǒng)自動分配和釋放內(nèi)存)
  2. 基本數(shù)據(jù)類型的值不可改變,動態(tài)改變返回的是一個新的變量
  3. 基本類型的比較,是值的比較
  • 引用類型
  1. 引用類型存放在堆中(內(nèi)存不會自動釋放),變量實際上是一個指向存放在棧內(nèi)存的指針
  2. 引用類型的值可以改變
  3. 引用類型比較是引用的比較(指針指向相同)

賦值和拷貝的區(qū)別

深拷貝:將 B 對象拷貝到 A 對象中,包括 B 里面的子對象,

淺拷貝:將 B 對象拷貝到 A 對象中,但不包括 B 里面的子對象


賦值和拷貝對比

淺拷貝核心代碼

function shallowCopy(src) {
  var dst = {};
    for (var prop in src) {
        if (src.hasOwnProperty(prop)) {
            dst[prop] = src[prop];
        }
    }
    return dst;
}

深拷貝核心代碼

乞丐版
《你不知道的JavaScript(上)》中提及:
對于JSON安全(也就是可以被序列化為一個JSON字符串并且可以根據(jù)這個字符串解析出一個結(jié)構(gòu)和值完全一樣的對象)的對象來說,有一種巧妙的復制方法,代碼如下:

var newObj = JSON.parse(JSON.stringify(someObj));

這種方法要保證對象是JSON安全的,所以只適用于部分情況。

完美版
思路:遇到簡單類型,直接復制return;遇到復雜類型,賦值簡單類型,遞歸遍歷子復雜類型。

function deepCopy(obj){
    //判斷是否是簡單數(shù)據(jù)類型
    if(typeof obj == 'object'){
    //復雜數(shù)據(jù)類型
    var result = obj.constructor == Array ? [] : {};
        for(let i in obj){
        //若是對象,就是result[屬性名];若是數(shù)組,就是result[下標]
        result[i] = typeof obj[i] == "object" ? deepCopy(obj[i]) : obj[i];
        }
    }
    else{
    //簡單數(shù)據(jù)類型
        var result = obj;
    }
    return result;
}


instanceOf

思路是順著原型鏈一直找,直到null

function instanceOf(left,right){
    let proto = left.__proto__;
    let prototype = right.prototype;
    while(true) {
        if(proto === null) return false
        if(proto === prototype) return true
        proto = proto.__proto__;
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容