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

时间:2012-08-20 23:57:06

标签: javascript performance idioms

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

第一种方式使用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成语的用例,但我想知道:

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

2 个答案:

答案 0 :(得分:2)

这就好了:

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,指向在创建实例本身时创建的唯一函数对象。


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

答案 1 :(得分:1)

与往常一样,您必须进行测试才能回答以下问题: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;
}