【问题标题】:Is there a performance penalty associated with methods created in the constructor versus methods created on the prototype?在构造函数中创建的方法与在原型上创建的方法是否存在性能损失?
【发布时间】:2012-08-16 07:45:18
【问题描述】:

我可以通过两种方式声明对象的方法:

第一种方式使用self=this成语。

function SelfIdiomExample(name){
    var self = this;

    self.sayHello = function (name){
         alert("Hello, "+name);
    }
}

当您需要在方法中引用对象时(例如,如果该方法将作为回调传递),这很有用。另一种方法是通过修改原型来实现:

function PrototypeModExample(){
   //pass
}

PrototypeModExample.prototype.sayHello = function(name){
   alert("Hello, "+name);
}

两者的结果相同:

var sieg = new SelfIdiomExample();
var pmeg = new PrototypeModExample();

sieg.sayHello("Barnaby");
pmeg.sayHello("Josephine");

虽然我了解 self=this 成语的用例,但我想知道:

使用在构造函数中创建的方法与在原型中创建的方法相比是否存在性能损失?

【问题讨论】:

  • 它只是对变量的赋值引用。 jsperf.com - 用它来衡量“差异” PS:在第一种情况下,你实际上根本不需要 self
  • 您始终可以使用this 在原型方法中获取对对象的引用。此外,您在第一个 sn-p 中缺少 var
  • 请不要忘记用var声明你的局部变量!!!
  • @zerkms 这是一个非常有用的工具。谢谢!它回答了我的问题。不过,我想知道更多关于下面到底发生了什么。

标签: javascript performance idioms


【解决方案1】:

这里是:

var self = this;

根本就没有性能影响。它非常快,因为它只是访问一个局部变量。即使是嵌套函数,这在 JavaScript 中也是一个非常快速的操作。

但是,在构造函数中创建的方法与在原型中创建的方法存在巨大的性能差异。

在这个例子中:

var PrototypeModExample = function(){
  this.name = "Joe";
};

PrototypeModExample.prototype.sayHello = function(){
   alert("Hello, " + this.name);
};

var a = new PrototypeModExample();
var b = new PrototypeModExample();
console.log(a.sayHello === b.sayHello); // true

构造函数的每个实例都可以访问相同的函数对象。这可以通过使用=== 运算符比较两个实例上的函数对象来证明。只有当它们是相同的对象时,它才会返回true。所以在全球范围内,我们现在有 2 个实例,但它们共享一个函数对象,用于实现 sayHello 方法。这意味着当您想要创建一个新实例时,该函数已经设置并创建。

换句话说,对于所有实例,obj.sayHello 指向同一个函数对象,该对象是在任何实例完全存在之前创建的。


但另一方面:

function SelfIdiomExample(name){
    var self = this;
    this.name = "Joe";

    this.sayHello = function(){
         alert("Hello, " + self.name);
    }
}

var a = new SelfIdiomExample();
var b = new SelfIdiomExample();
console.log(a.sayHello === b.sayHello); // false

工作方式不同。现在我们看到=== 比较是错误的。这是因为为每个实例创建了一个新函数对象。创建此函数需要时间(需要对其进行解析)和内存(需要存储该函数的唯一版本)。因此,当创建大量此类实例时,此方法会更慢并消耗更多内存。

换句话说,对于所有实例,obj.sayHello 指向一个唯一的函数对象,该对象是在创建实例本身时创建的。


因此,通常首选原型方法。特别是在可能存在大量实例的情况下,因为每个实例都可以共享其方法的函数对象。

【讨论】:

  • 谢谢亚历克斯,回想起来,我应该在提问之前测试一下!这就是我一直在寻找的答案。
【解决方案2】:

与往常一样,您必须进行测试才能回答这样的问题:http://jsperf.com/this-vs-self/2

当您进行测试时,似乎没有太大差异(在某些情况下,不到几个百分点,对self 略有优势)。 self 的一个优点是可以通过将其更改为单字符变量名来更好地最小化它,这显然是某些框架使用它的原因。

在您的示例中,我想说self 的使用是多余的,没有必要。通常人们只在使用闭包时才使用self,并且某些回调中this 的值不再是您想要的那样:

counter.prototype.incrementWithDelay(delay) {
    var self = this;
    setTimeout(function() {
        self.counter++;
    }, delay);
}

但是,如果你只是一个普通的方法,没有理由使用self

counter.prototype.set(val) {
    this.counter = val;
}

【讨论】:

    猜你喜欢
    • 2020-11-28
    • 1970-01-01
    • 1970-01-01
    • 2016-09-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    • 1970-01-01
    相关资源
    最近更新 更多