原型鏈問題之 __proto__
警告: 通過現代瀏覽器的操作屬性的便利性,可以改變一個物件的 [[Prototype]]
屬性, 這種行為在每一個JavaScript引擎和瀏覽器中都是一個非常慢且影響效能的操作,使用這種方式來改變和繼承屬性是對效能影響非常嚴重的,並且效能消耗的時間也不是簡單的花費在 obj.__proto__ = ...
語句上, 它還會影響到所有繼承來自該 [[Prototype]]
的物件,如果你關心效能,你就不應該在一個物件中修改它的 [[Prototype]].。相反, 建立一個新的且可以繼承 [[Prototype]]
Object.create()
。
警告: 當Object.prototype.__proto__
已被大多數瀏覽器廠商所支援的今天,其存在和確切行為僅在ECMAScript 2015規範中被標準化為傳統功能,以確保Web瀏覽器的相容性。為了更好的支援,建議只使用 Object.getPrototypeOf()
。
Object.prototype
的 __proto__
屬性是一個訪問器屬性(一個getter函式和一個setter函式), 暴露了通過它訪問的物件的內部[[Prototype]]
null
)。
使用__proto__
是有爭議的,也不鼓勵使用它。因為它從來沒有被包括在EcmaScript語言規範中,但是現代瀏覽器都實現了它。__proto__
屬性已在ECMAScript 6語言規範中標準化,用於確保Web瀏覽器的相容性,因此它未來將被支援。它已被不推薦使用, 現在更推薦使用Object.getPrototypeOf
/Reflect.getPrototypeOf
和Object.setPrototypeOf
/Reflect.setPrototypeOf
(儘管如此,設定物件的[[Prototype]]是一個緩慢的操作,如果效能是一個問題,應該避免)。
__proto__ 屬性也可以在物件文字定義中使用物件[[Prototype]]來建立,作為Object.create()
的一個替代。 請參閱: object initializer / literal syntax.
let Circle = function () {};
let shape = {};
let circle = new Circle();
// 設定該物件的原型鏈引用
// 過時且不推薦使用的。這裡只是舉個例子,儘量不要在生產環境中這樣做。
shape.__proto__ = circle;
// 判斷該物件的原型鏈引用是否屬於circle
console.log(shape.__proto__ === circle); // true
let shape = function () {};
let p = {
a: function () {
console.log('aaa');
}
};
shape.prototype.__proto__ = p;
let circle = new shape();
circle.a();//aaa
console.log(shape.prototype === circle.__proto__);//true
//或者
let shape = function () {};
var p = {
a: function () {
console.log('a');
}
};
let circle = new shape();
circle.__proto__ = p;
circle.a(); // a
console.log(shape.prototype === circle.__proto__);//false
//或者
function test() {}
test.prototype.myname = function () {
console.log('myname');
}
let a = new test()
console.log(a.__proto__ === test.prototype);//true
a.myname();//myname
//或者
let fn = function () {};
fn.prototype.myname = function () {
console.log('myname');
}
let obj = {
__proto__: fn.prototype
};
obj.myname();//myname
注意:這是兩個下劃線,後面是五個字元的 “proto” ,後面再跟兩個下劃線。
描述
_proto__的讀取器(getter)暴露了一個物件的內部 [[Prototype]]
。對於使用物件字面量建立的物件,這個值是 Object.prototype
。對於使用陣列字面量建立的物件,這個值是 Array.prototype
。對於functions,這個值是Function.prototype
。對於使用 new fun 建立的物件,其中fun是由js提供的內建構造器函式之一(Array
, Boolean
, Date
, Number
, Object
, String
等等),這個值總是fun.prototype。對於用js定義的其他js構造器函式建立的物件,這個值就是該構造器函式的prototype屬性。
__proto__ 的設定器(setter)允許物件的 [[Prototype]]被變更。前提是這個物件必須通過
Object.isExtensible()
判斷為是可擴充套件的,如果不可擴充套件,則會丟擲一個 TypeError
錯誤。要變更的值必須是一個object或null
,提供其它值將不起任何作用。
要理解原型如何被使用,請檢視相關文章:Inheritance and the prototype chain。
.__proto__屬性是Object.prototype
一個簡單的訪問器屬性,其中包含了get(獲取)和set(設定)的方法,任何一個__proto__的存取屬性都繼承於Object.prototype
,但一個訪問屬性如果不是來源於Object.prototype
就不擁有.__proto__屬性,譬如一個元素設定了其他的.__proto__屬性在Object.prototype
之前,將會覆蓋原有的Object.prototype
。