js繼承實現之Object.create

同事前幾天去面試,回來同步了一下面試題庫,其中一道題就是」new和Object.create的區別」。聽到這個題目,個人第一個反映是 , what?( ⸝⸝⸝°_°⸝⸝⸝ ), Object.create這個東東我沒有用過,怎麼回答。爲了不沒法給出response的尷尬,老夫抓緊一切時間開始在console裏演示着。面試

-> demo <-函數

function Person(name, sex) {
   this.name = name;
   this.sex = sex;
}
Person.prototype.getInfo = function() {
   console.log('getInfo: [name:' + this.name + ', sex:' + this.sex + ']');
}
var a = new Person('jojo', 'femal');
var b = Object.create(Person.prototype);

圖片描述

-> 分析 <-學習

赤裸裸的結果,a就是對象Person的實例,a.__proto__ === Person.prototype。what about b ? b是對象F的一個實例,而且b.__proto__ === Person.prototype的。this

這個F究竟是個啥呢? 好了,又到了copy-paste時間了,參考了https://developer.mozilla.org... 其實現的polyfill方法:spa

if (typeof Object.create !== "function") {
    //此方法未考慮create的第二個參數的實現
    Object.create = function (proto, propertiesObject) {
        if (typeof proto !== 'object' && typeof proto !== 'function') {
            throw new TypeError('Object prototype may only be an Object: ' + proto);
        } else if (proto === null) {
            throw new Error("This browser's implementation of Object.create is a shim and doesn't support 'null' as the first argument.");
        }

        if (typeof propertiesObject != 'undefined') throw new Error("This browser's implementation of Object.create is a shim and doesn't support a second argument.");
        //實現一個隱藏函數
        function F() {}
        //函數的原型設置爲參數傳進來的原型
        F.prototype = proto;
        // 返回一個F函數的實例,即此實例的__proto__指向爲參數proto
        return new F();
    };
}

好吧,既然都看了polyfill了,就知道Object.create究竟是幹啥的了,它就是生成了一個實例,這個實例的原型由我來指定,可是它的構造函數F被隱藏了。那下面咱們來驗證一下是否是這個邏輯。prototype

圖片描述

經過Object.create()生成的實例怎麼纔能有本身的屬性呢,別怕,咱們看一下它完成的面目是怎樣的,撒花,揭幕~~Object.create(proto, [propertiesObject]), 人家是有第二個參數滴。能夠本身定義它的屬性,可寫、可配、可枚舉,都可本身定義,實現一條龍自助服務。3d

var b = Object.create(Person.prototype, {
    name: {
        value: 'coco',
        writable: true,
        configurable: true,
        enumerable: true,
    },
    sex: {
        enumerable: true,
        get: function(){ return 'hello sex'},
        set: function(val){console.log('set value:' + val)}
    }
})

-> 更進一步 <-code

說了這麼多,那Object.create的應用價值究竟是什麼呢? 看一下本文標題就知道了,固然說的是繼承了,操刀試一下。對象

function Student(name, sex, age) {
    Person.call(this, name, sex);
    this.age = age;
}
//原型鏈拼接
Student.prototype = Object.create(Person.prototype);
//構造函數彎了,糾正
Student.prototype.constructor = Student;
Student.prototype.getInfo = function() {
    console.log('getInfo: [name:' + this.name + ', sex:' + this.sex + ', age:' +this.age + '].');
}
    
var s = new Student('coco', 'femal', 25);

圖片描述

s是Student的實例,Person.prototype在s的原型鏈上,而且這個F實例的constructor又指回了Student。
既然說到了這裏,那若是想要一個對象繼承多個類怎麼辦呢?在上面的代碼基礎上使用mixin加工下就可啦。blog

//再建立一個基類
function Animal(age) {
 this.age = age;
}
Animal.prototype.say = function(language) { 
    console.log('you say ' + language);
}

function Student(name, sex, age) {
    Person.call(this, name, sex);
    Animal.call(this, age);
}
//原型鏈拼接
Student.prototype = Object.create(Person.prototype);
Object.assign(Student.prototype, Animal.prototype);
Student.prototype.constructor = Student;
Student.prototype.getInfo = function() {
    console.log('getInfo: [name:' + this.name + ', sex:' + this.sex + ', age:' +this.age + '].');
};
var s = new Student('coco', 'femal', 25);

s的原型還是一個F實例,其原型指向了Person,可是這個F實例上mixin了Animal的方法。可是原型鏈上並無Animal什麼事,經過instanceof能夠驗證這一點。這種方式比較適合父類爲同級別,子類只要擁有相同的屬性和方法便可的狀況。

圖片描述

若有異議處,歡迎你們指出來,一塊兒探討。學習費腦掉了好多頭皮屑,不過今天又能夠碎個覺了。

∧__∧( ●ω●) |つ/(___/└-(____/bug>>>bug>>bug>bug  ̄ ̄ ̄ ̄ ̄ ̄

相關文章
相關標籤/搜索