一日客語:中文:晚上 客語:暗晡am buˊ
function Plant() {}
function Apple() {}
Apple.prototype.shape = 'circle';
Apple.prototype = new Plant();//現在Apple的prototype是放 Plant的實例
const myapple = new Apple();
console.log(myapple.constructor);//[Function: Plant]
使用原型繼承會讓constructor指向Plant function,使myapple的constructor不是Apple function,從程式碼的寫法來說明明是建構函式Apple所建立的實例,但顯示的建構子會是plant function。
原本constructor可以判斷由哪一個函式建立,現在卻不是預期的樣子
如果使用原型繼承又要讓constructor是Apple?
語法:Object.defineProperty(obj, prop, descriptor)
對物件設定新屬性或修改物件屬性回傳設定好的物件
Object.defineProperty(定義的物件, 屬性,屬性描述子)
物件內的每一個屬性都有property descriptor
property descriptor | 說明 |
---|---|
configurable | 物件的property 是否可以被修改/刪除 |
enumerable | 物件的property是否被for/in 迴圈Object.keys() |
writable | 物件的property的值是否能被改變 |
value | 設定屬性值 |
get | 定義取值getter function 可以取得屬性值,不能和value/writable一起設定 |
set | 定義設值setter function 可以設定屬性指派的值,不能和value/writable一起設定 |
所以descriptor也是一個物件
這個屬性的值可以修改嗎
true:可以修改
false:不可以修改
const apple = {};
Object.defineProperty(apple, 'color', {
value: 'red',
writable: false,
});
apple.color = 'gold';
console.log(apple.color);//red
const apple = {};
Object.defineProperty(apple, 'color', {
value: 'red',
writable: true,
});
apple.color = 'gold';
console.log(apple.color);//gold
是否可以被for/in迭代列出
目標:設定apple的shape屬性,是不可以被for/in迭代列出
作法:把property descriptor的enumerable設成false
let apple = {};
Object.defineProperty(apple, 'color', { value: 'red', enumerable: true });
Object.defineProperty(apple, 'shape', { value: 'circle', enumerable: false });
Object.defineProperty(apple, 'size', { value: 'small', enumerable: true });
Object.defineProperty(apple, 'price', { value: 10000, enumerable: true });
for (let i in apple) {
console.log(i);
}
//color
//size
//price
取值時,啟動get,return 出fruit[0]//apple出去
const map = {
fruit: ['apple', 'orange', 'banana'],
get eat() {
return this.fruit[0];
},
set eat(value) {
this.fruit[0] = value;
},
};
console.log(map.eat);//apple
賦值時,啟動set,會把value(water)賦值到fruit[0]
const map = {
fruit: ['apple', 'orange', 'banana'],
get eat() {
return this.fruit[0];
},
set eat(value) {
this.fruit[0] = value;
},
};
map.eat = 'water';
//現在fruit: ['water', 'orange', 'banana']
function Go() {}
function Run() {}
Go.prototype.school = 'sleep';
Run.prototype = new Go();
const student = new Run();
console.log(student.constructor);//[Function: Go]
解決方式:就是在property descriptor 讓Apple.prototype的constructor設定為 Apple,且不讓他被改寫也讓他不要出現在for-in迴圈
function Plant() {}
function Apple() {}
Apple.prototype.shape = 'circle';
Apple.prototype = new Plant();
const myapple = new Apple();
Object.defineProperty(Apple.prototype, 'constructor', {
value: Apple,
enumerable: false,
writable: false,
});
console.log(myapple.constructor); //Function: Apple]
這樣方式既可以繼承,constructor也是指向當初建立的函式
學完一整套原型鏈~讚
資料參考:
忍者開發技巧探秘第二版
mdn