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

tvz2xvvm  于 2023-05-27  发布在  Java
关注(0)|答案(3)|浏览(107)

我正在为request模块构建一个组合,但是我不确定在JS中为Node构建对象的最佳实践是什么。
选择1:

function RequestComposite(request) {
  return {
    get: function (url) { return request.get(url); }
  }
}
var comp = RequestComposite(request);
  • 注意:我知道我应该以异步方式调用CB,但为了便于解释,我返回它...

备选方案二:

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

我试着找到我的路,然而我对如何使用对象感到更加困惑...
如果我想在浏览器中使用对象,答案会有所不同吗?
谢谢。

dz6r00yl

dz6r00yl1#

最有效的方法如下:

  • 将所有基本的初始化放在构造函数中(例如验证构造器参数、设置属性等)。
  • 在构造函数的.prototype属性中设置方法。为什么?因为这可以防止每次创建对象时重写每个方法。通过这种方式,您可以为创建的每个对象回收相同的原型。高效的内存和节省编码时间。
  • 不要对私有属性使用闭包。为什么?它很慢,并且阻止你在继承链中使用这个对象(伪私有变量不属于对象,它们只是可访问的)。相反,在声明对象属性时使用下划线是常见的做法,以指示它是不应该从外部访问的 _private 属性。
  • 使用new代替Object.create。如果你习惯了其他的OOP语言,它会更容易记住;最后new在引擎盖下使用Object.create

换句话说,类似这样的东西:

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 newBenchmark here。虽然这个问题是针对Node.js的,但我认为同样的行为是可以预期的。(欢迎更正)
*模拟私有属性的闭包:你可以在这个问题中读到。private/closure属性不属于对象是一个编程事实:它们可由对象方法访问,但不属于对象。当使用继承时,这是一个很大的混乱。此外,只有在构造函数中声明的方法才能访问闭包。在原型中定义的方法不需要。
*在构造函数或prototype属性中定义方法:读取this question,并查看this benchmark

编辑15/04/2016

三年前我在这里提出的观点从性能的Angular 来看仍然是正确的,但我对什么是“推荐方式”的看法在此期间发生了一些变化。工厂函数通常是一个很好的选择,这将是OP的第一种方法。举个例子:

function Person(name) {
    return {
        sayHello: function () { alert('My name is: ' + name); }
    };
}

然后就这样做:

var p = Person('John');

在这种情况下,您可以牺牲灵活性(没有new耦合,易于与其他“mix-in”组合)和简单性(没有this混乱,易于对象示例化)来换取一定的速度和内存。一般来说,它们是完全有效的。如果您有性能问题,并且这些问题是由于这种创建对象的方式造成的,请恢复到另一种方法。Object.create方法也很好,在某种程度上介于new和工厂函数之间(旁注:新的class语法是new + prototype的语法糖)
总结:我推荐的方法是从最简单和最容易的创建对象的方法(工厂函数)开始,然后在遇到性能问题时(在大多数情况下,这是永远不会发生的)转向其他方法。

2023年编辑

自从我写了这个答案后,下了很多雨,它不再相关了。只需使用class并担心真实的的问题。

8fsztsew

8fsztsew2#

在JS中有很多方法可以创建“类”和“对象”。我更喜欢这样:

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();
w51jfk4q

w51jfk4q3#

注意:如果你更熟悉OOP语法,你也可以使用class,它只是在现有的基于原型的方式上的语法糖。

4种创建对象方式性能对比-带构造函数(Chrome 61 -https://jsperf.com/create-object-ways

选项A:使用return(最快3x)
选项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.3x)
选项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'

相关问题