成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

JS 中的 __proto__ 與 prototype

Donald / 3134人閱讀

摘要:在這篇文章中,他介紹了一種實(shí)現(xiàn)繼承的方法,這種方法并沒(méi)有使用嚴(yán)格意義上的構(gòu)造函數(shù)。的左值一般是一個(gè)對(duì)象,右值一般是一個(gè)構(gòu)造函數(shù),用來(lái)判斷左值是否是右值的實(shí)例。

__proto__ 探究

__proto__隱式原型與prototype顯式原型是個(gè)容易令人混淆的概念,簡(jiǎn)而言之prototype是構(gòu)造函數(shù)用來(lái)被自己的實(shí)例繼承的原型,而_proto_是實(shí)例用來(lái)繼承父類原型的載體。

1. 是什么 顯式原型 explicit prototype property

每一個(gè)函數(shù)在創(chuàng)建之后都會(huì)擁有一個(gè)名為prototype的屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象,定義了該構(gòu)造函數(shù)創(chuàng)建的所有實(shí)例對(duì)象共享的屬性。
Note:通過(guò)Function.prototype.bind方法構(gòu)造出來(lái)的函數(shù)是個(gè)例外,它沒(méi)有prototype屬性

NOTE Function objects created using Function.prototype.bind do not have a prototype property or the [[Code]], [[FormalParameters]], and [[Scope]] internal properties. ----- ECMAScript Language Specification
隱式原型 implicit prototype link

JavaScript中任意對(duì)象都有一個(gè)內(nèi)置屬性[[prototype]],在ES5之前沒(méi)有標(biāo)準(zhǔn)的方法訪問(wèn)這個(gè)內(nèi)置屬性,但是大多數(shù)瀏覽器都支持通過(guò)__proto__來(lái)訪問(wèn)。ES5中有了對(duì)于這個(gè)內(nèi)置屬性標(biāo)準(zhǔn)的Get方法,Object.getPrototypeOf() 。
__proto__是瀏覽器自實(shí)現(xiàn)的[[prototype]]

二者的關(guān)系

隱式原型指向創(chuàng)建這個(gè)對(duì)象的函數(shù)(構(gòu)造函數(shù)constructor)的顯式原型prototype

function Person(name) {this.name = name}
var person1 = new Person
console.log(person1.__proto__ === Person.prototype)                    // true
console.log(Object.getPrototypeOf(person1) === person1.__proto__)        // true
console.log(person1.prototype === person1.__proto__)                    // false
console.log(Object.getPrototypeOf(Person) === Person.__proto__)    // true
console.log(Person.prototype===Person.__proto__)                        // false
console.log(person1.constructor === Person)                                // true
2. 作用是什么

顯示原型的作用:用來(lái)實(shí)現(xiàn)基于原型的繼承與屬性的共享。

ECMAScript does not use classes such as those in C++, Smalltalk, or Java. Instead objects may be created in various ways including via a literal notation or via constructors which create objects and then execute code that initialises all or part of them by assigning initial values to their properties. Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties.Objects are created by using constructors in new expressions; for example, new Date(2009,11) creates a new Date object. ---- ECMAScript Language Specification

隱式原型的作用:構(gòu)成原型鏈,同樣用于實(shí)現(xiàn)基于原型的繼承。舉個(gè)例子,當(dāng)我們?cè)L問(wèn)obj這個(gè)對(duì)象中的x屬性時(shí),如果在obj中找不到,那么就會(huì)沿著__proto__依次查找。

Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” ---- ECMAScript Language Specification
3. __proto__的指向

__proto__的指向到底如何判斷呢?根據(jù)ECMA定義 "to the value of its constructor"s "prototype" " ----指向創(chuàng)建這個(gè)對(duì)象的函數(shù)(構(gòu)造函數(shù))的顯式原型。所以關(guān)鍵的點(diǎn)在于找到創(chuàng)建這個(gè)對(duì)象的構(gòu)造函數(shù),接下來(lái)就來(lái)看一下JS中對(duì)象被創(chuàng)建的方式,一眼看過(guò)去似乎有三種方式:對(duì)象字面量的方式 、new 的方式 、ES5中的Object.create() 但是我認(rèn)為本質(zhì)上只有一種方式,也就是通過(guò)new來(lái)創(chuàng)建。為什么這么說(shuō)呢,首先字面量的方式是一種為了開(kāi)發(fā)人員更方便創(chuàng)建對(duì)象的一個(gè)語(yǔ)法糖,本質(zhì)就是 var o = new Object(); o.xx = xx;o.yy=yy; 再來(lái)看看Object.create(),這是ES5中新增的方法,在這之前這被稱為原型式繼承

道格拉斯在2006年寫(xiě)了一篇文章,題為 Prototypal Inheritance In JavaScript。在這篇文章中,他介紹了一種實(shí)現(xiàn)繼承的方法,這種方法并沒(méi)有使用嚴(yán)格意義上的構(gòu)造函數(shù)。他的想法是借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象,同時(shí)還不比因此創(chuàng)建自定義類型,為了達(dá)到這個(gè)目的,他給出了如下函數(shù):
 function object(o){
    function F(){}
    F.prototype = o;
    return new F()
}

----- 《JavaScript高級(jí)程序設(shè)計(jì)》P169

所以從實(shí)現(xiàn)代碼 return new F() 中我們可以看到,這依然是通過(guò)new來(lái)創(chuàng)建的。不同之處在于由 Object.create() 創(chuàng)建出來(lái)的對(duì)象沒(méi)有構(gòu)造函數(shù),看到這里你是不是要問(wèn),沒(méi)有構(gòu)造函數(shù)我怎么知道它的__proto__指向哪里呢,其實(shí)這里說(shuō)它沒(méi)有構(gòu)造函數(shù)是指在 Object.create() 函數(shù)外部我們不能訪問(wèn)到它的構(gòu)造函數(shù),然而在函數(shù)內(nèi)部實(shí)現(xiàn)中是有的,它短暫地存在了那么一會(huì)兒。假設(shè)我們現(xiàn)在就在函數(shù)內(nèi)部,可以看到對(duì)象的構(gòu)造函數(shù)是F, 現(xiàn)在

// 以下是用于驗(yàn)證的偽代碼
var f = new F(); 
// 于是有
f.__proto__ === F.prototype         // true
// 又因?yàn)?F.prototype === o;            // true
// 所以
f.__proto__ === o;

因此由Object.create(o)創(chuàng)建出來(lái)的對(duì)象它的隱式原型指向o。好了,對(duì)象的創(chuàng)建方式分析完了,現(xiàn)在你應(yīng)該能夠判斷一個(gè)對(duì)象的__proto__指向誰(shuí)了。
好吧,還是舉一些一眼看過(guò)去比較疑惑的例子來(lái)鞏固一下。

構(gòu)造函數(shù)的顯示原型的隱式原型:

內(nèi)建對(duì)象(built-in object):比如Array(),Array.prototype.__proto__指向什么?Array.prototype也是一個(gè)對(duì)象,對(duì)象就是由 Object() 這個(gè)構(gòu)造函數(shù)創(chuàng)建的,因此Array.prototype.__proto__ === Object.prototype //true,或者也可以這么理解,所有的內(nèi)建對(duì)象都是由Object()創(chuàng)建而來(lái)。

自定義對(duì)象

默認(rèn)情況下:

function Foo(){}
var foo = new Foo()
Foo.prototype.__proto__ === Object.prototype         // true 理由同上

其他情況:

function Bar(){}
//這時(shí)我們想讓Foo繼承Bar
Foo.prototype = new Bar()
Foo.prototype.__proto__ === Bar.prototype //true
//我們不想讓Foo繼承誰(shuí),但是我們要自己重新定義Foo.prototype
Foo.prototype = {
  a:10,
  b:-10
}
//這種方式就是用了對(duì)象字面量的方式來(lái)創(chuàng)建一個(gè)對(duì)象,根據(jù)前文所述 
Foo.prototype.__proto__ === Object.prototype

Note: 以上兩種情況都等于完全重寫(xiě)了Foo.prototype,所以Foo.prototype.constructor也跟著改變了,于是乎constructor這個(gè)屬性和原來(lái)的構(gòu)造函數(shù)Foo()也就切斷了聯(lián)系。

構(gòu)造函數(shù)的隱式原型

既然是構(gòu)造函數(shù)那么它就是Function()的實(shí)例,因此也就指向Function.prototype,比如 Object.__proto__ === Function.prototype

4. instanceof

instanceof 操作符的內(nèi)部實(shí)現(xiàn)機(jī)制和隱式原型、顯式原型有直接的關(guān)系。instanceof的左值一般是一個(gè)對(duì)象,右值一般是一個(gè)構(gòu)造函數(shù),用來(lái)判斷左值是否是右值的實(shí)例。它的內(nèi)部實(shí)現(xiàn)原理是這樣的:

// 設(shè) L instanceof R 
// 通過(guò)判斷
L.__proto__.__proto__ ..... === R.prototype ?
// 最終返回true or false

也就是沿著L的__proto__一直尋找到原型鏈末端,直到等于R.prototype為止。知道了這個(gè)也就知道為什么以下這些奇怪的表達(dá)式為什么會(huì)得到相應(yīng)的值了,所有構(gòu)造函數(shù)都是Fucntion的實(shí)例,所有對(duì)象都是Object的實(shí)例

Function instanceof Object // true 
Object instanceof Function // true 
Function instanceof Function //true
Object instanceof Object // true
Number instanceof Number //false
5. Js對(duì)象體系結(jié)構(gòu)

每一個(gè)對(duì)象都有__proto__,誰(shuí)創(chuàng)建的對(duì)象(繼承誰(shuí)),__proto__就指向誰(shuí)的prototype

所有的函數(shù)都是由Function()創(chuàng)建的,所以所有的函數(shù)的__proto__就指向Function的prototype,包括它自己

函數(shù)有prototype,普通實(shí)例對(duì)象沒(méi)有,且函數(shù)的prototype都有一個(gè)自有屬性constructor指向自己

所有的prototype也是對(duì)象,是由Object()創(chuàng)建(繼承Object)而來(lái)的,所以所有的prototype__proto__都指向Object

6. 謹(jǐn)慎操作__proto__

警告: 由于現(xiàn)代 JavaScript 引擎優(yōu)化屬性訪問(wèn)所帶來(lái)的特性的關(guān)系,更改對(duì)象的 [[Prototype]]在各個(gè)瀏覽器和 JavaScript 引擎上都是一個(gè)很慢的操作。其在更改繼承的性能上的影響是微妙而又廣泛的,這不僅僅限于 obj.__proto__ = ... 語(yǔ)句上的時(shí)間花費(fèi),而且可能會(huì)延伸到任何代碼,那些可以訪問(wèn)任何[[Prototype]]已被更改的對(duì)象的代碼。如果你關(guān)心性能,你應(yīng)該避免設(shè)置一個(gè)對(duì)象的 [[Prototype]]。相反,你應(yīng)該使用 Object.create()來(lái)創(chuàng)建帶有你想要的[[Prototype]]的新對(duì)象。

網(wǎng)上的帖子大多深淺不一,甚至有些前后矛盾,在下的文章都是學(xué)習(xí)過(guò)程中的總結(jié),如果發(fā)現(xiàn)錯(cuò)誤,歡迎留言指出~

參考:
1、js中__proto__和prototype的區(qū)別和關(guān)系?
2、G小調(diào)的悲傷的博客
3、JavaScript instanceof 運(yùn)算符深入剖析

PS:歡迎大家關(guān)注我的公眾號(hào)【前端下午茶】,一起加油吧~

另外可以加入「前端下午茶交流群」微信群,長(zhǎng)按識(shí)別下面二維碼即可加我好友,備注加群,我拉你入群~

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/92021.html

相關(guān)文章

  • js 原型鏈、__proto__、prototype

    摘要:另外常說(shuō)的的構(gòu)造函數(shù),就是指這個(gè)。按照理解,可能會(huì)這樣的疑問(wèn)指向構(gòu)造函數(shù)再次提醒,是一個(gè)對(duì)象的,所以這個(gè)對(duì)象的構(gòu)造函數(shù)是它自己自己創(chuàng)建自己么額。。。 本文由用途意義,進(jìn)行腦測(cè)解析,從需求角度走一遍原型鏈的發(fā)展。 用對(duì)象模擬類的繼承 js中沒(méi)有類(沒(méi)有類,沒(méi)有類,重要的事情說(shuō)3遍)只有對(duì)象,怎么才能做到繼承的效果? var a={x:1} var b={}; b.__proto__=a...

    shengguo 評(píng)論0 收藏0
  • js內(nèi)功修煉之九陽(yáng)神功--原型鏈

    摘要:寫(xiě)在前面如果說(shuō)是一本武學(xué)典籍,那么原型鏈就是九陽(yáng)神功。那么,如何修煉好中的九陽(yáng)神功呢真正的功法大成的技術(shù)是從底層上去理解,那種工程師和碼農(nóng)的區(qū)別就在于對(duì)底層的理解,當(dāng)你寫(xiě)完一行代碼,或者你遇見(jiàn)一個(gè)解決的速度取決于你對(duì)底層的理解。 寫(xiě)在前面 如果說(shuō)JavaScript是一本武學(xué)典籍,那么原型鏈就是九陽(yáng)神功。在金庸的武俠小說(shuō)里面,對(duì)九陽(yáng)神功是這樣描述的:練成「九陽(yáng)神功」后,會(huì)易筋洗髓;生出...

    蘇丹 評(píng)論0 收藏0
  • js內(nèi)功修煉之九陽(yáng)神功--原型鏈

    摘要:寫(xiě)在前面如果說(shuō)是一本武學(xué)典籍,那么原型鏈就是九陽(yáng)神功。那么,如何修煉好中的九陽(yáng)神功呢真正的功法大成的技術(shù)是從底層上去理解,那種工程師和碼農(nóng)的區(qū)別就在于對(duì)底層的理解,當(dāng)你寫(xiě)完一行代碼,或者你遇見(jiàn)一個(gè)解決的速度取決于你對(duì)底層的理解。 寫(xiě)在前面 如果說(shuō)JavaScript是一本武學(xué)典籍,那么原型鏈就是九陽(yáng)神功。在金庸的武俠小說(shuō)里面,對(duì)九陽(yáng)神功是這樣描述的:練成「九陽(yáng)神功」后,會(huì)易筋洗髓;生出...

    Profeel 評(píng)論0 收藏0
  • js內(nèi)功修煉之九陽(yáng)神功--原型鏈

    摘要:寫(xiě)在前面如果說(shuō)是一本武學(xué)典籍,那么原型鏈就是九陽(yáng)神功。那么,如何修煉好中的九陽(yáng)神功呢真正的功法大成的技術(shù)是從底層上去理解,那種工程師和碼農(nóng)的區(qū)別就在于對(duì)底層的理解,當(dāng)你寫(xiě)完一行代碼,或者你遇見(jiàn)一個(gè)解決的速度取決于你對(duì)底層的理解。 寫(xiě)在前面 如果說(shuō)JavaScript是一本武學(xué)典籍,那么原型鏈就是九陽(yáng)神功。在金庸的武俠小說(shuō)里面,對(duì)九陽(yáng)神功是這樣描述的:練成「九陽(yáng)神功」后,會(huì)易筋洗髓;生出...

    morgan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<