摘要:所以,在每個(gè)構(gòu)造函數(shù)都會(huì)有一個(gè)屬性,指向一個(gè)對象作為這個(gè)構(gòu)造函數(shù)構(gòu)造出來的新對象的原型。那么根據(jù)上面第二條事實(shí),每個(gè)函數(shù)也會(huì)有指向它的構(gòu)造函數(shù)的。而這個(gè)構(gòu)造函數(shù)的函數(shù)就是,中的所有函數(shù)都是由構(gòu)造出來的。
“__proto__”
JavaScript是一個(gè)面向?qū)ο笳Z音,即一切皆對象。
那么怎么生成對象?在Java的世界里,對象是由類(Class)實(shí)例出來的,通俗地說,就是將事物抽象成一個(gè)模具,用這個(gè)模具(類)生產(chǎn)出一個(gè)個(gè)具體的實(shí)物(對象)。
可是JS中沒有類這個(gè)概念,有的是“原型”,對象是由原型衍生出來的。通俗地說,在JS的世界里,“原型”并不是一個(gè)模具,而是一個(gè)具體的實(shí)物(對象)。所有對象都是由另一個(gè)對象衍生出來的,而這個(gè)被衍生的對象就是所謂的“原型對象”。
每一個(gè)對象自動(dòng)生成一個(gè)屬性:__proto__,這個(gè)屬性是一個(gè)引用對象,其指向這個(gè)對象的“原型對象”。
Talk is cheap, show me the code! 咱們來看看代碼:
var obj = {}; console.log(obj);
咱們將__proto__展開看看:是一些默認(rèn)方法。
你一定會(huì)發(fā)生這個(gè)__proto__對象中也有一個(gè)__proto__對象,正如我們剛才說的,每個(gè)對象都有一個(gè)__proto__屬性指向它的原型對象。我們打印一下這個(gè)__proto__中的__proto__:
console.log(obj.__proto__.__proto__); //--> null
結(jié)果是null,說明已經(jīng)到了頂層原型對象。obj是用大括號(hào){}定義的,obj的原型對象自然是JS的頂層對象。
咱們再看一端代碼,加強(qiáng)下理解:
var parent = { name : "parent" }; var child = { name : "child", __proto__ : parent }; var subChild = { name : "subChild", __proto__ : child } console.log(subChild);
subChild.__proto__ --> child
child.__proto__ --> parent
parent.__proto__ --> 頂層原型對象
上面我們說到,每一個(gè)對象都包含一個(gè)__proto__,指向這個(gè)的對象的“原型”。
類似的事情是,每一個(gè)函數(shù)都包含一個(gè)prototype,這個(gè)prototype對象干什么的了?
咱們看看如下代碼,用構(gòu)造函數(shù)來創(chuàng)建一個(gè)對象(上面是用字面量的形式創(chuàng)建對象)。
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__);
試想想,這個(gè)foo對象的__proto__會(huì)指向什么?
一個(gè)包含constructor屬性的對象?看不太懂沒關(guān)系,把函數(shù)Foo的prototype屬性打印出來,對比一下就知道了。
function Foo(){}; var foo = new Foo(); console.log(foo.__proto__); console.log(Foo.prototype); console.log(foo.__proto__ === Foo.prototype);
原來,new出來的對象foo的__proto__就只指向函數(shù)Foo的prototype。
foo.__proto__ --> Foo.prototype
JS這么設(shè)計(jì)有何意義了?回憶下上面說的,在JS的世界中,對象不是根據(jù)類(模具)創(chuàng)建出來的,而是從原型(另一個(gè)對象)衍生出來的。
當(dāng)我們執(zhí)行new操作創(chuàng)建一個(gè)新的對象時(shí),先不深入new操作的具體實(shí)現(xiàn),但有一點(diǎn)我們是肯定的——就是為新對象的__proto__指向一個(gè)原型對象。
就剛才這段代碼
function Foo(){}; var foo = new Foo();
foo.__proto__到底要指向誰了?你怎么不能指向Foo這個(gè)函數(shù)本身吧,雖然函數(shù)也是對象,這個(gè)有機(jī)會(huì)會(huì)詳細(xì)講。但如何foo.__proto__指向Foo固然不合適,因?yàn)镕oo是一個(gè)函數(shù),有很多邏輯代碼,foo作為一個(gè)對象,繼承邏輯處理沒有任何意義,它要繼承的是“原型對象”的屬性。
所以,每個(gè)函數(shù)會(huì)自動(dòng)生成一個(gè)prototype對象,由這個(gè)函數(shù)new出來的對象的__proto__就指向這個(gè)函數(shù)的prototype。
foo.__proto__ --> Foo.prototype
說了這么多,感覺還是沒完全說清楚,不如上一張圖。我曾經(jīng)參考過其他網(wǎng)友的圖,但總覺得哪里沒說清楚,所以我自己畫了一張圖,如果覺得我的不錯(cuò),請點(diǎn)個(gè)贊!(老子可是費(fèi)了牛勁才畫出來)。
(點(diǎn)擊可放大)
咱們就著這張圖,記住如下幾個(gè)事實(shí):
1. 每個(gè)對象中都有一個(gè)_proto_屬性。
JS世界中沒有類(模具)的概念,對象是從另一個(gè)對象(原型)衍生出來的,所以每個(gè)對象中會(huì)有一個(gè)_proto_屬性指向它的原型對象。(參考左上角的那個(gè)用字面量形式定義的對象obj,它在內(nèi)存中開辟了一個(gè)空間存放對象自身的屬性,同時(shí)生成一個(gè)_proto_指向它的原型——頂層原型對象。)
2. 每個(gè)函數(shù)都有一個(gè)prototype屬性。
“構(gòu)造函數(shù)”為何叫構(gòu)造函數(shù),因?yàn)樗獦?gòu)造對象。那么根據(jù)上面第一條事實(shí),構(gòu)造出來的新對象的_proto_屬性指向誰了?總不能指向構(gòu)造函數(shù)自身,雖然它也是個(gè)對象,但你不希望新對象繼承函數(shù)的屬性與方法吧。所以,在每個(gè)構(gòu)造函數(shù)都會(huì)有一個(gè)prototype屬性,指向一個(gè)對象作為這個(gè)構(gòu)造函數(shù)構(gòu)造出來的新對象的原型。
3. 函數(shù)也是對象。
每個(gè)函數(shù)都有一些通用的屬性和方法,比如apply()/call()等。但這些通用的方法是如何繼承的呢?函數(shù)又是怎么創(chuàng)建出來的呢?試想想,一切皆對象,包括函數(shù)也是對象,而且是通過構(gòu)造函數(shù)構(gòu)造出來的對象。那么根據(jù)上面第二條事實(shí),每個(gè)函數(shù)也會(huì)有_proto_指向它的構(gòu)造函數(shù)的prototype。而這個(gè)構(gòu)造函數(shù)的函數(shù)就是Function,JS中的所有函數(shù)都是由Function構(gòu)造出來的。函數(shù)的通用屬性與方法就存放在Function.prototype這個(gè)原型對象上。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/78272.html
摘要:實(shí)例可以通過代理來找到它,并用來檢測其構(gòu)造函數(shù)。經(jīng)典繼承圖這也是通過構(gòu)造函數(shù)來創(chuàng)建對象,但是在這一系列的對象和實(shí)例之間我們的焦點(diǎn)是放在原型鏈上。盡管,但構(gòu)造函數(shù)的屬性并不是對象自己的屬性,它實(shí)際上是通過尋找原型鏈獲得的,即所指向的地方。 繼承是面向?qū)ο缶幊陶Z言的一大核心功能點(diǎn),雖然JavaScript并不是一門真正意義上的面向?qū)ο蟮木幊陶Z言,但也通過某種手段實(shí)現(xiàn)了繼承這一功能,最常見的...
摘要:了解中原型以及原型鏈只需要記住以下點(diǎn)即可對象都有屬性,指向構(gòu)造函數(shù)的構(gòu)造函數(shù)函數(shù)都有屬性,指向構(gòu)造函數(shù)的原型對象的內(nèi)置構(gòu)造函數(shù)可知所有的構(gòu)造函數(shù)都繼承于甚至包括根構(gòu)造器及自身。 了解JavaScript中原型以及原型鏈只需要記住以下2點(diǎn)即可 對象都有__proto__屬性,指向構(gòu)造函數(shù)的prototype 構(gòu)造函數(shù)函數(shù)都有prototype屬性,指向構(gòu)造函數(shù)的原型 1、對象的__p...
摘要:而作為構(gòu)造函數(shù),需要有個(gè)屬性用來作為以該構(gòu)造函數(shù)創(chuàng)造的實(shí)例的繼承。 歡迎來我的博客閱讀:「JavaScript 原型中的哲學(xué)思想」 記得當(dāng)年初試前端的時(shí)候,學(xué)習(xí)JavaScript過程中,原型問題一直讓我疑惑許久,那時(shí)候捧著那本著名的紅皮書,看到有關(guān)原型的講解時(shí),總是心存疑慮。 當(dāng)在JavaScript世界中走過不少旅程之后,再次萌發(fā)起研究這部分知識(shí)的欲望,翻閱了不少書籍和資料,才搞懂...
摘要:深入理解原型與繼承看過不少書籍,不少文章,對于原型與繼承的說明基本上讓人不明覺厲,特別是對于習(xí)慣了面向?qū)ο缶幊痰娜藖碚f更難理解,這里我就給大家說說我的理解。 深入理解:JavaScript原型與繼承 看過不少書籍,不少文章,對于原型與繼承的說明基本上讓人不明覺厲,特別是對于習(xí)慣了面向?qū)ο缶幊痰娜藖碚f更難理解,這里我就給大家說說我的理解。 首先JavaScript是一門基于原型編程的語言...
摘要:原文鏈接關(guān)于的原型和原型鏈,看我就夠了一參考鏈接闖關(guān)記之原型及原型鏈之原型與原型鏈一篇文章帶你理解原型和原型鏈徹底理解原型鏈一的默認(rèn)指向圖解和的三角關(guān)系原型和原型鏈三張圖搞懂的原型對象與原型鏈 溫故 創(chuàng)建對象的三種方式 通過對象直接量 通過new創(chuàng)建對象 通過Object.create() js中對象分為兩種 函數(shù)對象 普通對象 仔細(xì)觀察如下代碼 function Foo(na...
摘要:在創(chuàng)建對象不論是普通對象還是函數(shù)對象的時(shí)候,都有一個(gè)叫做的內(nèi)置屬性,用于指向創(chuàng)建它的構(gòu)造函數(shù)的原型對象,也就是。因?yàn)橐粋€(gè)普通對象的構(gòu)造函數(shù)所以原型鏈原型鏈的形成是真正是靠而非。參考文章最詳盡的原型與原型鏈終極詳解,沒有可能是。 【前端芝士樹】Javascript的原型、原型鏈以及繼承機(jī)制 前端的面試中經(jīng)常會(huì)遇到這個(gè)問題,自己也是一直似懂非懂,趁這個(gè)機(jī)會(huì)整理一下 0. 為什么會(huì)出現(xiàn)原型和...
閱讀 1803·2021-11-18 10:02
閱讀 3531·2021-11-16 11:45
閱讀 1796·2021-09-10 10:51
閱讀 2113·2019-08-30 15:43
閱讀 1383·2019-08-30 11:23
閱讀 1491·2019-08-29 11:07
閱讀 1897·2019-08-23 17:05
閱讀 1424·2019-08-23 16:14