分析javascript原型及原型鏈
我們創(chuàng)建的每個(gè)函數(shù)都有一個(gè) prototype (原型)屬性,這個(gè)屬性是一個(gè)指針,指向一個(gè)原型對(duì)象,而這個(gè)原型對(duì)象中擁有的屬性和方法可以被所以實(shí)例共享。
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ì)腳本則是完全不可見(jiàn)的。
不過(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é)上更好地封裝原型的功能,更常見(jiàn)的做法是用一個(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í)例中了。
- JS學(xué)習(xí)筆記之原型鏈和利用原型實(shí)現(xiàn)繼承詳解
- JavaScript中構(gòu)造函數(shù)與原型鏈之間的關(guān)系詳解
- 深入淺析js原型鏈和vue構(gòu)造函數(shù)
- JavaScript原型鏈與繼承操作實(shí)例總結(jié)
- JavaScript作用域、閉包、對(duì)象與原型鏈概念及用法實(shí)例總結(jié)
- [js高手之路]圖解javascript的原型(prototype)對(duì)象,原型鏈實(shí)例
- JavaScript使用原型和原型鏈實(shí)現(xiàn)對(duì)象繼承的方法詳解
- JavaScript對(duì)象原型鏈原理解析
相關(guān)文章
JS 實(shí)現(xiàn)列表與多選框選擇附預(yù)覽動(dòng)畫
本節(jié)為大家介紹的是用JS實(shí)現(xiàn)列表與多選框選擇,并附gif演示動(dòng)畫,這個(gè)例子很詳細(xì),大家可以看看2014-10-10webpack4.x開(kāi)發(fā)環(huán)境配置詳解
這篇文章主要介紹了webpack4.x開(kāi)發(fā)環(huán)境配置方法,結(jié)合實(shí)例形式詳細(xì)分析了webpack4.x的具體安裝、項(xiàng)目創(chuàng)建、打包操作等相關(guān)問(wèn)題與處理技巧,需要的朋友可以參考下2018-08-08用javascript實(shí)現(xiàn)自定義標(biāo)簽
用javascript實(shí)現(xiàn)自定義標(biāo)簽...2007-05-05chrome瀏覽器當(dāng)表單自動(dòng)填充時(shí)如何去除瀏覽器自動(dòng)添加的默認(rèn)樣式
很多朋友都遇到這個(gè)問(wèn)題:當(dāng)使用chrome瀏覽器表單自動(dòng)填充時(shí)都會(huì)自動(dòng)添加默認(rèn)的樣式,該如何去除默認(rèn)樣式呢?看看小編是怎么去除的,需要的朋友一起學(xué)習(xí)吧2015-10-10