淺談JavaScript原型鏈
instanceof 簡(jiǎn)介
在 JavaScript 中,判斷一個(gè)變量的類型通常會(huì)用 typeof 運(yùn)算符,在使用 typeof 運(yùn)算符時(shí)采用引用類型存儲(chǔ)值會(huì)出現(xiàn)一個(gè)問(wèn)題,無(wú)論引用的是什么類型的對(duì)象,它都返回 "object"。例如:
var arr = new Array(); console.log( typeof arr ); // object
如果想要確定原型和實(shí)例之間的關(guān)系就需要用到 instanceof 操作符, 例如:
var arr = new Array();
var Fn = function() {};
var foo = new Fn();
console.log( arr instanceof Array ); // true
console.log( arr instanceof Object ); // true
console.log( foo instanceof Fn); // true
console.log( foo instanceof Function ); // false
console.log( foo instanceof Object ); // trueFunction instanceof Function ?
console.log( String instanceof String ); console.log( Function instanceof Function ); console.log( Function instanceof Object ); console.log( Object instanceof Function ); console.log( Object instanceof Object );
要解釋這個(gè)問(wèn)題就需要了解 1.JavaScript 語(yǔ)言規(guī)范中是如何定義 instanceof 運(yùn)算符的,2.JavaScript 原型繼承機(jī)制。
instanceof 運(yùn)算符的定義
在 ECMAScript-262 中 instanceof 運(yùn)算符的定義是這樣的。
12.9.4 Runtime Semantics: InstanceofOperator(O, C)
The abstract operation InstanceofOperator(O, C) implements the generic algorithm for determining if an object O inherits from the inheritance path defined by constructor C. This abstract operation performs the following steps:
1. If Type(C) is not Object, throw a TypeError exception. 2. Let instOfHandler be GetMethod(C,@@hasInstance). 3. ReturnIfAbrupt(instOfHandler). 4. If instOfHandler is not undefined, then a. Return ToBoolean(Call(instOfHandler, C, ?O?)). 5. If IsCallable(C) is false, throw a TypeError exception. 6. Return OrdinaryHasInstance(C, O). NOTE Steps 5 and 6 provide compatibility with previous editions of ECMAScript that did not use a @@hasInstance method to define the instanceof operator semantics. If a function object does not define or inherit @@hasInstance it uses the default instanceof semantics.
7.3.19 OrdinaryHasInstance (C, O)
The abstract operation OrdinaryHasInstance implements the default algorithm for determining if an object O inherits from the instance object inheritance path provided by constructor C. This abstract operation performs the following steps:
1. If IsCallable(C) is false, return false.
2. If C has a [[BoundTargetFunction]] internal slot, then
a. Let BC be the value of C's [[BoundTargetFunction]] internal slot.
b. Return InstanceofOperator(O,BC) (see 12.9.4).
3. If Type(O) is not Object, return false.
4. Let P be Get(C, "prototype").
5. ReturnIfAbrupt(P).
6. If Type(P) is not Object, throw a TypeError exception.
7. Repeat
a. Let O be `O.[[GetPrototypeOf]]()`.
b. ReturnIfAbrupt(O).
c. If O is null, return false.
d. If SameValue(P, O) is true, return true.官網(wǎng)的定義非?;逎厦娴姆g成代碼大概就是:
function instanceOf( L, R ) { //L 表示左表達(dá)式,R 表示右表達(dá)式
var P = R.prototype; // 取 R 的顯示原型
L = L.__proto__; // 取 L 的隱式原型
while ( true ) {
if ( L === null ) return false;
if ( P === L ) return true;
L = L.__proto__;
}
}再直接點(diǎn)的表達(dá)就是 instanceof 會(huì)一直在 obj 的原型鏈上查找,直到找到右邊那個(gè)構(gòu)造函數(shù)的 prototype 屬性,或者為 null 的時(shí)候才停止。
類似:
obj.__proto__.__proto__ ... = Obj.prototype
instanceof 會(huì)一直沿著隱式原型鏈 __proto__ 向上查找直到 obj.__proto__.__proto__ ...... === Obj.prototype 為止,如果找到則返回 true,也就是 obj 為 Obj 的一個(gè)實(shí)例。否則返回 false,obj 不是 Obj 的實(shí)例。
JavaScript 原型繼承機(jī)制
原型與原型鏈
在 JavaScript 每個(gè)函數(shù)都有一個(gè) prototype 屬性,該屬性存儲(chǔ)的就是原型對(duì)象。JavaScript 構(gòu)造函數(shù)的繼承都是通過(guò) prototype 屬性, 真正的原型鏈的實(shí)現(xiàn)是通過(guò) __proto__ 實(shí)現(xiàn)的,__proto__其實(shí)是指向‘父類’的 prototype 屬性。例如:
var Foo = function() {}
var foo = new Foo;
console.log(foo.__proto__ === Foo.prototype) // true
console.log(Foo.__proto__ === Function.prototype) // true原型繼承
JavaScript 是單繼承的,Object.prototype 是原型鏈的頂端,所有對(duì)象從它繼承了包括 valueOf、toString 等等方法和屬性。
Object 本身是構(gòu)造函數(shù),繼承了 Function.prototype。 Function 也是對(duì)象,繼承了 Object.prototype。

Object instanceof Object
ObjectL = Object, ObjectR = Object; R = ObjectR.prototype = Object.prototype L = ObjectL.__proto__ = Function.prototype R != L // 循環(huán)查找 L 是否還有 __proto__ L = Function.prototype.__proto__ = Object.prototype R == L // 返回 true
String instanceof String
StringL = String, StringR = String; R = StringR.prototype = String.prototype L = StringL.__proto__ = Object.prototype R != L // 循環(huán)查找 L 是否還有 __proto__ L = Object.prototype.__proto__ = null // 返回 false
一切皆對(duì)象?
常常說(shuō) JavaScript 中一切皆對(duì)象,那么就有這樣一個(gè)問(wèn)題了:
'string'.__proto__ === String.prototype // true 'string' instanceof String // false
按照上面的推導(dǎo),'string' instanceof String 應(yīng)該為 true,但是我們得到的卻是 false。 其實(shí)問(wèn)題的關(guān)鍵在于:
console.log(typeof 'string'); // string
'string' 并不是一個(gè) object 對(duì)象,MDN 上對(duì) instanceof 的定義是:
The instanceof operator tests whether an object in its prototype chain has the prototype property of a constructor.
這樣又有一個(gè)問(wèn)題了,既然字符串不是對(duì)象那為什么有對(duì)象才有的屬性和方法呢?
var s1 = "string"; var s2 = s1.substring(2);
為了便于操作基本類型值,ECMAScript 還提供了 3 個(gè)特殊的引用類型: Boolean、Number 和 String。 實(shí)際上,每當(dāng)讀取一個(gè)基本類型值的時(shí)候,后臺(tái)就會(huì)創(chuàng)建一個(gè)對(duì)應(yīng)的基本包裝類型的對(duì)象,從而讓我們 能夠調(diào)用一些方法來(lái)操作這些數(shù)據(jù)。
《JavaScript高級(jí)程序設(shè)計(jì)》中是這么解釋的:
上面的例子其實(shí)當(dāng)?shù)诙写a訪問(wèn) s1 時(shí),訪問(wèn)過(guò)程處于一種讀取模式,也就是要 從內(nèi)存中讀取這個(gè)字符串的值。而在讀取模式中訪問(wèn)字符串時(shí),后臺(tái)都會(huì)自動(dòng)完成: (1) 創(chuàng)建 String 類型的一個(gè)實(shí)例; (2) 在實(shí)例上調(diào)用指定的方法; (3) 銷毀這個(gè)實(shí)例。
可以將以上三個(gè)步驟想象成是執(zhí)行了下列 ECMAScript 代碼。
var s1 = new String("some text");
var s2 = s1.substring(2);
s1 = null;《Javascript權(quán)威指南》里說(shuō):
其實(shí)(包裝對(duì)象)在實(shí)現(xiàn)上并不一定創(chuàng)建或銷毀這個(gè)臨時(shí)對(duì)象,然而整個(gè)過(guò)程看起來(lái)是這樣的。
這樣 Boolean、Number 是一樣的邏輯。還剩下兩種基本類型:null 和 undefined。
undefined 當(dāng)我們對(duì)變量只聲明沒(méi)有初始化時(shí),輸出為 undefined,typeof undefined 返回的是 undefined 也不是 object 類型,所以 undefined 并不是任何對(duì)象的實(shí)例。
null 表示的是空對(duì)象,雖然 typeof null 是 object,但是 null 和 undefined 一樣并沒(méi)有任何屬性和方法,在 instanceof 定義中也有判斷,如果類型不是 object(這個(gè)類型判斷并不是跟 typeof 返回值一樣),就返回 false。

寫(xiě)在最后
如果這篇文章對(duì)你有幫助,請(qǐng)不要吝嗇你手中的贊??!你的鼓勵(lì)將是我不斷分享的動(dòng)力!??
到此這篇關(guān)于淺談JavaScript原型鏈的文章就介紹到這了,更多相關(guān)JavaScript原型鏈內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于JavaScript實(shí)現(xiàn)十五拼圖代碼實(shí)例
這篇文章主要介紹了基于JavaScript實(shí)現(xiàn)十五拼圖代碼實(shí)例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-04-04
js發(fā)送短信倒計(jì)時(shí)的簡(jiǎn)單實(shí)現(xiàn)方法
下面小編就為大家?guī)?lái)一篇js發(fā)送短信倒計(jì)時(shí)的簡(jiǎn)單實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2016-09-09
js實(shí)現(xiàn)點(diǎn)擊切換checkbox背景圖片的簡(jiǎn)單實(shí)例
下面小編就為大家?guī)?lái)一篇js實(shí)現(xiàn)點(diǎn)擊切換checkbox背景圖片的簡(jiǎn)單實(shí)例。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-05-05
關(guān)于JS判斷圖片是否加載完成且獲取圖片寬度的方法
本篇文章小編為大家介紹,關(guān)于JS判斷圖片是否加載完成且獲取圖片寬度的方法,有需要的朋友可以參考一下2013-04-04
一個(gè)JS函數(shù)搞定網(wǎng)頁(yè)標(biāo)題(title)閃動(dòng)效果
這篇文章主要介紹了使用JS函數(shù)實(shí)現(xiàn)網(wǎng)頁(yè)標(biāo)題(title)閃動(dòng)效果的代碼,需要的朋友可以參考下2014-05-05

