引言
從關鍵字new 說起
我來試著模擬一下new的操作過程。
//模擬new關鍵字的行為
function methodnew( func ) //func:新物件的建構函式
; //{}實際上等價於object()
obj.constructor = func; //更改obj的constructor屬性
obj.__proto__ = func.prototype; //設定obj.__proto__屬性,從而訪問到原型鏈上的屬性,
//比如 func.prototype.name可以通過 obj.name讀取,但是不能使用obj.name來修改,這樣會為obj新增乙個name屬性。
//這裡只處理func方法引數為空的情況
func.call( obj ); //為obj新增func方法中定義的屬性,比如
//function func()
//相當於執行obj.name = "jerry"
return obj;
}}
來測試一下
function
people()}
var obj = methodnew( object );
var beauty = methodnew( people );
console.log( obj );
console.log( beauty );
結果如下
object
{}people
結果與new關鍵字生成的物件一致。
稍微總結一下,new關鍵字的行為與後面的方法是不是object()有關,
在非object()方法時,執行下面四步
1.
var obj = {}; //生成乙個object物件
2. obj.constructor = func; //設定constructor,由此判斷物件的型別由constructor屬性決定
3. obj.__proto__ = func.prototype; //這一步很關鍵,將obj連入原型鏈,從而能訪問func.prototype物件以及它的原型鏈上端物件的屬性
4. func.call( obj ); //為obj新增func()方法中宣告的屬性
這裡我把__proto__
放在前面,因為它是原型鏈的基礎。
people.prototype
.hobby = "籃球"
;people.prototype
.swim = function();
var obj = {};
obj.__proto__ = people.prototype
;console.log( obj.hobby );
obj.swim
;
物件訪問屬性的順序是先查詢自身,顯然hobby和swim都不是obj自身的屬性,這是系統會查詢obj.__proto__
指向的物件是否有這兩個屬性,這裡就是people.prototype,如果還沒有,會繼續找people.prototype.__proto__
指向的物件有沒有所需屬性,這裡有乙個知識點,宣告乙個函式people()時,people.prototype屬性指向誰呢?
根據我的研究,函式的prototype屬性的初始化很簡單,分為兩步
1. people.prototype = {}; //將乙個object物件賦給prototype
2. people.prototype.constructor = people; //設定constructor為people,表示原型物件的型別是people
因為people.prototype是乙個普通的object物件,所以有
people.prototype.__proto__
指向object.prototype,
這與圖中的描述是吻合的。
如此一來,下面的原型鏈就形成了
obj−→
−−−−
−−−__proto__
people.prototype−→
−−−−
−−−__proto__
object.prototype−→
−−−−
−−−__proto__
null
有一條對原型鏈文章的評價:js物件其實就是鍵值對,說的不錯,js中的方法和變數都以物件的形式存在,乙個物件能訪問到的其實就是自己的屬性和原型鏈上的屬性。
看看下面的例子
people.prototype
.hobby = "籃球"
;people.prototype
.swim = function();
var obj = {};
obj.__proto__ = people.prototype
; obj.hobby );
;obj.hobby = "撩妹"
;console.log( people.prototype
.hobby );
發現結果仍然是籃球
,說明這裡是為obj新增了自己的hobby屬性,並沒有改動原型物件的屬性。
我們再做進一步測試
people.prototype
.sing = function()
var obj = {};
obj.song = "愛的供養"
;obj.__proto__ = people.prototype
;obj.sing();
people.prototype
.sing
.call( obj );
//結果
//愛的供養*2
這一步解釋了原型物件中的方法是怎麼被執行的。
圖中function與object的關係比較令人費解,其實可以這麼理解。
js中所有的物件都是由函式通過new操作符生成的,比如
var obj = new people()
則一定有obj.__proto__ == people.prototype'
而所有的函式物件都是由function()函式生成的,object()方法也不例外,所以有
object.__proto__ = function.prototype
當然,function()方法也是由自己生成的,所以推出
function.__proto__ = function.prototype
(其實object()方法和function()方法都是本地**(native code),也就是事先寫好的,並不是生成的物件,原型鏈中這樣設計是為了邏輯的完備)。
這裡比較特殊的兩個物件是function.prototype和object.prototype,這兩個物件的生成不符合上面提到的規律
1. people.prototype = {};
2. people.prototype.constructor = people;
function.prototype作為function的原型物件是由function()函式直接返回的,並不是乙個object物件,而且這個屬性是唯讀的,它的值顯示如下
function empty() {}
從邏輯上來說, 所有的函式物件也應該能訪問object.prototype的屬性,所以有
function.protototype.__proto__ = object.prototype
讓所有的函式物件通過function.prototype訪問原型鏈的末端object.prototype。
作為原型鏈的尾端,object.prototype的屬性可以被js中的所有物件訪問,object.prototype的__proto__
是唯讀的,這保證了object.prototype作為原型鏈的乙個出口。
我對js原型和原型鏈的用法
優點 1.資料共享 節約記憶體記憶體空間 2.實現繼承 我們知道在js中,萬物皆物件,物件可以說是重中之重了。每乙個物件都擁有自己的屬性。但是在這個世界中有很多東西都是相似的,可以歸為一類,他們有共同的方法和屬性。不可能讓每乙個物件都定義乙個屬性吧。那樣太消耗記憶體了。所以,在js中怎麼才能讓多個物...
對JS原型機原型鏈的理解
使用建構函式建立物件 function person var person1 newperson person1.name 張三 console.log person1.name 張三 person就是乙個建構函式,通過new建立了person1物件例項。其實建構函式和普通函式沒有多大區別,首先字母...
js 原型 原型鏈理解
執行發現如下 自定義乙個函式,函式包含兩個關鍵資料 prototype,proto 1 原型 prototype person具有prototype屬性 包含我們定義的屬性name,age以及constructor,並且constructor指向我們的person函式,可以理解為prototype就...