我正在为request
模块构建一个复合体,但是我不确定在JS for Node中构建对象的最佳实践是什么。
选项1:
function RequestComposite(request) {
return {
get: function (url) { return request.get(url); }
}
}
var comp = RequestComposite(request);
选项2:
function RequestComposite(request) {
this.request = request;
}
RequestComposite.prototype.get = function (url) { return this.request.get(url); };
var comp = new RequestComposite(request);
选项3:
var RequestComposite = {
init: function (request) { this.request = request; },
get: function (url) { return request.get(url); }
}
var comp = Object.create(RequestComposite).init(request);
我试图找到自己的方式,但是我对如何使用对象更加困惑......
如果我想为浏览器使用对象,答案是否会有所不同?
感谢。
答案 0 :(得分:46)
最有效的方法如下:
仅在构造函数中设置属性。
在构造函数的.prototype
属性中设置方法。为什么?因为这可以防止每次创建对象时重写每个方法。这样,您可以为您创建的每个对象回收相同的原型。记忆力和时间效率。
不要对私有财产使用闭包。为什么?:它很慢,并阻止您在继承链中使用此对象(伪私有变量不属于对象,它们只是可访问)。请使用下划线表示它是不应从外部访问的私有属性。
使用new
代替Object.create
。它更快,最后Object.create在引擎盖下使用new
。
换句话说,就像这样:
var Person = function (name) {
this._name = name;
};
Person.prototype.sayHello = function () {
alert('My name is: ' + this._name);
};
var john = new Person('John');
john.sayHello();
一些额外信息:
Object.create vs new 。 Benchmark here。虽然问题是针对node.js,但我认为可以预期相同的行为。 (欢迎任何更正)
模仿私有媒体资源的封闭:您可以阅读in this question.。 private / closure属性不属于该对象的点是编程事实:它们可由对象方法访问,但不属于该对象。使用继承时,这是一个很大的混乱。此外,只有在构造函数中声明的方法才能访问闭包。原型中定义的方法没有。
在构造函数或原型属性中定义方法:阅读this question,并查看this benchmark
三年前我在这里提出的观点仍然是从表演的角度来看,但我对“推荐方式”的看法在一段时间内发生了一些变化。工厂功能通常是一个很好的选择,这将是OP的第一种方法。举个例子:
function Person(name) {
return {
sayHello: function () { alert('My name is: ' + name); }
};
}
然后就这样做:
var p = Person('John');
在这种情况下,您可以交换灵活性(没有new
耦合,易于与其他“混合”组合)和简单(没有this
混乱,简单的对象实例化)对于某些速度和内存。一般来说,它们完全有效。如果您遇到性能问题,并且这些是因为这种创建对象的方式,则还原为另一种方法。 Object.create
方法也很好,在某种程度上落在new
和工厂函数的中间(旁注:新的class
语法是new
+ {{1的语法糖}})
总结:我推荐的方法是从创建对象(工厂函数)的最简单最简单的方法开始,然后在遇到性能问题时(在大多数情况下永远不会这样做)落到其他方法上。
答案 1 :(得分:7)
在JS中有很多方法可以创建“Class”和“Object”。我更喜欢这种方式:
var MyObject =
function(args) {
// Private
var help = "/php/index.php?method=getHelp";
var schedule = "/php/index.php?method=getSchedules";
var ajax = function(url, callback, type) {
//....
}
// Public
this.property = 0;
this.getInfo = function() {
// ...
}
// Constructor
function(data) {
this.property = data;
}(args);
};
var o = new MyObject();
答案 2 :(得分:1)
注意:如果您更熟悉OOP语法,那么您也可以使用class
,它只是基于现有原型的方法的语法糖。
4种创建对象方式的性能比较 - 使用构造函数(Chrome 61 - https://jsperf.com/create-object-ways)
选项A:使用return
(最快3倍)
选项B:使用{key:value}
(1.5x)
选项C:使用prototype
(1x)< - Base
选项D:使用class
(1.02x)
选项A 接缝表现最佳。请注意,一些性能提升是因为它避免使用new
或object.create
。所以,为了获得公平的试验,这是另一个没有构造函数和属性的方法对象之间的测试。
创建仅限方法对象的4种方式之间的效果比较(Chrome 61 - https://jsperf.com/create-static-object-ways)
选项A:使用return
(3.2x)
选项B:使用{key:value}
(最快3.3倍)
选项C:使用prototype
(1.8x)
选项D:使用class
(1.9x)
选项B 表现优于选项A 。此外,由object.create
引起的瓶颈超过了new
。
最佳实践
选项A (使用return
)在这两种方案中效果最佳。如果你有很多方法和属性,这种方式可能会变得很乱。
我更喜欢划分构造函数&使用选项A 的单独对象中的属性和使用选项B 的其他对象中的方法。这种方法确实需要在参数中发送额外的instance
引用,但如果您有多个使用相同属性的对象,则可能非常有用。构造函数(也可以实现一些OOP继承)。
示例:强>
// Constructor & Properties Object (Using option A)
var UserData = function(request){
// Constructor
if ( request.name )
var name = request.name;
else
var name = 'Not Available';
if ( request.age )
var age = request.age;
else
var age = null;
// Return properties
return {
userName: name,
userAge: age
};
};
// Object methods (Using Option B)
var Adults = {
printName: function(instance){ // Read propery example
console.log( 'Mr. ' + instance.userName );
},
changeName: function(instance, newName){ // Write property example
instance.userName = newName;
},
foo: function(){
console.log( 'foo' );
}
};
// Object methods (Using Option B)
var Children = {
printName: function(instance){
console.log( 'Master ' + instance.userName );
},
bar: function(){
console.log( 'bar' );
}
}
// Initialize
var userData = UserData ( {name: 'Doe', age: 40} );
// Call methods
Adults.printName(userData); // Output 'Mr. Doe'
Children.printName(userData); // Output 'Master Doe'
Adults.foo(); // Output 'foo'
Children.bar(); // Output 'bar'
Adults.changeName(userData, 'John');
Adults.printName(userData); // Output 'Mr. John'