最初,在通過構(gòu)造函數(shù)Object.create()方法創(chuàng)建對象,其原型是在對象被創(chuàng)建時指定的,對象原型在實例化之后保持不變,ES5中出現(xiàn)了Object.getPrototypeOf()方法來返回任意指定對象的原型,但仍缺少對象在實例化后去修改原型的方法。
ES6中新增了Object.setPrototypeOf()來修改實例指向的原型對象。舉例:
let person = {
name: 'zhangsan',
get() {
return this.name;
}
}
let date = {
time:new Date().getFullYear()+'年',
get() {
return this.time;
}
}
let obj = Object.create(person);
let dt = Object.create(date);
const isAlong = Object.is(Object.getPrototypeOf(obj),person);
console.log(isAlong); // true
console.log(obj.get()); //zhangsan
console.log(dt.get()); // 2021年
上述中先創(chuàng)建兩個基對象(person和date),通過兩個基對象去實例化,再去調(diào)取繼承對象的方法。
修改對象的原型
let person = {
name: 'zhangsan',
get() {
return this.name;
}
}
let date = {
time:new Date().getFullYear()+'年',
get() {
return this.time;
}
}
let obj = Object.create(person);
let dt = Object.create(date);
// 修改對象的原型
Object.setPrototypeOf(obj,date);
const isAlong = Object.is(Object.getPrototypeOf(obj),person);
console.log(isAlong); // false
console.log(obj.get()); // 2021年
console.log(dt.get()); // 2021年

改變對象原型的原理:對象原型的真實值被儲存在內(nèi)部的一個特定的屬性
[[Prototype]]中,調(diào)用Object.getPrototypeOf()方法返回儲存在其中的值,調(diào)用Object.setPrototypeOf()方法改變其中的值。
ES6中引入了Super引用的特性,使其更加快捷的訪問對象原型。
let person = {
name: 'zhangsan',
get() {
return this.name;
}
}
let common = {
get(){
return Object.getPrototypeOf(this).get.call(this) + 'common method'; // 修改對象原型
}
}
let obj = Object.create(person);
Object.setPrototypeOf(common,obj);
console.log(common);
console.log(common.get()); // zhangsancommon method
const isAlong = Object.is(Object.getPrototypeOf(obj),person);
console.log(isAlong); // true
在ES6中,還有一關(guān)鍵字super,super引用相當于指向?qū)ο笤偷闹羔?,實際上也就是等價于Object.setPrototypeOf(this)的值,可以簡化上述的get()方法
let common = {
get(){
return super.get() + 'common method'; // 修改對象原型
}
}
注意點:super引用調(diào)用對象原型上所有其他的方法,必須要在使用簡寫方法的對象中使用super引用,但是如果在其他方法中聲明去使用就會報錯。
比如使用匿名函數(shù)定義一個屬性,由于上下文super引用不合法,則出現(xiàn)報錯
let common = {
get:function(){
return super.get() + 'common method';
}
}

super引用在對于多重繼承的場景非常實用,不會像Object.getPrototypeOf(this).get.call(this)一樣引發(fā)沖突。
let person = {
name: 'zhangsan',
get() {
return this.name;
}
}
let common = {
get(){
return Object.getPrototypeOf(this).get.call(this) + ' common method';
}
}
Object.setPrototypeOf(common,person);
let obj = Object.create(common);
console.log(Object.getPrototypeOf(obj));
console.log(obj.get());

由于this是obj,obj的原型是common對象,obj執(zhí)行common里面的get()方法時,
Object.getPrototypeOf(this)這個返回的是common對象,這樣就導致了棧溢出報錯。使用super更改代碼:
let person = {
name: 'zhangsan',
get() {
return this.name;
}
}
let common = {
get(){
return super.get() + ' common method';
}
}
Object.setPrototypeOf(common,person);
let obj = Object.create(common);
console.log(Object.getPrototypeOf(obj));
console.log(obj.get());
super引用總是能指向正確的對象,因為多重繼承,對于super引用而言,始終指向的都是父級的對象,也就是person對象。