關於JavaScript原型鏈
技術標籤:JavaScript學習關於面試
關於JavaScript原型鏈
建立物件的方法
在瞭解原型鏈之前,先了解以下三種建立物件的幾種方式:
//第一種:字面量
var o1={name:'o1'}
var o2=new Object({name:'o2'})
//第二種:建構函式
var M=function(name){this.name=name;}
var o3=new M('o3')
//第三種:Object.create
var s={name:'s'}
var o4=Object.create(s)
列印結果:
o1:{ name: ‘o1’ }
o2:{ name: ‘o2’ }
o3:M { name: ‘o3’ }
o4:{}
型及原型鏈
先來一張圖
什麼是例項?原型物件?建構函式?
var M=function(name){this.name=name;}
var o3=new M('o3')
在這段程式碼裡:
- 例項就是物件,o3即為例項,M為建構函式
- 例項通過new一個建構函式生成
- 從上圖可知,例項的__proto__指向原型物件,例項的建構函式的prototype也指向原型物件,原型物件的construor指向的是建構函式
- M的prototype指向原型物件,o3的 __proto__也指向同一個原型物件,因為o3是通過M new出來的,即( o3.__proto__===M.prototype) 為true
- 原型物件裡的 constructor 屬性就是建構函式
- M.prototype.constructor===M 為true,即M的原型物件的建構函式就是M本身
那什麼是原型鏈?
每個例項物件 (object )都有一個私有屬性(稱之為 __proto__
)指向它的建構函式的原型物件(prototype )。該原型物件也有一個自己的原型物件( __proto__
) ,層層向上,直到一個物件的原型物件為 null,形成一條原型鏈。根據定義,null 沒有原型,並作為這個原型鏈中的最後一個環節。
原型物件和例項之間有什麼作用呢?
當通過一個建構函式創建出來的多個例項都要新增一個方法時,若給每個例項都去新增該方法並不是一個明智的選擇,這時原型的作用就明顯了。
在例項的原型上新增此方法,那麼這個原型的所有例項就都有了這個方法。
接著上面的例子演示:
var M = function (name) { this.name = name; }
var o3 = new M('o3')
var o5 = new M()
M.prototype.say=function(){
console.log('hello')
}
// o3.__proto__.say=function(){
// console.log('hello')
// }
o3.say()
o5.say()
通過建構函式的prototype屬性和例項的__proto__屬性新增方法都可
列印結果:
hello
hello
【補充】
- 只有函式有prototype,物件是沒有的
- 函式也是有__proto__的,因為函式也是物件
- 函式的__proto__指向Function.prototype
- 即 普通函式是Function這個建構函式的一個例項
instanceof 原理
instanceof判斷的是 例項物件的__proto__和生成該例項的建構函式的prototype是否引用自同一個地址,即判斷constructor.prototype是否存在於例項物件的原型鏈上。
是則返回true,不是返回false。
那麼怎麼判斷例項是由哪個建構函式生成的呢?這時就要用到constructor了。
obj.__proto__.constructor 例項的原型的建構函式
o3.__proto__.constructor===M //true
o3.__proto__,constructor===Object //false
new 運算子
new 關鍵字的操作?
1.建立一個空的簡單JavaScript物件(即{})
2.連結該物件(設定該物件的constructor)到另一個物件
3.將步驟1新建立的物件作為this的上下文
4.若該函式沒有返回物件,則返回this
建立一個使用者自定義物件需要兩步:
1.編寫函式實現定義物件型別
2.通過new建立物件例項
當執行程式碼 new Foo(…) 時,會發生以下事情:
1.一個繼承自Foo.prototype的新物件被建立
2.使用指定的引數呼叫建構函式Foo,並將this繫結到新建立的物件。(new Foo等同於new Foo(),也就是沒有指定引數列表,Foo不帶任何引數呼叫的情況)
3.由建構函式返回的物件就是new表示式的結果(若建構函式沒有顯式返回一個物件,則使用步驟1建立的物件)
如果你沒有使用 new 運算子, 建構函式會像其他的常規函式一樣被呼叫, 並不會建立一個物件。在這種情況下, this 的指向也是不一樣的。
基於new的工作原理,手動實現一個new運算子:
var new1=function(func){
var o=Object.create(func.prototype);//建立物件
var k=func.call(o);//改變this指向,結果賦給k
if(typeof k ==='object')return k;//k是物件,返回k
else return o;//若k不為物件,則返回建構函式的執行結果
}
Object.create()
使用該方法建立一個新物件,使用現有的物件來提供新建立的物件的__proto __。