摘要:如果要理清原型和原型鏈的關(guān)系,首先要明確一下幾個概念中的所有東西都是對象,函數(shù)也是對象而且是一種特殊的對象中所有的東西都由衍生而來即所有東西原型鏈的終點指向?qū)ο蠖加幸粋€隱藏的屬性,他指向創(chuàng)建它的構(gòu)造函數(shù)的原型,但是有一個例外,指向的是。
首先要搞明白幾個概念:
函數(shù)函數(shù)(function)
函數(shù)對象(function object)
本地對象(native object)
內(nèi)置對象(build-in object)
宿主對象(host object)
function foo(){ } var foo = function(){ }
前者為函數(shù)聲明,后者為函數(shù)表達式。typeof foo
的結(jié)果都是function。
函數(shù)就是對象,代表函數(shù)的對象就是函數(shù)對象
官方定義, 在Javascript中,每一個函數(shù)實際上都是一個函數(shù)對象.JavaScript代碼中定義函數(shù),或者調(diào)用Function創(chuàng)建函數(shù)時,最終都會以類似這樣的形式調(diào)用Function函數(shù):var newFun = new Function(funArgs, funBody)
其實也就是說,我們定義的函數(shù),語法上,都稱為函數(shù)對象,看我們?nèi)绾稳ナ褂谩H绻覀儐渭兊陌阉?dāng)成一個函數(shù)使用,那么它就是函數(shù),如果我們通過他來實例化出對象來使用,那么它就可以當(dāng)成一個函數(shù)對象來使用,在面向?qū)ο蟮姆懂犂锩妫瘮?shù)對象類似于類的概念。
var foo = new function(){ } typeof foo // object 或者 function Foo (){ } var foo = new Foo(); typeof foo // object
上面,我們所建立的對象
本地對象ECMA-262 把本地對象(native object)定義為“獨立于宿主環(huán)境的 ECMAScript 實現(xiàn)提供的對象”。簡單來說,本地對象就是 ECMA-262 定義的類(引用類型)。它們包括:
Object,Function,Array,String,Boolean,Number
Date,RegExp,Error,EvalError,RangeError,ReferenceError,SyntaxError,TypeError,URIError.
我們不能被他們起的名字是本地對象,就把他們理解成對象(雖然是事實上,它就是一個對象,因為JS中萬物皆為對象),通過
typeof(Object) typeof(Array) typeof(Date) typeof(RegExp) typeof(Math)
返回的結(jié)果都是function
也就是說其實這些本地對象(類)是通過function建立起來的,
function Object(){ } function Array(){ } ...
可以看出Object原本就是一個函數(shù),通過new Object()之后實例化后,創(chuàng)建對象。類似于JAVA中的類。
內(nèi)置對象ECMA-262 把內(nèi)置對象(built-in object)定義為“由 ECMAScript 實現(xiàn)提供的、獨立于宿主環(huán)境的所有對象,在 ECMAScript 程序開始執(zhí)行時出現(xiàn)”。這意味著開發(fā)者不必明確實例化內(nèi)置對象,它已被實例化了。ECMA-262 只定義了兩個內(nèi)置對象,即 Global 和 Math (它們也是本地對象,根據(jù)定義,每個內(nèi)置對象都是本地對象)。
理清楚了這幾個概念,有助于理解我們下面要講述的原型和原型鏈。
prototypeprototype屬性是每一個函數(shù)都具有的屬性,但是不是一個對象都具有的屬性。比如
function Foo(){ } var foo = new Foo();
其中Foo中有prototype屬性,而foo沒有。但是foo中的隱含的__proto__屬性指向Foo.prototype。
foo.__proto__ === Foo.prototype
為什么會存在prototype屬性?
Javascript里面所有的數(shù)據(jù)類型都是對象,為了使JavaScript實現(xiàn)面向?qū)ο蟮乃枷耄捅仨氁軌驅(qū)崿F(xiàn)‘繼承’使所有的對象連接起來。而如何實現(xiàn)繼承呢?JavaScript采用了類似C++,java的方式,通過new的方式來實現(xiàn)實例。
舉個例子,child1,child2都是Mother的孩子,且是雙胞胎。(雖然不是很好,但是還是很能說明問題的)
function Mother(name){ this.name = name; this.father = "baba"; } var child1 = new Mother("huahua"); var child2 = new Mother("huahua");
如果有一天,發(fā)現(xiàn)孩子的父親其實是Baba,那么就要修改每一個孩子的father屬性。
child1.father ="Baba"; console.log(child2.father) // baba
也就是說修改了其中一個孩子的father屬性不會影響到下一個,屬性的值無法共享。
正是這個原因才提出來prototype屬性,把需要共享的屬性放到構(gòu)造函數(shù)也就是父類的實例中去。
__proto____proto__屬性是每一個對象以及函數(shù)都隱含的一個屬性。對于每一個含有__proto__屬性,他所指向的是創(chuàng)建他的構(gòu)造函數(shù)的prototype。原型鏈就是通過這個屬性構(gòu)件的。
想像一下,如果一個函數(shù)對象(也稱為構(gòu)造函數(shù))a的prototype是另一個函數(shù)對象b構(gòu)建出的實例,a的實例就可以通過__proto__與b的原型鏈起來。而b的原型其實就是Object的實例,所以a的實例對象,就可以通過原型鏈和object的prototype鏈接起來。
function a(){ } function b(){ } var b1 = new b(); a.prototype = b1; var a1 = new a(); console.log(a1.__proto__===b1);//true console.log(a1.__proto__.__proto__===b.prototype) //true console.log(a1.__proto__.__proto__.__proto__===Object.prototype) //true
如果要理清原型和原型鏈的關(guān)系,首先要明確一下幾個概念:
1.JS中的所有東西都是對象,函數(shù)也是對象, 而且是一種特殊的對象
2.JS中所有的東西都由Object衍生而來, 即所有東西原型鏈的終點指向Object.prototype
3.JS對象都有一個隱藏的__proto__屬性,他指向創(chuàng)建它的構(gòu)造函數(shù)的原型,但是有一個例外,Object.prototype.__proto__指向的是null。
4.JS中構(gòu)造函數(shù)和實例(對象)之間的微妙關(guān)系
構(gòu)造函數(shù)通過定義prototype來約定其實例的規(guī)格, 再通過 new 來構(gòu)造出實例,他們的作用就是生產(chǎn)對象.
function Foo(){ } var foo = new Foo(); foo其實是通過Foo.prototype來生成實例的。
構(gòu)造函數(shù)本身又是方法(Function)的實例, 因此也可以查到它的__proto__(原型鏈)
function Foo(){ } 等價于 var Foo= new Function();
而Function實際上是
function Function(){ Native Code } 也就是等價于 var Function= new Function();
所以說Function是通過自己創(chuàng)建出來的。正常情況下對象的__proto__是指向創(chuàng)建它的構(gòu)造函數(shù)的prototype的.所以Function的__proto__指向的Function.prototype
Object 實際上也是通過Function創(chuàng)建出來的
typeof(Object)//function 所以, function Object(){ Native Code } 等價于 var Object = new Function();
那么Object的__proto__指向的是Function.prototype,也即是
Object.__proto__ === Function.prototype //true
下面再來看Function.prototype的__proto__指向哪里
因為JS中所有的東西都是對象,那么,F(xiàn)unction.prototype 也是對象,既然是對象,那么Function.prototype肯定是通過Object創(chuàng)建出來的,所以,
Function.prototype.__proto__ === Object.prototype //true
綜上所述,F(xiàn)unction和Object的原型以及原型鏈的關(guān)系可以歸納為下圖。
對于單個的對象實例,如果通過Object創(chuàng)建,
var obj = new Object();
那么它的原型和原型鏈的關(guān)系如下圖
如果通過函數(shù)對象來創(chuàng)建,
function Foo(){ } var foo = new Foo();
那么它的原型和原型鏈的關(guān)系如下圖
那JavaScript的整體的原型和原型鏈中的關(guān)系就很清晰了,如下圖所示
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/107771.html
摘要:構(gòu)造函數(shù)創(chuàng)建一個對象上邊這個例子,我們通過構(gòu)造函數(shù)創(chuàng)建了一個實例,從這個實例到他的原型到最后得,他們之間得關(guān)系,就形成了一個原型鏈和首先上邊這個例子里邊,我們聲明了一個構(gòu)造函數(shù),在后再這個構(gòu)造函數(shù)里邊有一個的屬性。 構(gòu)造函數(shù)創(chuàng)建一個對象 function Person() { } var person = new Person(); person.name = zhangsan; c...
摘要:原型鏈與繼承當(dāng)談到繼承時,只有一種結(jié)構(gòu)對象。如果對該圖不怎么理解,不要著急,繼續(xù)往下看基于原型鏈的繼承對象是動態(tài)的屬性包指其自己的屬性。當(dāng)使用操作符來作用這個函數(shù)時,它就可以被稱為構(gòu)造方法構(gòu)造函數(shù)。 原型鏈與繼承 當(dāng)談到繼承時,JavaScript 只有一種結(jié)構(gòu):對象。每個實例對象(object )都有一個私有屬性(稱之為proto)指向它的原型對象(prototype)。該原型對象也...
摘要:我們用一張圖表示構(gòu)造函數(shù)和實例原型之間的關(guān)系好了構(gòu)造函數(shù)和實例原型之間的關(guān)系我們已經(jīng)梳理清楚了,那我們怎么表示實例與實例原型,也就是或者和之間的關(guān)系呢。 開篇: 在Brendan Eich大神為JavaScript設(shè)計面向?qū)ο笙到y(tǒng)的時候,借鑒了Self 和Smalltalk這兩門基于原型的語言,之所以選擇基于原型的面向?qū)ο笙到y(tǒng),并不是因為時間匆忙,它設(shè)計起來相對簡單,而是因為從一開始B...
摘要:我們用一張圖表示構(gòu)造函數(shù)和實例原型之間的關(guān)系好了構(gòu)造函數(shù)和實例原型之間的關(guān)系我們已經(jīng)梳理清楚了,那我們怎么表示實例與實例原型,也就是或者和之間的關(guān)系呢。 開篇: 在Brendan Eich大神為JavaScript設(shè)計面向?qū)ο笙到y(tǒng)的時候,借鑒了Self 和Smalltalk這兩門基于原型的語言,之所以選擇基于原型的面向?qū)ο笙到y(tǒng),并不是因為時間匆忙,它設(shè)計起來相對簡單,而是因為從一開始B...
摘要:上圖中的在原型繼承稱作構(gòu)造器。構(gòu)造器就是一個普通的函數(shù),但是將操作符用到構(gòu)造器上時,它會執(zhí)行一個叫的過程。從第條可以看到,構(gòu)造器生成的對象的屬性會指向構(gòu)造器的值,這就是我們構(gòu)造原型鏈的關(guān)鍵。 基于類的繼承是大多數(shù)人所熟悉的,也是比較容易理解的。當(dāng)我們形成類型繼承的思維定勢后,再次接觸原型繼承可能會覺得有些奇怪并難以理解。你更可能會吐槽,原型繼承根本就不能叫做繼承,一點都不面向?qū)ο蟆1救?..
閱讀 1967·2021-11-24 10:45
閱讀 1459·2021-11-18 13:15
閱讀 4542·2021-09-22 15:47
閱讀 3918·2021-09-09 11:36
閱讀 2012·2019-08-30 15:44
閱讀 3092·2019-08-29 13:05
閱讀 2502·2019-08-29 12:54
閱讀 1994·2019-08-26 13:47