原文地址:http://dailyjs.com/2012/05/20/js101-prototype/
在花費了很多年研究面向?qū)ο缶幊讨螅朐趈avascript使用是令人失望的初橘。主要是從根源上缺少一個class
這樣的關(guān)鍵詞迹恐。然而契耿,javascript的設(shè)計不會成為阻礙 -- 精通它基于原型的繼承椒惨,將會加深你對該語言的理解碌奉。
首先我們需要弄清楚面向?qū)ο笈c面向類編程的區(qū)別翁都。Javascript提供了我們需要的工具來完成大多數(shù)語言的類可以做的事情 -- 我們只需要學(xué)習(xí)如何正確使用它碍论。
我們簡單的看一下prototype
屬性,看它如何深化我們對javascript的了解柄慰。
prototype
屬性(The prototype Property)
prototype
屬性是一個內(nèi)部屬性鳍悠,它被用于實現(xiàn)繼承税娜。我們這里的“繼承”是一種特定的繼承形式。因為狀態(tài)和方法都由對象承載藏研,所以我們可以說結(jié)構(gòu)敬矩、行為和狀態(tài)都是繼承的。這與基于類的語言形成對比蠢挡,其狀態(tài)由實例承載弧岳,而方法由類承載。
構(gòu)造函數(shù)就是一個具有屬性的方法业踏,該屬性被稱作prototype
:
function Animal() {
}
console.log(Animal.protype);
{}
標(biāo)識Animal
具有一個prototype
屬性缩筛,但是沒有用戶定義它。我們可以隨意添加值和方法:
function Animal() {
}
Animal.prototype.type = 'Unknown';
Animal.prototype.weight = 0;
Animal.prototype.weightUnits = 'kg';
Animal.prototype.toString = function() {
return this.type + ', ' + this.weight + this.weightUnits;
};
var molly = new Animal();
molly.type = 'Dog';
molly.weight = 28;
console.log(molly.toString()); // Dog, 28kg
這將會輸出"Dog, 28kg"堡称。我們可以使用對象字面量將這些賦值分組:
function Animal() {
}
Animal.prototype = {
type: 'Unknown',
weight: 0,
weightUnits: 'kg',
toString: function() {
return this.type + ', ' + this.weight + this.weightUnits;
}
};
這樣就和你熟悉的類的方式差異不是很大瞎抛。
動態(tài)原型(Dynamic Prototypes)
通過指定值可以給對象動態(tài)的添加屬性。
var molly = new Animal()
, harley = new Animal();
molly.type = 'Dog';
molly.weight = 28;
harley.type = 'Dog';
harley.weight = 38;
harley.name = 'Harley';
console.log(molly);
console.log(harley);
// { type: 'Dog', weight: 28 }
// { type: 'Dog', weight: 38, name: 'Harley' }
在這里添加name
屬性只影響了實例却紧。然而桐臊,構(gòu)造函數(shù)的屬性可以被改變,并且將影響用這個原型創(chuàng)建的對象晓殊。
Animal.prototype.weightUnits = 'oz';
console.log(molly.toString())
// Now displays 'Dog, 28oz'
這就是為什么人們只會擴展自己的庫而不去改變內(nèi)置原型断凶,或者說只有這么做才是安全的。我們完全有可能改變對象巫俺,例如使用String
的內(nèi)置方法做一些不安全的事情:
String.prototype.match = function() {
return true;
};
console.log('alex'.match(/1234/));
輸出為true
,所以現(xiàn)在我成功的破壞了很多程序都在依賴的基礎(chǔ)方法认烁。
改變內(nèi)置原型也不一定全部是壞的;我們使用它有用的東西介汹,如修補支持更舊版本的ECMAScript
在舊版的瀏覽器却嗡。
如果我們替換prototype
屬性會發(fā)生什么?
var molly = new Animal()
, harley;
molly.type = 'Dog';
molly.weight = 28;
Animal.prototype = {
toString: function() {
return '...';
}
};
harley = new Animal;
harley.type = 'Dog';
harley.weight = 38;
console.log(molly.toString());
console.log(harley.toString());
// Dog, 28kg
// ...
盡管事實上改變原型會影響所有實例嘹承,但是完全替換構(gòu)造函數(shù)的原型不會影響舊實例窗价。為什么?實例具有對原型的引用叹卷,而不是離散拷貝撼港。想象它就是這樣:使用new
關(guān)鍵字創(chuàng)建的每個實例都鏈接到原始原型。