第四章 構(gòu)造函數(shù)和原型對(duì)象

也許你還沒有理解構(gòu)造函數(shù)和原型對(duì)象的時(shí)候已經(jīng)在javascript的路上走了很久,但直到你很好的掌握它們之前你不會(huì)真正欣賞這門語言,由於Javascript缺乏類,它使用構(gòu)造函數(shù)和原型對(duì)象來給對(duì)象帶來與類相似的功能,但是,這些相似的功能並不一定表現(xiàn)的跟類完全一致,在本章中,你會(huì)詳細(xì)看到j(luò)avascript如何使用構(gòu)造函數(shù)和原型對(duì)象來創(chuàng)建對(duì)象。

4.1構(gòu)造函數(shù)

構(gòu)造函數(shù)就是你用new創(chuàng)建對(duì)象時(shí)調(diào)用的函數(shù)。到目前爲(wèi)止,你已經(jīng)見過好幾次內(nèi)建javascript構(gòu)造函數(shù)了,例如,Object,Array和Function。使用構(gòu)造函數(shù)的好處在於用同一個(gè)構(gòu)造函數(shù)創(chuàng)建的對(duì)象都具有同樣的屬性和方法。如果想創(chuàng)建多個(gè)相同的對(duì)象,你可以創(chuàng)建自己的構(gòu)造函數(shù)以及引用類型

構(gòu)造函數(shù)也是函數(shù)。你會(huì)用同樣的方法定義它,唯一的區(qū)別是構(gòu)造函數(shù)名字應(yīng)該首字母大寫,以此區(qū)分其他函數(shù)。下列定義了一個(gè)空的Person函數(shù)。

function Person(){

//intertionally empty

}

這個(gè)函數(shù)就是構(gòu)造函數(shù)。構(gòu)造函數(shù)和其他函數(shù)並沒有絕對(duì)的與發(fā)上的區(qū)別。唯一的線索就時(shí)首字母大寫。

定義好構(gòu)造函數(shù)後,你就可以用它來創(chuàng)建對(duì)象,例如下面的Person對(duì)象

var person1=new Person();

var person2=new Person();

如果沒有需要傳遞給構(gòu)造函數(shù)的參數(shù),你甚至可以忽略小括號(hào)。

var person1=new Person;

var person2=new Person;

即使Person構(gòu)造函數(shù)並沒有顯式返回任何東西,person1和person2都會(huì)被認(rèn)爲(wèi)時(shí)一個(gè)新的Person類型的實(shí)例。new操作符會(huì)自動(dòng)創(chuàng)建給定類型的對(duì)象並返回給它們。這也意味著,你可以用instanceof操作符獲取對(duì)象的類型。如下所示。

console.log(person1 instanceof Person);

console.log(person1 instanceof Person);

由於person1和person2被Person構(gòu)造函數(shù)創(chuàng)建,用instanceof檢查它們是否爲(wèi)Person類型時(shí)返回true。

你也可以用構(gòu)造函數(shù)屬性來檢查一個(gè)對(duì)象的類型。每個(gè)對(duì)象在創(chuàng)建時(shí)都自動(dòng)擁有一個(gè)構(gòu)造函數(shù)屬性,其中包含一個(gè)指向其構(gòu)造函數(shù)的引用。那些通過對(duì)象字面形式或Object構(gòu)造函數(shù)創(chuàng)建出來的泛用對(duì)象,其構(gòu)造函數(shù)指向Object;那些通過自定義構(gòu)造函數(shù)創(chuàng)建出來的對(duì)象,其構(gòu)造函數(shù)屬性指向創(chuàng)建它的構(gòu)造函數(shù)。如下例person1和person2的constructor屬性Person。

console.log(person1.constructor ===Person);

console.log(person2.constructo===Person);

console.log函數(shù)對(duì)兩個(gè)對(duì)象都輸出true。因爲(wèi)它們都是用Person構(gòu)造函數(shù)創(chuàng)建的。

雖然對(duì)象實(shí)例機(jī)器構(gòu)造函數(shù)之間存在這樣的關(guān)係。但是還是建議你使用instanceof來檢查對(duì)象類型。這是因爲(wèi)構(gòu)造函數(shù)屬性可以被覆蓋,並不一定完全準(zhǔn)確。

當(dāng)然,一個(gè)空的構(gòu)造函數(shù)並不是十分游泳的。使用構(gòu)造函數(shù)的目的時(shí)爲(wèi)了輕鬆創(chuàng)建許多擁有相同屬性和方法的對(duì)象。爲(wèi)此,你只需要在構(gòu)造函數(shù)內(nèi)簡單的給this天界你想要的任何屬性即可。如下例。

function Person(name){

this.name =name;

this.sayName=function(){

console.log(this.name);

}}



該板根的Person構(gòu)造函數(shù)接受一個(gè)命名參數(shù)name並將賦給this對(duì)象的name屬性。同時(shí),構(gòu)造函數(shù)還給對(duì)象添加一個(gè)sayName()方法。當(dāng)你調(diào)用構(gòu)造函數(shù)時(shí),new會(huì)自動(dòng)創(chuàng)建this對(duì)象。且其類型就是構(gòu)造函數(shù)的類型,(在本例中爲(wèi)Person)構(gòu)造函數(shù)本身不不需要返回一個(gè)值,new操作符會(huì)幫你返回。

現(xiàn)在你而可以用Person構(gòu)造函數(shù)來創(chuàng)建具有初始name屬性的對(duì)象了。

var person1=new Person("Nicholas");

var person2=new Person("Greg");

console.log(person1.name);

console.log(person2.name);

person1.sayName();

person2.sayName();

每個(gè)對(duì)象都有自己的name屬性,所以sayName()方法可以根據(jù)不同對(duì)象返回不同的值。

注意:你也可以在構(gòu)造函數(shù)中顯式調(diào)用return,如果返回的值是一個(gè)對(duì)象,它會(huì)代替新創(chuàng)建的對(duì)象實(shí)例返回。如果返回的值時(shí)一個(gè)原始類型那個(gè),他會(huì)被忽略,新創(chuàng)建的對(duì)象實(shí)例會(huì)被返回。

構(gòu)造函數(shù)允許你用一致的方式初始化一個(gè)類型的實(shí)例。在使用對(duì)象錢設(shè)置好所有的屬性。如下例。你也可以在構(gòu)造函數(shù)中用Ocject.defineProperty()方法 來幫助我們初始話。

function Person(name){

Object.defineProperty(this,"name"{

get:function(){

return name;},

set:function(newName){

name =newName;

},

enumerable:true,

configurable:true

});

this.sayName=function(){

console.log(this.name)}

}

在這個(gè)版本的Person構(gòu)造函數(shù)中,name屬性是一個(gè)訪問者屬性,利用name參數(shù)來保存實(shí)際的值,之所以能這樣做,是因爲(wèi)命名參數(shù)就相當(dāng)於一個(gè)本地變量。

始終確保用new調(diào)用構(gòu)造函數(shù);否則,你就是在冒改全局對(duì)象的風(fēng)險(xiǎn),而不是創(chuàng)建一個(gè)新的對(duì)象,考慮如下代碼中發(fā)生了什麼。

var ?person1= Person("Nicholas");

console.log(person1.instanceof Person);

console.log(name);

console.log(typeof person1);

當(dāng)Person不是被new調(diào)用時(shí),構(gòu)造函數(shù)中的this對(duì)象等於全局this對(duì)象,由於person構(gòu)造函數(shù)依靠new提供返回值,person1變量爲(wèi)undefined。沒有new,Person只不過時(shí)一個(gè)沒有返回語句的函數(shù)。對(duì)this.name的賦值實(shí)際上時(shí)創(chuàng)建來一個(gè)全局變量name來保存?zhèn)鬟f給Person的參數(shù)。第6章介紹的幾個(gè)對(duì)象模式中將包括對(duì)這一問題的解決辦法

注意;在嚴(yán)格模式下,當(dāng)你不通過new調(diào)用Person構(gòu)造函數(shù)時(shí)會(huì)出現(xiàn)錯(cuò)誤。這是因爲(wèi)嚴(yán)格模式並沒有爲(wèi)全局對(duì)象設(shè)置this。this保持爲(wèi)undefined,而當(dāng)你是試圖爲(wèi)undefined添加屬性時(shí)都會(huì)出錯(cuò)

構(gòu)造函數(shù)允許你給對(duì)象配置同樣的屬性,但是鉤爪函數(shù)並沒有消除冗餘臺(tái)嗎,在之前的例子中,每一個(gè)對(duì)象都有自己的sayName()方法。這意味著如果你有100個(gè)對(duì)象實(shí)例,你就有100個(gè)函數(shù)做相同的使其,只是使用的數(shù)據(jù)不同。如果所有的對(duì)象實(shí)例共享一個(gè)方法更加有效,該方法可以使用this.name訪問正確的數(shù)據(jù),這就是需要用到原型對(duì)象啦。

4.2 原型對(duì)象

可以把原型對(duì)象看成是對(duì)象的基類。幾乎所有的函數(shù)(除了一些內(nèi)建函數(shù))都有一個(gè)名爲(wèi)property的屬性,改屬性時(shí)一個(gè)原型對(duì)象用來創(chuàng)建新的對(duì)象實(shí)例。所有創(chuàng)建的對(duì)象實(shí)例共享該原型對(duì)象,且這些對(duì)象實(shí)例可以訪問原型對(duì)象的屬性。例如,hasOwnProperty()方法被定義在泛用對(duì)象Object的原型對(duì)象中,但卻可以被任何對(duì)象當(dāng)作自己的屬性訪問,如下例

var book={

title:"The Principles of Object-Oriented JavaScript"

};

console.log("title" in book);

console.log(book.hasOwnProperty("title"));

console.log("hasOwnProperty" in book);

console.log(book.hasOwnProperty("hasOwnProperty"));

console.log(Object.prototype.hasOwnProperty("hasOwnProperty"));

即時(shí)book中並沒有hasOwnProperty()這個(gè)方法的定義,仍然可以通過book.hasOwnProperty()訪問該方法。這是因爲(wèi)該方法的定義存在與Object.prototype中。in操作符對(duì)原型屬性和自有屬性都返回true。

鑑別一個(gè)原型對(duì)象 ?你可以用這樣一個(gè)函數(shù)去鑑別一個(gè)屬性是否是原型對(duì)象。

function hasPrototypeProperty(object,name){

return name in object &&! object.hasOwnProperty(name);

}

console.log(hasPrototypeProperty(book,"title"));

console.log(hasPrototypeProperty(book,"hasOwnProperty"));

4.2.1 [[Prototype]]屬性

一個(gè)對(duì)象實(shí)例通過內(nèi)部屬性[[Prototype]]跟蹤其原型對(duì)象。該屬性時(shí)一個(gè)指向該實(shí)例使用的原型對(duì)象的指針。當(dāng)你使用new創(chuàng)建一個(gè)新的對(duì)象的時(shí)候,構(gòu)造函數(shù)的原型對(duì)象會(huì)給該對(duì)象的[[Prototype]]屬性。[[Prototype]]屬性是讓多個(gè)對(duì)象實(shí)例引用同一個(gè)原型對(duì)象來減少重複代碼的。

你可以調(diào)用對(duì)象的Object.getPrototypeOf()方法讀取[[Prototype]]屬性的值。下例代碼檢查一個(gè)泛用空對(duì)象的[[Prototype]]屬性。

var object={};

var prototype=Object.getPrototypeOf(object);

console.log(prototype=== Object.prototype);// true

如上例,任何一個(gè)泛用對(duì)象,其[[Prototype]]屬性始終指向Object.prototype。

注意:大部分JavaScript引擎在所有對(duì)象上都支持一個(gè)名爲(wèi)_proto_的屬性,該屬性使你可以世界讀寫[[Prototype]]屬性。firefox,safari,chrome和node.js都支持該屬性,且EcmaScript6正在考慮將其加入到標(biāo)準(zhǔn)中。

你也可以用isPrototype()方法檢查某個(gè)對(duì)象是否時(shí)另一個(gè)對(duì)象的原型對(duì)象。該方法被包含在所有對(duì)象中。

var object={};

console.log(Object.prototype.isPrototypeOf(object)); //true


因爲(wèi)object時(shí)一個(gè)泛用對(duì)象,它的原型時(shí)Object.prototype。意味著本例中的isPrototypeOf()方法返回true。

當(dāng)讀取一個(gè)對(duì)象的屬性時(shí),javascript引擎首先在該對(duì)象的自有屬性中查找屬性的名字,如果找到則返回,如果自有屬性中不包含該名字,則javascript會(huì)搜索[[Prototype]]中的對(duì)象。如果找打則返回。如果找不到,則返回undefined。

下列先創(chuàng)建一個(gè)沒有自有屬性的對(duì)象。

var object={};

console.log(object.toString());

object.toString=function(){

return "[object Custom]";

};

console.log(object.toString());

delete object.toString;

console.log(object.toString());

delete object.toString;

console.log(object.toString());

本例最初的toString()方法來自於原型對(duì)象,默認(rèn)返回"[object Object]"如果你定義一個(gè)名叫toString的自有屬性,那麼每次調(diào)用該對(duì)象的toString()方法都會(huì)調(diào)用該自有屬性。自有屬性會(huì)覆蓋原型屬性。僅當(dāng)自有屬性被刪除時(shí),原型屬性纔會(huì)再以此被使用。delete操作符僅對(duì)自有屬性起作用,你無法闡述一個(gè)對(duì)象的原型屬性。還有就是無法給一個(gè)對(duì)的原型屬性賦值。

4.2.2 在構(gòu)造函數(shù)總使用原型對(duì)象

原型對(duì)象的共享機(jī)制使得它們成爲(wèi)一次性爲(wèi)所有對(duì)象定義方法的理想手段。因爲(wèi)一個(gè)方法對(duì)所有的對(duì)象實(shí)例做相同的使其,美麗有每個(gè)實(shí)例都要有一份自己的方法。

將方法放在原型對(duì)象中並用this訪問當(dāng)前實(shí)例時(shí)更有效的做法。下例展現(xiàn)了新Person構(gòu)造函數(shù)。

function Person(name){

this.name=name;

};

Person.prototype.sayName=function(){

console.log(this.name);

};

var person1=new Person("Nicholas");

var person2=new Person("Greg");

console.log(person1.name);

console.log(person2.name);

person1.sayName();

person2.sayName();

在這個(gè)版本的Person構(gòu)造函數(shù)中,sayName()被定義在原型對(duì)象上而不是構(gòu)造函數(shù)中。創(chuàng)建出的對(duì)象和本章之前的例子中創(chuàng)建的對(duì)象別無二致,只不過sayName()現(xiàn)在是一個(gè)原型屬性而不是自有屬性。在person1和person2調(diào)用sayName()時(shí),相對(duì)的this的值被分別賦在person1或person2.

也可以在原型對(duì)象上存儲(chǔ)其他類型的數(shù)據(jù),但在存儲(chǔ)引用值時(shí)需要注意。因爲(wèi)這些引用值會(huì)被多個(gè)實(shí)例共享,可能搭建不希望一個(gè)實(shí)例能夠改變另一個(gè)實(shí)例的值。下例顯示當(dāng)你不注意你的引用值的實(shí)際指向那裏時(shí)會(huì)發(fā)生的情況。

function Person(name){

this.name=name;

}

Person.prototype.sayName=function(){

console.log(this.name);

};

Person.prototype.favorites=[];

var person1=new Person("Nicholas");

var person2=new Person("Greg");

person1.favorites.push("pizza");

person2.favorites.push("quinoa");

console.log(person1.favorites);

console.log(person2.favorites);

favorites屬性被定義在原型對(duì)象上,意味著person1.favorites和person2.favorites指向同一個(gè)數(shù)組。你對(duì)任一Person對(duì)象的favorites插入的值都將成爲(wèi)原型對(duì)象上數(shù)據(jù)的元素。但這可能不是你期望的行爲(wèi),所以在原型對(duì)象上定義時(shí)你要非常小心。

雖然你可以在原型對(duì)象上一一添加屬性,但是很多開發(fā)者會(huì)使用一種更簡潔的方式:直接用一個(gè)對(duì)象字面形式替換原型對(duì)象。

如下:

function Person(name){

this.name=name;

};

Person.prototype={

sayName:function(){

console.log(this.name);

},

toString:function(){

return “[Person”+this.name+"]";

}

};

上段代碼在原型對(duì)象上定義了兩個(gè)訪拿廣發(fā),sayName()和toString()。這種定義的方式非常流行,因爲(wèi)這種方式不需要多次鍵入Person.prototype.但是有一個(gè)副作用需要注意。

var ?person1=new Person("Nicholas");

console.log(person1 instanceof Person);

console.log(person1.constructor ===Person);

console.log(person1.constructor ===Object);

使用對(duì)象字面形式改寫原型對(duì)象改變了構(gòu)造函數(shù)的屬性,因此現(xiàn)在指向Object而不是Person。這是因爲(wèi)原型對(duì)象具有一個(gè)constructor屬性,這是其他對(duì)象的實(shí)例沒有的。當(dāng)一個(gè)函數(shù)被創(chuàng)建時(shí),它的prototype屬性也被創(chuàng)建,且該原型對(duì)象的constructor屬性指向該函數(shù)。當(dāng)使用對(duì)字面形式改寫原型對(duì)象的Peroson.prototype時(shí),其constructor屬性將設(shè)置爲(wèi)泛用對(duì)象Object。爲(wèi)了避免這一點(diǎn)。需要在改寫原型對(duì)象時(shí)手動(dòng)重置其constructor屬性,如下例。

function Person(name){

this.name=name;

};

Person.prototype={

constructor:Person,

sayName:function(){

console.log(this.name);

},

toString:function(){

return "[Person"+this.name+" ]";

}

};

var person1=new Person("Nicholas");

var person2=new Person("Greg");

console.log(person1 instanceof Person);

console.log(person1.constructor === Person);

console.log(person1.constructor === Object);

console.log(person. instanceof Person);

console.log(person2.constructor === Person);

console.log(person2.constructor === Object);

本例顯示指定了原型對(duì)象的constructor屬性,爲(wèi)了不忘記賦值,最好把它設(shè)置爲(wèi)原型對(duì)象的第一屬性。

構(gòu)造函數(shù),原型對(duì)象和對(duì)象實(shí)例之間的關(guān)係最有趣的一個(gè)方面也許就是對(duì)象的實(shí)例和構(gòu)造函數(shù)之間沒有之間聯(lián)繫,不過對(duì)象實(shí)例和原型對(duì)象以及原型對(duì)象和構(gòu)造函數(shù)之間都有之間關(guān)係。這樣的關(guān)係意味著,如果打斷對(duì)象的實(shí)例和原型對(duì)之間的聯(lián)繫,那麼也將打斷對(duì)象和實(shí)例和其構(gòu)造函數(shù)的聯(lián)繫。

4.2.3 改變?cè)蛯?duì)象

給定類定的所有對(duì)象實(shí)例共享一個(gè)原型對(duì)象,所以你可以一次性擴(kuò)充所有對(duì)象實(shí)例。記住,[[Prototype]]屬性只是包含了一個(gè)指向原型對(duì)象的指針,任何對(duì)原型對(duì)象的改變都立即反映到所有引用它的對(duì)象實(shí)例上。這意味著你給原型對(duì)象添加的新成員都可以立即被所有已經(jīng)存在的對(duì)象實(shí)例使用,如下例

function Person(name){

this.name =name;

}

Person.prototyp={

constructor:Person,

sayName:function(){

console.log(this.name);

},

toString:function(){

return "[Person"+this.name+"]"};

}

var peson1=new Person("Nicholas");

var person2=new Person("Greg");

console.log("sayHi" in ?person1);

console.log("sayHi" in person2 );

Person.prototype.sayHi=function(){

console.log("Hi");

};

person1.sayHi();

person2.sayHi();

在這段代碼中,Person類型一開始只有兩個(gè)方法,sayName()和toString(),然後在創(chuàng)建兩個(gè)Person對(duì)象實(shí)例後給原型對(duì)象添加了一個(gè)sayHi(),對(duì)命名屬性的查找時(shí)在每次訪問屬性的時(shí)候發(fā)生的。所以可以做到無縫體驗(yàn)。

可以隨時(shí)改變?cè)蛯?duì)象的能力在封印對(duì)象和凍結(jié)對(duì)象上有一個(gè)十分有趣的後果。當(dāng)你在一個(gè)對(duì)象上使用Obejct.Seal()或Obejct.freeze()時(shí),完全是在操作對(duì)象的自有屬性,你無法添加自有屬性或改變凍結(jié)對(duì)象的自有屬性,但是仍然可以通過原型對(duì)象上添加屬性來擴(kuò)展這些對(duì)象的實(shí)例。如下例;

var person1=new Person("Nicholas");

var person2=new Person("Greg");

Object.freeze(person1);

Person.prototype.sayHi=function(){

console.log("Hi");

};

person1.sayHi();

person2.sayHi();

本例中有兩個(gè)Person的對(duì)象實(shí)例。Person1是 凍結(jié)對(duì)象而person2是普通對(duì)象,當(dāng)你在原型對(duì)象上添加sayHi()時(shí),person1和person2都獲得了這一新方法,這似乎不合person1的凍結(jié)狀態(tài)。其實(shí)[[Prototye]]屬性是對(duì)象實(shí)例的自有屬性,屬性本身被凍結(jié)。但其指向的值(原型對(duì)象)並沒有凍結(jié)。

注意:實(shí)際開發(fā)javascript時(shí),你不可能會(huì)頻繁地使用原型對(duì)象,但時(shí)理解對(duì)象實(shí)例以及其原型對(duì)象之間的關(guān)係是非常重要的,而像這樣的奇怪例子有助於你理解這些概念。

4.2.4 內(nèi)建對(duì)象的原型對(duì)象

到這裏,你可能會(huì)疑惑原型對(duì)象是否也允許你改版javascript引擎的標(biāo)準(zhǔn)內(nèi)建對(duì)象,答案是yes。所有內(nèi)建對(duì)象都有搞糟函數(shù),因此也都有原型對(duì)象給你去改變。例如,在所有數(shù)組上添加一個(gè)新的方法只需要簡單地修改Array.prototype即可。

Array.prototype.sum=function(){

return this.reduce(function(pervious,current){

return previous+current;

});

};

var number =[1,2,3,4,5,6];

var result=number.sum();

console.log(result);

這個(gè)例子在Array.prototype上創(chuàng)建了一個(gè)名爲(wèi)sum()的方法,該方法對(duì)該數(shù)組的所有元素求和並返回。numbers數(shù)組通過原型對(duì)象自動(dòng)擁有這個(gè)方法,在sum()內(nèi)部,this指向數(shù)組的對(duì)象實(shí)例numbers,於是該方法也可以自由使用數(shù)組的其他方法,比如reduce()。

你可能還記得字符串,數(shù)字和布爾類型都有內(nèi)建的原始封裝類型來幫助我們像使用普通對(duì)象一樣來使用它們,如果改變?cè)挤庋b類型的原始對(duì)象,你就可以給這些原始值添加更多的功能,如下例

String.prototype.capitalize=function(){

return this.charAt(0).toUpperCase()+this.substring(1);

};

var message ="hello world";

console.log(message.capitalize());

這段代碼爲(wèi)字符轉(zhuǎn)創(chuàng)建了一個(gè)名爲(wèi)capitalize()的方法,String類型是字符串的原始封裝類型。修改其原型對(duì)象意味著所有的字串都自動(dòng)獲得這些改動(dòng)。

注意:修改內(nèi)建對(duì)象來實(shí)驗(yàn)各種功能是既有好玩的事情,但在生產(chǎn)環(huán)境中這門做不是一個(gè)好主意,開發(fā)者們都期望一個(gè)內(nèi)建對(duì)象具有一定的方法並表現(xiàn)出一定的行爲(wèi),故意改變內(nèi)建對(duì)象會(huì)破壞這種期望導(dǎo)致其他開發(fā)者無法確定這些對(duì)象會(huì)如何工作。

4.3 總結(jié)

構(gòu)造函數(shù)就是用new操作符調(diào)用普通函數(shù),你可以隨時(shí)定義你自己的構(gòu)造函數(shù)來創(chuàng)建多個(gè)具有同樣屬性的對(duì)象。可以用instaceof 操作符或直接訪問constructor屬性來鑑別對(duì)象被那個(gè)構(gòu)造函數(shù)創(chuàng)建的。

每一個(gè)函數(shù)都具有prototype屬性,它定義了該構(gòu)造函數(shù)的所有對(duì)象的共享的屬性,通常,共享的方法和原始值屬性被定義在原型對(duì)象裏,而其他屬性都定義在構(gòu)造函數(shù)裏。constructor屬性實(shí)際上被定義在原型對(duì)象裏供所有對(duì)象實(shí)例共享。

原型對(duì)象被保存在對(duì)象的實(shí)例內(nèi)部的[[Prototype]]屬性中,這個(gè)屬性時(shí)一個(gè)引用而不是一個(gè)副本。由於javascript查找屬性的機(jī)制。你對(duì)原型對(duì)象的修改都立刻出現(xiàn)在所有對(duì)象的實(shí)例中。當(dāng)你試圖訪問一個(gè)對(duì)象的某個(gè)屬性時(shí),javascript首先在自有屬性中查找該屬性的名字,如果在自有屬性中沒有找到則查找原型屬性。這樣的機(jī)制意味著原型對(duì)象可以隨時(shí)改變而引用它的對(duì)象實(shí)例則立即反映出這些改變。

內(nèi)建對(duì)象也有可以被修改的原型對(duì)象。雖然不建議在生產(chǎn)環(huán)境中這麼做。但它們可以被用來實(shí)驗(yàn)或驗(yàn)證新功能。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,967評(píng)論 6 531
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,273評(píng)論 3 415
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,870評(píng)論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,742評(píng)論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,527評(píng)論 6 407
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,010評(píng)論 1 322
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,108評(píng)論 3 440
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,250評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,769評(píng)論 1 333
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,656評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,853評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,371評(píng)論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,103評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,472評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,717評(píng)論 1 281
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,487評(píng)論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,815評(píng)論 2 372

推薦閱讀更多精彩內(nèi)容

  • javascript有很多創(chuàng)建對(duì)象的模式,完成工作的方式也不只一種。你可以隨時(shí)定義自己的類型或自己的泛用對(duì)象。可以...
    WanLum閱讀 266評(píng)論 0 0
  • 盡管javascript里有大量內(nèi)建引用對(duì)象,很可能你還說會(huì)頻繁創(chuàng)建自己的對(duì)象。當(dāng)你在這么做的時(shí)候,記得javas...
    WanLum閱讀 535評(píng)論 1 3
  • 學(xué)習(xí)如何創(chuàng)建對(duì)象時(shí)理解面向?qū)ο蟮牡谝徊健5诙繒r(shí)理解繼承。在傳統(tǒng)面向?qū)ο蟮恼Z言中,類從其他類繼承屬性。然而在jav...
    WanLum閱讀 267評(píng)論 0 0
  • 我們已經(jīng)在第1章討論過,在javascript中,函數(shù)其實(shí)就是對(duì)象,使函數(shù)不同意其他對(duì)象的決定性特點(diǎn)是函數(shù)存在一個(gè)...
    WanLum閱讀 312評(píng)論 2 1
  • 大多數(shù)的開發(fā)者在使用Java或C#等基于類的語言的過程中學(xué)會(huì)了面向?qū)ο缶幊獭S捎贘avaScript沒有對(duì)類的正式...
    WanLum閱讀 595評(píng)論 0 4