[英]Functions inside constructor vs prototype
我知道也有類似的問題,但是我想看看在新的Javascript引擎中進行優化后,這些答案是否仍然有效。
我認為,在構造函數內部定義函數的最大好處是,您可以輕松地不必知道'this'關鍵字的值:
var Person = function() {
var self = this;
self.firstName = null;
self.lastName = null;
self.fullName = function() {
return self.firstName + self.lastName;
};
};
淘汰管理“ this”建議使用此方法。 這是一個很大的優勢,特別是當許多開發人員正在修改代碼時,因為它很容易理解和使用。
另一種方法是使用對象原型:
var Person = function() {
this.firstName = null;
this.lastName = null;
};
Person.prototype.fullName = function() {
return this.firstName + this.lastName;
};
在這種情況下,由於功能對象將被創建一次,因此具有性能優勢。 但是我遇到的主要問題是處理'this'關鍵字可能很復雜。 上面的例子非常簡單,但是如果您有事件處理程序,forEach調用,jQuery each()調用,從不同上下文中調用方法等,那么很容易就不好用了。
當然,如果您了解“這”是如何工作的並且知道如何調用方法,那么您應該不會有太多問題。 但是,以我的經驗,這需要時間,而且容易出錯,尤其是當許多開發人員編寫代碼時。
我知道像V8這樣的新JS引擎正在通過創建隱藏類對在構造函數中聲明函數的情況進行優化: V8引擎如何工作? 。
所以我的問題是,考慮到新JS引擎完成的這些優化以及必須處理'this'關鍵字的復雜性,使用基於原型的方法是否仍然有意義? 通過使用將所有內容放入構造函數的方法,我會失去什么?
更新1:
我只是在Chrome(版本42)上做了一個微基准測試。 我用構造函數內部的函數和原型中的函數創建1M對象。 這是一個非常簡單的對象,具有兩個變量和三個函數,結果如下所示:
Functions inside constructor: 1.91 seconds
Functions in prototype: 1.10 seconds
聽起來,即使在V8中進行了這些優化,它仍然快了73%。 但這是一個微觀基准。 不確定在現實應用中這是否會有很大的不同。
更新2:
我還研究了內存消耗,並且也存在很大差異。 對於構造函數內部的函數:
Shallow size: 64,000,120
Retained size: 336,001,128
對於原型功能:
Shallow size: 40,000,000
Retained size: 40,000,000
使用隱藏類進行的優化不是很好,否則我會丟失一些東西。 我使用的是V8建議的單態代碼(不帶args的構造函數),但不確定我做錯了什么。
更新3:
這是我所做的測試的鏈接,以防有人指出那里的錯誤: http : //jsperf.com/dg-constructor-vs-prototype
我執行快速測試。 如果在構造函數中聲明函數,則即使經過優化,兩個對象實例也具有不同的函數實例。 但是,使用原型時,只有一個功能實例可以解釋性能差異。
var Person = function () { var self = this; self.firstName = null; self.lastName = null; self.fullName = function () { return self.firstName + self.lastName; }; }; Person.prototype.fullName2 = function () { return this.firstName + this.lastName; }; var a = new Person(); var b = new Person(); console.log(a.fullName == b.fullName); // returns false console.log(a.fullName2 == b.fullName2); // returns true
我一直在使用一種略有不同的方法,IMO具有清晰性的優點,並且避免了每次調用構造函數時都重新創建成員函數:
例如:
// Constructor for MyClass
function MyClass(a, b){
// set properties of the instance from constructor arguments
this.a = a;
this.b = b;
// assign the report function as a member of this instance
this.report = Report;
}
// Report function is defined at the module level,
// but used by assigning it to an instance variable
// within the constructor.
function Report(){
console.log( "a=" + this.a, "b=" + this.b);
}
成員函數只有一個實例,該成員函數由同一類的所有實例共享(就像將函數分配給class.prototype.function
時的情況一樣),因此該方法非常有效,並且具有其他優點,海事組織:
用法:
// Create instances of my class
var inst1 = new MyClass( "as", "df");
var inst2 = new MyClass( "gh", "jk");
// Report the instances
inst1.report();
inst2.report();
// Class and method declarations follow below here...
這種方法有什么缺點嗎?
就像@Ersin Basaran提到的那樣,在構造函數內部創建的函數對於每個對象實例都是唯一的,與使用原型創建該函數時,它對於每個對象實例都具有相同的功能不同。
但是,在ES6(ECMAScript2015)中引入類之后,如果使用類來創建方法而不是使用構造函數,並且在構造函數外部(但在類內部)創建此方法,則每個對象都相同實例,就像使用原型時一樣。
這是創建fullName()
方法的示例:
class Person {
constructor () {
var self = this;
self.firstName = null;
self.lastName = null;
}
fullName () {
return self.firstName + self.lastName;
}
}
Person.prototype.fullName2 = function () {
return this.firstName + this.lastName;
};
var a = new Person();
var b = new Person();
console.log(a.fullName == b.fullName); // returns true
console.log(a.fullName2 == b.fullName2); // returns true
我希望這有幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.