我們創(chuàng)建的每個(gè)函數(shù)都有一個(gè) prototype (原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)原型對(duì)象,而這個(gè)原型對(duì)象中擁有的屬性和方法可以被所以實(shí)例共享。
噶爾網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、自適應(yīng)網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)公司2013年成立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
function Person(){ } Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true
一、理解原型對(duì)象
無(wú)論什么時(shí)候,只要?jiǎng)?chuàng)建了一個(gè)新函數(shù),就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè) prototype屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。
在默認(rèn)情況下,所有原型對(duì)象都會(huì)自動(dòng)獲得一個(gè) constructor(構(gòu)造函數(shù))屬性,這個(gè)屬性包含一個(gè)指向 prototype 屬性所在函數(shù)的指針。
當(dāng)調(diào)用構(gòu)造函數(shù)創(chuàng)建一個(gè)新實(shí)例后,該實(shí)例的內(nèi)部將包含一個(gè)指針(內(nèi)部屬性),指向構(gòu)造函數(shù)的原型對(duì)象。ECMA-262 第 5 版中管這個(gè)指針叫 [[Prototype]] 。
雖然在腳本中沒(méi)有標(biāo)準(zhǔn)的方式訪問(wèn) [[Prototype]] ,但 Firefox、Safari 和 Chrome 在每個(gè)對(duì)象上都支持一個(gè)屬性__proto__ ;而在其他實(shí)現(xiàn)中,這個(gè)屬性對(duì)腳本則是完全不可見的。
不過(guò),要明確的真正重要的一點(diǎn)就是,這個(gè)連接存在于實(shí)例與構(gòu)造函數(shù)的原型對(duì)象之間,而不是存在于實(shí)例與構(gòu)造函數(shù)之間。
以前面使用 Person 構(gòu)造函數(shù)和 Person.prototype 創(chuàng)建實(shí)例的代碼為例,圖 6-1 展示了各個(gè)對(duì)象之間的關(guān)系。
在此, Person.prototype 指向了原型對(duì)象,而 Person.prototype.constructor 又指回了 Person 。
person1 和 person2 都包含一個(gè)內(nèi)部屬性,該屬性僅僅指向了 Person.prototype ;換句話說(shuō),它們與構(gòu)造函數(shù)沒(méi)有直接的關(guān)系。
可以調(diào)用 person1.sayName() 。這是通過(guò)查找對(duì)象屬性的過(guò)程來(lái)實(shí)現(xiàn)的。(會(huì)先在實(shí)例上搜索,如果搜索不到就會(huì)繼續(xù)搜索原型。)
用isPrototypeOf()方法判斷實(shí)例與原型對(duì)象之間的關(guān)系
alert(Person.prototype.isPrototypeOf(person1)); //true alert(Person.prototype.isPrototypeOf(person2)); //true
用Object.getPrototypeOf() 方法返回實(shí)例的原型對(duì)象
alert(Object.getPrototypeOf(person1) == Person.prototype); //true
使用 hasOwnProperty() 方法可以檢測(cè)一個(gè)屬性是存在于實(shí)例中,還是存在于原型中。
alert(person1.hasOwnProperty("name")); //false 來(lái)著原型
person1.name = "Greg";
alert(person1.name); //"Greg"——來(lái)自實(shí)例
alert(person1.hasOwnProperty("name")); //true
二、更簡(jiǎn)單的原型語(yǔ)法
前面例子中每添加一個(gè)屬性和方法就要敲一遍 Person.prototype 。為減少不必要的輸入,也為了從視覺(jué)上更好地封裝原型的功能,更常見的做法是用一個(gè)包含所有屬性和方法的對(duì)象字面量來(lái)重寫整個(gè)原型對(duì)象。
function Person(){ } Person.prototype = { name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } };
在上面的代碼中,我們將 Person.prototype 設(shè)置為等于一個(gè)以對(duì)象字面量形式創(chuàng)建的新對(duì)象。最終結(jié)果相同,但有一個(gè)例外: constructor 屬性不再指向 Person 了。
前面曾經(jīng)介紹過(guò),每創(chuàng)建一個(gè)函數(shù),就會(huì)同時(shí)創(chuàng)建它的 prototype 對(duì)象,這個(gè)對(duì)象也會(huì)自動(dòng)獲得 constructor 屬性。
var friend = new Person(); alert(friend instanceof Object); //true alert(friend instanceof Person); //true alert(friend.constructor == Person); //false alert(friend.constructor == Object); //true
在此,用 instanceof 操作符測(cè)試 Object 和 Person 仍然返回 true ,但 constructor 屬性則等于 Object 而不等于 Person 了。
如果 constructor 的值真的很重要,可以像下面這樣特意將它設(shè)置回適當(dāng)?shù)闹怠?/p>
function Person(){ } Person.prototype = { constructor : Person, name : "Nicholas", age : 29, job: "Software Engineer", sayName : function () { alert(this.name); } };
三、原生對(duì)象的原型
所有原生引用類型( Object 、 Array 、 String ,等等)都在其構(gòu)造函數(shù)的原型上定義了方法。
例如,在 Array.prototype 中可以找到 sort() 方法,而在 String.prototype 中可以找到substring() 方法。盡管可以這樣做,但不推薦修改原生對(duì)象的原型。
四、原型對(duì)象的問(wèn)題
原型模式的最大問(wèn)題是由其共享的本性所導(dǎo)致的。 修改其中的一個(gè),另一個(gè)也會(huì)受影響。
function Person(){ } Person.prototype = { constructor: Person, name : "Nicholas", age : 29, job : "Software Engineer", friends : ["Shelby", "Court"], sayName : function () { alert(this.name); } }; var person1 = new Person(); var person2 = new Person(); person1.friends.push("Van"); alert(person1.friends); //"Shelby,Court,Van" alert(person2.friends); //"Shelby,Court,Van" alert(person1.friends === person2.friends); //true
五、原型鏈
其基本思想是利用原型讓一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法。然后層層遞進(jìn),就構(gòu)成了實(shí)例與原型的鏈條,這就是所謂原型鏈的基本概念。
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //繼承了 SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true
一張圖說(shuō)明:
property 則位于 SubType.prototype 中。這是因?yàn)?property 是一個(gè)實(shí)例屬性,而 getSuperValue() 則是一個(gè)原型方法。既然 SubType.prototype 現(xiàn)在是 SuperType的實(shí)例,那么 property 當(dāng)然就位于該實(shí)例中了。