在NodeJS中创建对象的推荐方法是什么?

时间:2013-12-16 08:36:09

标签: javascript performance node.js javascript-objects

我正在为request模块构建一个复合体,但是我不确定在JS for Node中构建对象的最佳实践是什么。

选项1:

function RequestComposite(request) {
  return {
    get: function (url) { return request.get(url); }
  }
}
var comp = RequestComposite(request);
  • 注意:我知道我应该以异步的方式打电话给CB,但为了便于解释,我把它归还......

选项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);

我试图找到自己的方式,但是我对如何使用对象更加困惑......

如果我想为浏览器使用对象,答案是否会有所不同?

感谢。

3 个答案:

答案 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

编辑2016年4月15日

三年前我在这里提出的观点仍然是从表演的角度来看,但我对“推荐方式”的看法在一段时间内发生了一些变化。工厂功能通常是一个很好的选择,这将是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 接缝表现最佳。请注意,一些性能提升是因为它避免使用newobject.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'