在學習JavaScript的過程中,原型是如何也繞不過去的一個知識點。雖然在現在ES6已經非常普及的現在,許多js的程序員都已經不再用原型的知識點來編寫代碼了,但是充分的理解原型也是很有必要的,尤其是在閱讀他人優秀的js代碼時,理解原型能幫助我們更好的理解早期代碼。而原型包括三個訪問器,這三個訪問器有時功能重疊,所以準確的理解并區分他們還是很有必要的。
這三個訪問器就是prototype
、getPrototypeOf
和__proto__
,從名字上可見這三個訪問器都是對prototype這個單詞做了一些變化,生成這樣的屬性方法名。為了測試這三個方法的輸出,我們先來模擬創建一個存儲用戶數據User的類。
function User(name, passwordHash) {
this.name = name;
this.passwordHash = passwordHash;
}
User.prototype.toString = function() {
return '[User ' + this.name + ']';
}
User.prototype.checkPassword = function(password) {
return hash(password) === this.passwordHash;
}
這里我們創建的這個User類的構造函數,接收兩個參數,一個是用戶名name,一個是密碼的hash值,并且類中有兩個方法toString
以及checkPassword
用來輸出用戶信息和檢查密碼。
如果這個時候我們打印這三個原型方法的日志會得到一樣的結果
var u = new User('Lix', '123456');
console.log(Object.getPrototypeOf(u)); // User { toString: [Function], checkPassword: [Function] }
console.log(u.__proto__); // User { toString: [Function], checkPassword: [Function] }
console.log(User.prototype); // User { toString: [Function], checkPassword: [Function] }
既然他們的輸出都一樣,那么他們是否作用一樣呢,我們可以來比較測試一下。
Object.getPrototypeOf(u) === User.prototype; // true
u.__proto__ === User.prototype; // true
既然這兩個方法都跟我們User對象的原型相等,那么這三個屬性的區別究竟是什么呢?別急,接下來就把結論告訴大家。
-
C.prototype
用于建立由new C()
創建的對象的原型。 -
Object.getPrototype(obj)
是ES5中用來獲取obj對象的原型對象的標準方法。 -
obj.__proto__
是獲取obj對象的原型對象的非標準方法。
所以一般我們是不會直接訪問C.prototype
去獲取原型對象的,在ES5的環境中,我們使用Object.getPrototype(obj)
來獲取原型對象,而在不支持ES5的環境中,我們可以考慮用__proto__
這樣的非標準方法來當做權宜之計,希望各位不明白的同學能牢記這些區別。