在构造函数中定义函数会比将其附加到原型消耗更多的内存

Will defining functions within the constructor consume more memory than attaching it to prototype?

本文关键字:原型 内存 定义 构造函数 函数      更新时间:2023-09-26

这可能是最安全的方法(情况A):

var myClass = function() { };
myClass.prototype = {
    doSomething : function() { alert('Something'); }
};

这是替代方案(案例 B):

var myClass = function() {
    this.doSomething = function() { alert('Something'); };
};

我的印象是,通过按照案例 B 所示执行此操作,doSomething 将成为一个成员,并且该函数将为我实例化的每个 myClass 对象定义一次,以便它将在内存中存在 100 次 100 个实例,而在案例 A 中,函数将只存在于内存中的一个位置,不同的实例将仅引用原型。

我理解正确吗?

作为一个额外的问题:当像案例B一样这样做时,chrome开发人员给了我doSomething的智能感知,但我必须展开__proto__才能看到它。为什么它没有显示在对象本身上?也就是说,为什么原型成员不显示在对象上,而是卡在__proto__上?我宁愿__proto__堆栈被展平并直接显示在对象上。有没有另一个案例可以允许这种情况发生?

首先,在 B 的情况下,您只是创建一个全局函数,而不是将其附加到实例。你的意思是:

this.doSomething = function() { }

其次,第一个会更快。虽然我现在找不到链接,但 jQuery honcho John Resig 对此发表了一篇详细的博客文章,展示了方法的原型继承与实例上声明的方法的速度测试。继承速度明显更快。

就精神而言,我一直非常喜欢继承。这是可重用的跨实例功能的地方。将其添加到每个实例的唯一好处是允许您在构造函数中的单个方便闭包中声明方法,但仅此而已。

如果这是你喜欢模式 B 的原因,那么在 a) 继承方法的同时就可以这样做;b) 不要在每次实例时都重新声明它们。

function SomeClass() {
    if (!SomeClass.prototype.someMethod) {
        SomeClass.prototype.someMethod = function() {}
    }
}

不过,这会稍微减慢初始实例化的速度,因为它负责设置原型 - 而不是实例化过程的工作。

两种情况之间还需要注意编程差异:

 function SomeClass(name) {}
 SomeClass.prototype.someMethod = function() {};
 var instance = new SomeClass();
 console.log(!!instance.someMethod); //true
 console.log(instance.hasOwnProperty('someMethod')); //false

最后一行为 false,因为该方法是继承的,而不是由实例拥有的。对于您的模式 B,这将解析为 true。

  1. 正确:在原型中定义方法将创建 1 个函数对象,每个实例将引用该 1 个函数。在构造函数中定义它为每个实例创建一个新函数

  2. 你的代码需要一些工作。在定义构造函数的方式中,doSomething函数被定义为全局添加var来解决这个问题。不过,这仍然没有将doSomething设置为属性,它只是在构造函数(闭包)范围内声明的函数。这就是为什么它没有在您的实例中显示为方法的原因:该函数未附加到this,但即使像这样解决此问题,您仍然会为每个实例创建新的函数对象:


 function MyConstructor()//capitalize constructors - conventions are important
 {
     var someMethod = function(){/*..*/};
     this.someMethod = someMethod;
 }

Utkanos指出了继承和原型方法的含义(.hasOwnProperty),他在这方面是绝对正确的(+1)。我只想补充一点,返回 false 的hasOwnProperty方法是一件小事。一般来说,在迭代对象并检查哪些属性和方法已设置,哪些未设置时。在大多数情况下,你想要的是属性,而不是方法。因此,实际上最好将它们设置为原型级别:

for(var name in obj)
{
    if (obj.hasOwnProperty(name))
    {
        //do stuff, here the methods are set @ prototype level
    }
    if (obj.hasOwnPrototype(name) && typeof obj[name] !== 'function')
    {
        //same stuff, but requires extra check when methods are assigned by constructor
    }
}