Prototype是js面向?qū)ο笾袑?shí)現(xiàn)多態(tài)的核心氮凝,或者說是區(qū)別于普通面向?qū)ο笳Z言如java等的靈魂所在陕凹,越是這種玩意恳不,越是坑檩小,因?yàn)槿绻麑?duì)這些理解不深,反而會(huì)被它的一些表面現(xiàn)象所迷惑烟勋,導(dǎo)致各種深層bug规求,不斷入坑。
這里對(duì)自己之前所做的項(xiàng)目中所用到的此部分內(nèi)容做一些總結(jié)
思考
開篇我想就我之前用JS的一些體會(huì)卵惦,簡(jiǎn)單說幾個(gè)點(diǎn)
- 人們常說阻肿,JS中萬物皆對(duì)象,所以很多時(shí)候如果我們用Java等語言的(類-對(duì)象)邏輯去套JS反而會(huì)讓自己無法理解沮尿。
這里丛塌,我們需要破而后立,先樹立一個(gè)概念蛹找,JS萬物皆對(duì)象姨伤,記住是對(duì)象,不是類庸疾!即使我們會(huì)定義一些function乍楚,然后使用new去定義初始化一些對(duì)象,但是這里的function仍然是對(duì)象届慈,只是剛好能夠用來幫助初始化一類對(duì)象而已
JS中的對(duì)象
通常來說徒溪,javascript中的對(duì)象就是一個(gè)指向prototype的指針和一個(gè)自身的屬性列表忿偷。javascript創(chuàng)建對(duì)象時(shí)采用了寫時(shí)復(fù)制的理念。
只有 構(gòu)造器 才具有prototype屬性臊泌,原型鏈繼承就是創(chuàng)建一個(gè)新的指針鲤桥,指向構(gòu)造器的prototype屬性。
prototype屬性之所以特別渠概,是因?yàn)閖avascript時(shí)讀取屬性時(shí)的遍歷機(jī)制決定的茶凳。本質(zhì)上它就是一個(gè)普通的指針。
構(gòu)造器包括以下對(duì)象:
- Object
- Function
- Array
- Date
- String
Prototype
Prototype是啥
這里強(qiáng)烈推薦參考[關(guān)于JS中的constructor與prototype][],這應(yīng)該是全網(wǎng)寫的最直白的播揪,幫助我們小白看懂其中的邏輯
首先贮喧,prototype我的理解是一個(gè)對(duì)象的屬性,根據(jù)上文猪狈,我們知道只有構(gòu)造器才有prototype屬性箱沦。
prototype屬性又指向了一個(gè)prototype對(duì)象,注意prototype屬性與prototype對(duì)象是兩個(gè)不同的東西雇庙,要注意區(qū)別谓形。在prototype對(duì)象中又有一個(gè)constructor屬性,這個(gè)constructor屬性同樣指向一個(gè)constructor對(duì)象疆前,而這個(gè)constructor對(duì)象恰恰就是這個(gè)function函數(shù)本身寒跳。
看圖(本文圖均出自[關(guān)于JS中的constructor與prototype][]文章,下文不再說明)
Sample Code:
function Person(name)
{
this.name=name;
this.showMe=function() {
alert(this.name);
}
};
var one=new Person('js');
alert(one.prototype)//undefined
alert(typeof Person.prototype);//object
alert(Person.prototype.constructor);//function Person(name) {...};
分析:
其中one是具體的構(gòu)造器弄出來的對(duì)象峡继,所以沒有prototype屬性冯袍。而Function有(Function是構(gòu)造器),并且prototype中有只想具體構(gòu)造函數(shù)的屬性
JS中對(duì)象的定義過程
按照《悟透javascript》書中說的碾牌,new形式創(chuàng)建對(duì)象的過程實(shí)際上可以分為三步:
第一步是建立一個(gè)新對(duì)象(叫A吧)康愤;
第二步將該對(duì)象(A)內(nèi)置的原型對(duì)象設(shè)置為構(gòu)造函數(shù)(就是Person)prototype 屬性引用的那個(gè)原型對(duì)象;
第三步就是將該對(duì)象(A)作為this 參數(shù)調(diào)用構(gòu)造函數(shù)(就是Person)舶吗,完成成員設(shè)置等初始化工作征冷。
其中第二步中出現(xiàn)了一個(gè)新名詞就是內(nèi)置的原型對(duì)象,注意這個(gè)新名詞跟prototype對(duì)象不是一回事誓琼,為了區(qū)別我叫它inobj,inobj就指向了函數(shù)Person的prototype對(duì)象检激。在person的prototype對(duì)象中出現(xiàn)的任何屬性或者函數(shù)都可以在one對(duì)象中直接使用,這個(gè)就是javascript中的原型繼承了腹侣。
這樣one對(duì)象通過內(nèi)置的原型對(duì)象inobj就可以直接訪問Person的prototype對(duì)象中的任何屬性與方法了叔收。這也就解釋了上面的代碼中為什么one可以訪問form函數(shù)了。因?yàn)閜rototype對(duì)象中有一個(gè)constructor屬性傲隶,那么one也可以直接訪問constructor屬性饺律。
JS繼承(原型鏈)
繼承的實(shí)現(xiàn)很簡(jiǎn)單,只需要把子類的prototype設(shè)置為父類的一個(gè)對(duì)象即可跺株。注意這里說的可是對(duì)象哦复濒!
那么通過prototype屬性實(shí)現(xiàn)繼承的原理是什么呢脖卖?還是先看圖形說明,然后編寫代碼進(jìn)行驗(yàn)證巧颈。
Sample Code:
function Person(name) {
this.name=name;
this.showMe=function() {
alert(this.name);
}
};
Person.prototype.from=function() {
alert('I come from prototype.');
}
function SubPerson() {
}
SubPerson.prototype=new Person();
var subOne=new SubPerson();
subOne.from();//I come from prototype.
alert(subOne.constructor);//function Person(name) {...};
alert(SubPerson.prototype.constructor);//function Person(name) {...};
這個(gè)所謂的原型鏈就是從最下方的子對(duì)象開始畦木,往自己的原型上溯。找調(diào)用的屬性或者方法砸泛,如果找不到就繼續(xù)找原型的原型十籍。一直下去。這個(gè)比較好理解晾嘶,和普通的父類回溯是差不多的邏輯妓雾。
What's More
至此娶吞,prototype的大概應(yīng)該有所理解了垒迂。那么還有幾個(gè)非常重要的細(xì)節(jié),并且是使用最多的特性需要再?gòu)?qiáng)調(diào)一下妒蛇,其實(shí)已經(jīng)隱藏在上面的code里了机断。
- 每一個(gè)對(duì)象(被構(gòu)造器創(chuàng)造出來的對(duì)象)姑且成為myObj,即new+某個(gè)function弄出的對(duì)象绣夺,可以直接訪問constructor屬性吏奸,這玩意指向的就是構(gòu)造器
但是同時(shí),這玩意是沒有prototype屬性的陶耍,因?yàn)閜rototype只在構(gòu)造器里才有奋蔚。不過我們可以這樣找到他的prototype,那就是myObj. constructor. prototype - 函數(shù)對(duì)象中自身聲明的方法和屬性與prototype聲明的對(duì)象有什么差別?
有下面幾個(gè)差別:
- 自身聲明的方法和屬性是 靜態(tài)的, 也就是說你在聲明后,試圖再去增加新的方法或者修改已有的方法,并不會(huì) 對(duì)由其已經(jīng)創(chuàng)建的對(duì)象產(chǎn)生影響
- 而prototype可以動(dòng)態(tài)地增加新的方法或者修改已有的方法, 從而是 動(dòng)態(tài)的 ,一旦 父函數(shù)對(duì)象 聲明了相關(guān) 的prototype屬性,由其創(chuàng)建的對(duì)象會(huì) 自動(dòng)繼承 這些prototype的屬性.
總結(jié)下烈钞,結(jié)合上文開頭所述泊碑,prototype是指針,指向的是一個(gè)prototype對(duì)象毯欣。而具體的調(diào)用在在具體使用的時(shí)候馒过,才去根據(jù)原型鏈一個(gè)一個(gè)去找的。所以在你update了prototype的屬性和方法后酗钞,所有繼承了這個(gè)prototype的對(duì)象都能動(dòng)態(tài)的自動(dòng)繼承這些新update的玩意腹忽。這個(gè)才是JS作為動(dòng)態(tài)的面向?qū)ο笳Z言最有價(jià)值的玩意。
Javascript的方法
JS中有三類方法
a. 類方法
b. 對(duì)象方法
c. 原型方法
Sample Code:
function People(name) {
this.name=name;
//對(duì)象方法
this.Introduce=function(){
alert("My name is "+this.name);
}
}
//類方法
People.Run=function(){
alert("I can run");
}
//原型方法
People.prototype.IntroduceChinese=function(){
alert("我的名字是"+this.name);
}
參考文章
[JS中的prototype][]
[關(guān)于JS中的constructor與prototype][]
[javascript必知必會(huì)之prototype][]
[JS中的prototype]:http://www.cnblogs.com/yjf512/archive/2011/06/03/2071914.html
[關(guān)于JS中的constructor與prototype]:http://blog.csdn.net/niuyongjie/article/details/4810835
[javascript必知必會(huì)之prototype]:http://www.cnblogs.com/mindsbook/archive/2009/09/19/javascriptYouMustKnowPrototype.html