目錄javascript
@java
1.函數與函數的原型對象(prototype object):瀏覽器
(1) 構造函數-->原型對象 (A.prototype-->B)安全
(2) 原型對象-->構造函數 (B.constructor-->A)ecmascript
(3) 實例對象-->原型對象 (A1.[[Prototype]]/A1._ proto _-->B)
函數
2.基於三種引用的操做
如上圖,咱們基於這三種引用會有許多的操做(修改,替換,刪除),咱們來進行一個分析總結.性能
構造函數建立實例的具體過程
參考資料:
英文版--new [[Construct]] [[Call]]
中文版--new [[Construct]] [[Call]]
new A();
1.令ref = 構造函數A的引用(地址)
2.令變量constructor = GetValue(ref): 按照ref找到函數對象A的存儲單元
3.調用constructor的[[Construct]]內部方法:測試
總結: 由上面的分析可知,若是在構造函數A的函數體內用this給實例添加的屬性,是不會反映到原型上的,屬於實例的自己的屬性.this
三種引用是否能夠被更改的測試
prototype
//TEST:三種引用是否均可以修改替換
function A (){}
var B = A.prototype;
var A1 = new A();
//A.prototype與B.constructor
console.log(Object.getOwnPropertyDescriptor(A,'prototype'));//可修改
console.log(Object.getOwnPropertyDescriptor(B,'constructor'));//可修改
//[[Prototype]]
console.log('prototype' in A1); //false,內部屬性不屬於原型屬性
console.log(A1.hasOwnProperty('prototype'));//false,內部屬性不屬於自身屬性
//只有獲取方法,沒有手動修改方法
//__ proto __
console.log(' __ proto __ ' in A1);
console.log(A1.hasOwnProperty(' __ proto __ '));//false, __ proto __ 屬於原型屬性
console.log(Object.prototype.hasOwnProperty(' __ proto __ '));//true,__ proto __ 定義在Object.prototype上
console.log(Object.getOwnPropertyDescriptor(Object.prototype, ' __ proto __ '));//configurable:true enumerable:false
//利用 __ proto __ 間接修改[[prototype]] (不推薦)
function C() {}
var D = C.prototype;
console.log(Object.getPrototypeOf(A1));
A1. __ proto __ = D; //利用非規範屬性 __ proto __ 間接修改[[prototype]]
console.log(Object.getPrototypeOf(A1));
總結: __ proto __屬性是非標準的,是定義在Object.prototype上的一個暴露實例內部[[prototype]]屬性的訪問器屬性.若是咱們考慮到代碼的安全和性能,咱們能夠在代碼開始位置用delete Objet.prototype. _ _ proto _ _
來刪除掉.
替換構造函數A的原型--修改A.prototype的值
預計的影響:
1.已有實例的原型不變,但沒法再用A.prototype添加或修改原型屬性
2.新實例的原型是A.prototype修改後的值,而且能夠用A.prototype添加或修改原型屬性
//TEST:構造函數替換原型對象的影響
function A() {}
function B() {}
var A1 = new A();
var B1 = new B();
A.prototype.say = function (){
alert('A鏈的方法');
}
B.prototype.say = function (){
alert('B鏈的方法');
}
var temp = B.prototype;
B.prototype = A.prototype;
A.prototype = temp;
var A2 = new A();
var B2 = new B();
//檢測A1 A2 B1 B2 各自的原型鏈
A1.say();
B1.say();
A2.say();
B2.say();
//嘗試經過原有構造函數向A1添加原型屬性
A.prototype.say2 = function (){
alert('仍能夠經過A向A1添加原型屬性');
}
A.prototype.say3 = function (){
alert('能夠經過A向A2添加原型屬性');
}
alert('say2' in A1);//false,A1.say2方法不存在.不能再經過A向A1添加原型屬性
A2.say3();//添加成功
替換已有實例的原型
預計影響:
1.接上了另外一條原型鏈
2.沒法再用A.prototype添加或修改原型屬性
//TEST:已有實例對象修改原型對象的影響
function A() {}
function B() {}
var A1 = new A();
var B1 = new B();
A.prototype.say = function (){
alert('A鏈的方法');
}
B.prototype.say = function (){
alert('B鏈的方法');
}
//測試是否接到另外一條原型鏈
var A2 = Object.create(A1);
A2.say();
A2.__ proto __ = B1;
A2.say();
//測試是否不能再用原來的構造函數添加原型屬性
var A3 = new A();
A3.__ proto __ = B1;
A.prototype.say2 = function (){
alert('仍然可用構造函數添加原型屬性');
}
A3.say2(); //出錯,A3中找不到方法say2()
替換原型的構造函數--A.prototype.constructor
影響:
1.只是沒法再用A.prototype.constructor獲取構造函數A,沒法便捷地添加'靜態方法'了
2.仍能正經常使用A建立實例,用A.prototype添加或修改原型屬性
1.instanceof運算符
參考資料:instanceof [[HasInstance]](V)
instaceof運算符,是將左邊對象的原型做爲參數,來調用右邊函數的[[HasInstance]] (V)內部方法,所得返回值即爲運算符的結果.
[[HasInstance]] (V)方法大體過程:(以A.[[HasInstance]] (V)爲例)
//TEST: instanceof原理測試:向上搜索實例的原型鏈,看由構造函數所指向的原型對象是否在其中
function A() {}
var A1 = new A();
var B = A.prototype;
console.log(A1 instanceof A);//true
B.constructor = null;
console.log(A1 instanceof A);//true
A.prototype = {};
console.log(A1 instanceof A);//false
2.屬性遍歷
注:歡迎轉載,轉載請註明出處