【问题标题】:Javascript: Prototyping a function with arguments for performanceJavascript:使用参数对函数进行原型设计以提高性能
【发布时间】:2012-05-12 11:26:08
【问题描述】:

在 John Resig 在Simple "Class" Instantiation in Javascript 上的帖子中,他说:

"...如果您希望人们与之交互的频繁访问的函数(返回一个对象),那么将对象属性放在原型链中并实例化它对您有利。这里是, 在代码中:"

// Very fast
function User(){}
User.prototype = { /* Lots of properties ... */ };
// Very slow
function User(){
    return { /* Lots of properties */ };
}

我想将其应用于如下函数(恰好位于“类”声明中)

//...
this.get_subscription = function(args)
{
    return {
        property_one: "value",
        property_two: {
            sub_prop: args.something
        }
    }
}

但不知道将参数放在哪里。如果我这样做了

this.get_subscription = function(args) {}
this.get_subscription.prototype = {
    property_one: "value"
    //...
}

它会说 args 是未定义的。我已经尝试了几种变体,但都不起作用。我应该如何正确地做到这一点,而不是将 args 放在父类的范围内?

【问题讨论】:

  • +1 提出了一个恰当的问题,但如果你仔细想想,你正在尝试的事情并没有多大意义。一个对象只有一个原型;但是对于每个args,您返回的对象都不同。这真的是您代码中的瓶颈吗?
  • 另外,对您考虑的效率的评论。直接在对象中定义的成员实际上比原型中的成员访问得更快。成员查找首先查找对象,然后查找其原型,依此类推,直至原型链。
  • @Cameron:不特别。我只想在这个项目中拥有尽可能少的 JS,而我所拥有的,我想尽可能快地制作 :)。正如以下答案之一指出的那样,我似乎误解了原型。

标签: javascript optimization prototype


【解决方案1】:

您似乎误解了prototype 的意思。原型包含对象的所有实例应该通用的方法和字段。因此,如果property_two是基于args传递给构造函数的,那么它属于原型!

毕竟在这段代码中

this.get_subscription = function(args) {}
this.get_subscription.prototype = {
    property_one: "value"
    //...
}

首先,创建函数get_subscription,然后将其原型设置为对象字面量。在调用构造函数之前没有args,因此在原型中使用args 做某事是没有意义的。

所以,你常用的 javascript 对象应该看起来像这个例子 - 一个 2D 点类。

function Point(x, y) {
    /*  In constructor:
     *  initialize fields that are related to the constructor parameters
     *  and are different for different instances
     */
    this.x = x;
    this.y = y;
}

// in prototype, define fields that are  common to all instances
Point.prototype.RED = '#FF0000';

/*  in prototype, also define the methods; as they can use the "this" keyword,
 *  they can reference their own instance, so you don't have to include them
 *  in each instance manually
 */

Point.prototype.toString = function() { return '[' + this.x + ', ' + this.y + ']'; };

【讨论】:

  • 谢谢。我明白我的问题是什么了。
【解决方案2】:

是的,这就是“一切到原型”理念的缺点:您无权访问构造函数参数 - 它们仅在函数体内部可用(除了你把他们进入那里的公共财产)。所有需要用到它们的东西都属于原型;您只会在原型上填写“默认属性”(通常是所有实例通用的方法)。

我认为你在这里无论如何都不需要那个。该模式仅对真正的构造函数有用,您在这里似乎没有(我希望this.Subscription)。此外,承诺的“性能提升”也可以忽略不计。

如果你真的想在这里使用它,那就是:

function Class() {
   this.Subscription = function(args) {
       this.propertyTwo = {
           subprop: args.something
       };
   };
   this.Subscription.prototype = {
       property_one: "value",
       property_two: {}
   };
}
// a method callable without the "new" operator:
Class.prototype.get_subscription = function(args) {
     return new this.Subscription(args);
}

用法:

var object = new Class();
var sub = new object.Subscription();
var sub2 = new object.Subscription();
// the promised boost is less memory usage for:
sub.propertyOne === object.Subscription.prototype.propertyOne === sub2.propertyOne;

当您尝试设置/更改/删除propertyTwo-Object(s) 上的属性时,还要注意Crockford's Prototypal inheritance - Issues with nested objects

【讨论】:

  • 非常有用,谢谢。您能否详细说明一下为什么这种模式在比较时会产生更少的内存使用?
  • 不,不是为了比较 :) 如果这些属性是对象(也是函数)而不是原始值,那么这些属性都将指向同一个对象。您只需要在内存中保存一个实例。然而,正如 Imp 在 cmets 中反对的那样,原型属性的查找比直接属性的查找要慢。该模式仅在这些属性非常消耗内存时才有用。
  • 另外,我需要解释一下“比较”。以上将扩展为 false,因为true !== "value"。我的意思是sub.propertyOne === object.Subscription.prototype.propertyOne && object.Subscription.prototype.propertyOne === sub2.propertyOne 是真的。
猜你喜欢
  • 2013-04-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-06
相关资源
最近更新 更多