JavaScript 是面向?qū)ο蟮哪_本語言,長期以來用作 Web 瀏覽器應(yīng)用程序的客戶端腳本接口。JavaScript 讓 Web 開發(fā)人員能以編程方式處理 Web 頁面上的對象,并提供了一個能夠動態(tài)操作這些對象的平臺。在最初引入 JavaScript 時,通常只用于提供 Web 頁面上的一些不重要的特性,如時鐘功能和瀏覽器狀態(tài)欄中的滾動文本等。
另一個常見的特性是 “rolloverlink”,就是當(dāng)用戶將鼠標(biāo)移到圖片或文本鏈接上時,圖片或文本鏈接的顏色會改變。然而,近年來,隨著AsynchronousJavaScript and XML (Ajax) 概念將基于 Web 的編程的交互性提升到一個新高度,JavaScript 也變得越來越重要。在出現(xiàn) Ajax 之前,所有服務(wù)器端處理或數(shù)據(jù)庫訪問都需要 “刷新” 整個頁面或通過瀏覽器呈現(xiàn)一個新頁面。這不僅減慢了速度并使用戶感到沮喪,而且還浪費帶寬和資源。
JavaScript原型
原型是JavaScript中一個比較難理解的概念,原型相關(guān)的屬性也比較多,對象有“[[prototype]]”屬性,函數(shù)對象有“prototype”屬性,原型對象有“constructor”屬性。
為了弄清原型,以及原型相關(guān)的這些屬性關(guān)系,就有了這篇文章。
相信通過這篇文章一定能夠清楚的認(rèn)識到原型,現(xiàn)在就開始原型之旅吧。
認(rèn)識原型
開始原型的介紹之前,首先來認(rèn)識一下什么是原型?
在JavaScript中,原型也是一個對象,通過原型可以實現(xiàn)對象的屬性繼承,JavaScript的對象中都包含了一個“ [[Prototype]]”內(nèi)部屬性,這個屬性所對應(yīng)的就是該對象的原型。
“[[Prototype]]”作為對象的內(nèi)部屬性,是不能被直接訪問的。所以為了方便查看一個對象的原型,F(xiàn)irefox和Chrome中提供了“__proto__”這個非標(biāo)準(zhǔn)(不是所有瀏覽器都支持)的訪問器(ECMA引入了標(biāo)準(zhǔn)對象原型訪問器“Object.getPrototype(object)”)。
實例分析
下面通過一個例子來看看原型相關(guān)概念:
this.name = name;
this.age = age;
this.getInfo = function(){
console.log(this.name + “ is ” + this.age + “ years old”);
};
}
var will = new Person(“Will”, 28);
在上面的代碼中,通過了Person這個構(gòu)造函數(shù)創(chuàng)建了一個will對象。下面就通過will這個對象一步步展開了解原型。
Step 1: 查看對象will的原型
通過下面代碼,可以查看對象will的原型:
console.log(will.__proto__);
console.log(will.constructor);
結(jié)果分析:
“Person {}”對象就是對象will的原型,通過Chrome展開可以看到,“Person {}”作為一個原型對象,也有“__proto__”屬性(對應(yīng)原型的原型)。
在這段代碼中,還用到了“constructor”屬性。在JavaScript的原型對象中,還包含一個“constructor”屬性,這個屬性對應(yīng)創(chuàng)建所有指向該原型的實例的構(gòu)造函數(shù)。
通過“constructor”這個屬性,我們可以來判斷一個對象是不是數(shù)組類型
function isArray(myArray) {
return myArray.constructor.toString().indexOf(“Array”) 》 -1;
}
在這里,will對象本身并沒有“constructor”這個屬性,但是通過原型鏈查找,找到了will原型(will.__proto__)的“constructor”屬性,并得到了Person函數(shù)。
Step 2: 查看對象will的原型(will.__proto__)的原型
既然will的原型“Person {}”也是一個對象,那么我們就同樣可以來查看“will的原型(will.__proto__)的原型”。
運行下面的代碼:
console.log(will.__proto__ === Person.prototype);
console.log(Person.prototype.__proto__);
console.log(Person.prototype.constructor);
console.log(Person.prototype.constructor === Person);
結(jié)果分析:
首先看 “will.__proto__ === Person.prototype”,在JavaScript中,每個函數(shù)都有一個prototype屬性,當(dāng)一個函數(shù)被用作構(gòu)造函數(shù)來創(chuàng)建實例時,該函數(shù)的prototype屬性值將被作為原型賦值給所有對象實例(也就是設(shè)置實例的__proto__屬性),也就是說,所有實例的原型引用的是函數(shù)的prototype屬性。了解了構(gòu)造函數(shù)的prototype屬性之后,一定就明白為什么第一句結(jié)果為true了。
prototype屬性是函數(shù)對象特有的,如果不是函數(shù)對象,將不會有這樣一個屬性。
當(dāng)通過“Person.prototype.__proto__”語句獲取will對象原型的原型時候,將得到“Object {}”對象,后面將會看到所有對象的原型都將追溯到“Object {}”對象。
對于原型對象“Person.prototype”的“constructor”,根據(jù)前面的介紹,將對應(yīng)Person函數(shù)本身。
通過上面可以看到,“Person.prototype”對象和Person函數(shù)對象通過“constructor”和“prototype”屬性實現(xiàn)了相互引用(后面會有圖展示這個相互引用的關(guān)系)。
Step 3: 查看對象Object的原型
通過前一部分可以看到,will的原型的原型是“Object {}”對象。實際上在JavaScript中,所有對象的原型都將追溯到“Object {}”對象。
下面通過一段代碼看看“Object {}”對象:
console.log(Person.prototype.__proto__ === Object.prototype);
console.log(typeof Object);
console.log(Object);
console.log(Object.prototype);
console.log(Object.prototype.__proto__);
console.log(Object.prototype.constructor);
通過下面的代碼可以看到:
Object對象本身是一個函數(shù)對象。
既然是Object函數(shù),就肯定會有prototype屬性,所以可以看到“Object.prototype”的值就是“Object {}”這個原型對象。
反過來,當(dāng)訪問“Object.prototype”對象的“constructor”這個屬性的時候,就得到了Obejct函數(shù)。
另外,當(dāng)通過“Object.prototype.__proto__”獲取Object原型的原型的時候,將會得到“null”,也就是說“Object {}”原型對象就是原型鏈的終點了。
Step 4: 查看對象Function的原型
在上面的例子中,Person是一個構(gòu)造函數(shù),在JavaScript中函數(shù)也是對象,所以,我們也可以通過“__proto__”屬性來查找Person函數(shù)對象的原型。
console.log(Person.__proto__ === Function.prototype);
console.log(Person.constructor === Function)
console.log(typeof Function);
console.log(Function);
console.log(Function.prototype);
console.log(Function.prototype.__proto__);
console.log(Function.prototype.constructor);
結(jié)果分析 :
在JavaScript中有個Function對象(類似Object),這個對象本身是個函數(shù);所有的函數(shù)(包括Function,Object)的原型(__proto__)都是“Function.prototype”。
Function對象作為一個函數(shù),就會有prototype屬性,該屬性將對應(yīng)“function () {}”對象。
Function對象作為一個對象,就有“__proto__”屬性,該屬性對應(yīng)“Function.prototype”,也就是說,“Function.__proto__ === Function.prototype”
對于Function的原型對象“Function.prototype”,該原型對象的“__proto__”屬性將對應(yīng)“Object {}”
對比prototype和__proto__
對于“prototype”和“__proto__”這兩個屬性有的時候可能會弄混,“Person.prototype”和“Person.__proto__”是完全不同的。
在這里對“prototype”和“__proto__”進(jìn)行簡單的介紹:
對于所有的對象,都有__proto__屬性,這個屬性對應(yīng)該對象的原型
對于函數(shù)對象,除了__proto__屬性之外,還有prototype屬性,當(dāng)一個函數(shù)被用作構(gòu)造函數(shù)來創(chuàng)建實例時,該函數(shù)的prototype屬性值將被作為原型賦值給所有對象實例(也就是設(shè)置實例的__proto__屬性)
評論
查看更多