JavaScript Object Literal表示法与普通函数和性能影响?

ace*_*ace 14 javascript

假设我有以下功能:

function foo() {

}

function bar() {

}
Run Code Online (Sandbox Code Playgroud)

我可以在上面写为Object Literal表示法:

var Baz = {
  foo: function() {
  },
 bar: function() {
 }
};
Run Code Online (Sandbox Code Playgroud)

据我所知,在后一种情况下,无论是否调用任何Baz函数,脚本加载时都会创建一个Baz实例.在前一种情况下,仅在调用该函数时才创建函数对象.我对这些假设是否正确?

如果我是正确的那么前者将具有比后者在很少调用这些函数的应用程序中更高的性能(更少的内存).但后者的优势在于它提供了更大的模块化和更低的全局命名空间污染.

您从专业经验中对此有何看法?有速度差吗?

T.J*_*der 43

在前一种情况下,仅在调用该函数时才创建函数对象.

不,无论如何都会创建这些功能.

请注意,您也可以这样做:

function foo() {
}

function bar() {
}

var Baz = {
  foo: foo,
  bar: bar
};
Run Code Online (Sandbox Code Playgroud)

或这个:

var Baz = (function() {
    function foo() {
    }

    function bar() {
    }

    return {
      foo: foo,
      bar: bar
    };
})();
Run Code Online (Sandbox Code Playgroud)

将函数Baz作为属性放置的主要目的是使它们作为"方法"可用Baz.这可能是为了方便,"命名空间"等.在您的第一个表单(以及我上面的第一个表单)中,如果该代码处于全局范围,foo并且bar被添加到全局范围,这可能会非常快速地拥挤(特别是.在浏览器上).在第二个示例中,唯一的全局符号是Baz因为函数是匿名的.在上面的最后一个例子中,唯一的全局符号是Baz但函数不是匿名的,它们具有调试器和堆栈跟踪可以显示的名称(这是一件好事; 更多信息).

在尝试优化函数何时创建时,以下是它的工作原理:当执行进入给定的上下文(全局上下文或与调用函数相关的上下文)时,这些事情就完成了:

  1. 创建幕后执行上下文对象.
  2. 创建该执行上下文的幕后变量对象.
  3. 在函数上下文的情况下:
    1. 将属性添加到变量对象中arguments(可用于访问参数的类似数组的事物)
    2. 对于每个函数的命名参数,将使用参数的值将属性添加到变量对象中
    3. 如果函数具有名称,则将其名称添加为变量对象的属性,并具有函数对象的值.
  4. 对于var在执行上下文中声明的每个变量,在变量对象上创建属性; 它们的值最初是undefined(无论是否var有初始化器).
  5. 处理上下文中的每个函数声明.(函数表达式尚未处理;更多信息如下所示.)创建每个函数名的变量对象的属性,并接收函数对象作为其值.
  6. 逐步执行代码.
    • 与所有表达式一样,函数表达式在逐步流程中遇到时会被计算.
    • var具有初始值设定项(例如var a = 2;)的语句与赋值语句(a = 2;)完全相同; var它的方面很早就完成了.(var经常被误解.例如,我们有这个问题就在昨天.)

您将注意到函数声明和函数表达式之间的差异.您可以通过查看是否将结果用作右手值来判断哪个是哪个 - 也就是说,您是将结果分配给变量,将其用作对象中属性定义的右侧文字,或将其传递给函数.如果你是,那就是一个函数表达式.如果你不是,那就是一个功能声明.

函数声明示例:

function foo() {
}
Run Code Online (Sandbox Code Playgroud)

函数表达式示例:

var foo = function() {
};
Run Code Online (Sandbox Code Playgroud)

另一个:

var Baz = {
    foo: function() { }
};
Run Code Online (Sandbox Code Playgroud)

(该foo行是对象文字中的属性声明,它使用函数表达式作为值.)

命名函数表达式示例:

var f = function foo() {  // <== Don't do this (more below)
};
Run Code Online (Sandbox Code Playgroud)

命名函数表达式应该是有效的,但它们在野外(特别是IE)中的实现很难得到支持,因此现在必须避免它们.更多这里.

  • @DHorse:JS中的Perf问题很棘手,因为引擎变化很大.但如果你的意思是问题中的两个选项,答案几乎肯定是否定的.一旦引擎具有函数引用,在两种情况下执行调用都是相同的,因此我们必须查看引擎如何获取函数引用.在第一个例子中,要调用`foo`,引擎必须在执行上下文的绑定对象上查找`foo`.在第二个例子中,它必须以相同的方式查找`Baz`,然后在'Baz`上查找`foo`,这是更多的步骤.但我敢打赌它没有真正的区别. (2认同)