這篇要介紹的是用 Object.create() 這個函式。
Object.create(proto[, propertiesObject])
帶入的兩個參數分別為:
帶入兩個參數後,會從指定的 prototype 物件建立一個新物件,並加上第二個參數的屬性,那這樣產生新物件可以做什麼?我們繼續看下去吧!
讀者可以先閱讀以下程式碼:
function Shape(x, y) {
this.x = x;
this.y = y;
}
Shape.prototype.move = function(x, y) {
this.x += x;
this.y += y;
};
function Rectangle(...args) {
Shape.apply(this, args);
}
const properties = {
name: {
value: "長方形",
enumerable: true,
writable: true,
},
getPos: {
value: function () {
console.log(`Current Position: ${this.x}, ${this.y}.`);
},
},
};
// Rectangle 繼承 Shape 物件
Rectangle.prototype = Object.create(Shape.prototype, properties);
Rectangle.prototype.constructor = Rectangle;
const rect = new Rectangle(0, 0);
閱讀完程式碼後,我們把一些函式的相關資訊都印出來看看:
Rectangle 的原型物件變成了 Shape 物件加上 Object.create() 第二個參數屬性後的物件,其它屬性則和一般函式沒什麼不一樣。
Shape 函式也沒什麼不一樣。
繼續觀察 Rectangle 的原型物件,它的 __proto__
為 Shape 函式的原型物件,但它的建構子指向 Rectangle。
而 new 關鍵字用來建立實體,像範例中的 react 物件。
我們將上面的內容畫成圖片來看:
可以看到 Object.create() 產生的物件在左下角(有最長黑色說明文字的那個),它的兩個屬性指向可以解釋以下兩行程式碼:
Rectangle.prototype = Object.create(Shape.prototype, properties);
Rectangle.prototype.constructor = Rectangle;
第一行就是透過 Object.create() 產生物件,它的 __proto__
是指向 Shape.prototype,所以這樣 Rectangle 函式產生的物件,也能透過原型鏈去取到 Shape 的函式。
第二行則是將 Object.create() 產生的物件的建構子,指向繼承的函式,所以可以看到左下角的物件 constructor 指向 Rectangle 函式。
來看些特別的例子,如果 Object.create() 的第一個參數是傳入 Object.prototype 的話,obj 變數就像是宣告了空物件一樣,也會有物件的一些屬性方法,但如果傳入 null,就不會有物件的任何屬性方法
const obj = Object.create(Object.prototype);
// 等同於: const obj = {};
const empty = Object.create(null);
// empty => null
文章的最後來個小練習題吧,這題是來自於 臉書的一篇貼文,若前面的內容有了解的話,這篇答案就很輕易知道囉~
const employee = {
company: 'levelhunt'
};
const empl = Object.create(employee);
delete empl.company;
console.log(empl.company); // ?
雖然刪除了 empl 物件本身的屬性,但它的 prototype 實際上不會影響,所以還是會印出 'levelhunt'。
JavaScript 核心觀念(51)- 繼承與原型鍊 - 使用 Object.create 建立多層繼承