Javascript 访问闭包变量与对象变量的速度

Javascript 访问闭包变量与对象变量的速度,javascript,closures,Javascript,Closures,考虑以下代码: var xx=1; var ff=function(){ return xx+1; } ff(); var gg=function(){ return gg.xx+1; } gg.xx=1; gg(); 这两种方法之间是否存在明显的性能差异?在我看来,ff函数应该执行得更快,因为它只引用一个变量,而gg函数引用两个变量。我正在开发一款游戏,希望尽我所能利用所有可能的速度技巧。有人问我这个问题。这里唯一的区别是,这两个示例通常都不是闭包,它们是变量和属性解析的简

考虑以下代码:

var xx=1;
var ff=function(){
  return xx+1;
}
ff();    

var gg=function(){
  return gg.xx+1;
}
gg.xx=1;
gg();

这两种方法之间是否存在明显的性能差异?在我看来,
ff
函数应该执行得更快,因为它只引用一个变量,而
gg
函数引用两个变量。我正在开发一款游戏,希望尽我所能利用所有可能的速度技巧。

有人问我这个问题。这里唯一的区别是,这两个示例通常都不是闭包,它们是变量和属性解析的简单示例

在下列情况下:

var xx = 1;
var ff = function(){
  return xx + 1;
}
var gg = function(){
  return gg.xx + 1;
}
gg.xx = 1;
然后在函数中,必须首先在局部变量对象上解析xx,然后在作用域链上解析xx。所以至少有两次查找

在下列情况下:

var xx = 1;
var ff = function(){
  return xx + 1;
}
var gg = function(){
  return gg.xx + 1;
}
gg.xx = 1;
在函数中,必须以与第一种情况完全相同的方式解析gg(即在局部变量对象上,然后在范围链上),这也是两种查找。找到gg后,必须搜索其属性以查找xx,这可能涉及大量查找

考虑到上述情况,合理的假设是第一个更快

当然,这只是一个逻辑推论,性能可能实际上与此相反。在某些浏览器中,无论作用域链的长度如何,全局变量查找都比局部变量查找快。算了吧

可以肯定的是,在不同的浏览器中,无论使用哪种方式,性能都会有所不同。这样的性能调整(如果有任何性能优势的话)是在边缘发挥作用,应该被视为过早的优化

编辑 将其编码为闭包需要以下内容:

var gg = (function() {
  var g;
  return function() {
    gg = function() {
      return g.xx + 1; // Here is the closure
    }

    if (typeof g == 'undefined') {
      g = gg;
    }

    if (typeof g.xx == 'undefined') {
      g.xx = 1;
    }

    return g();
  }
}());
由于gg在IIFE结束之前没有值,因此只能在该点创建闭包,因此只能在以后首次运行函数时分配该值

请注意,g仍然必须在局部变量对象上解析,然后在范围链上解析,因此仍然有两个查找,并且闭包没有收益(至少没有逻辑收益)

编辑2 只是想澄清一下关于关闭的问题:

var xx = 1;
var ff = function(){
  return xx + 1;
}
从技术上讲,这不是一个终结,但不值得承认。标识符xx在作用域链上解析,当某些外部执行上下文完成时,ff无法访问作用域链上的任何变量。因此,闭包只在函数存在的时间内存在,因此它并不比词法范围更显著

相比之下:

var ff = (function() {

  var closureVariable;

  // This "inner" function has a closure with closureVariable
  // If value is undefined, get (return) the value. Otherwise, set it
  return function(value) {
    if (typeof value == 'undefined') {
      return closureVariable;
    }
    closureVariable = value;
  };
}());
在这种情况下,ff以独占方式访问closureVariable,该变量在创建它的函数完成后仍然可以访问:

// set the value
ff('foo');

// get the value
console.log(ff());  // foo
closureVariable仅可由ff访问(与全局变量不同),并在多次调用中保持不变(与局部变量不同)。正是闭包的这一特性使它们能够


另一个特点是,许多函数可以对同一变量进行闭包(或私有访问),模拟一种继承。

有人问过这一点。这里唯一的区别是,这两个示例通常都不是闭包,它们是变量和属性解析的简单示例

在下列情况下:

var xx = 1;
var ff = function(){
  return xx + 1;
}
var gg = function(){
  return gg.xx + 1;
}
gg.xx = 1;
然后在函数中,必须首先在局部变量对象上解析xx,然后在作用域链上解析xx。所以至少有两次查找

在下列情况下:

var xx = 1;
var ff = function(){
  return xx + 1;
}
var gg = function(){
  return gg.xx + 1;
}
gg.xx = 1;
在函数中,必须以与第一种情况完全相同的方式解析gg(即在局部变量对象上,然后在范围链上),这也是两种查找。找到gg后,必须搜索其属性以查找xx,这可能涉及大量查找

考虑到上述情况,合理的假设是第一个更快

当然,这只是一个逻辑推论,性能可能实际上与此相反。在某些浏览器中,无论作用域链的长度如何,全局变量查找都比局部变量查找快。算了吧

可以肯定的是,在不同的浏览器中,无论使用哪种方式,性能都会有所不同。这样的性能调整(如果有任何性能优势的话)是在边缘发挥作用,应该被视为过早的优化

编辑 将其编码为闭包需要以下内容:

var gg = (function() {
  var g;
  return function() {
    gg = function() {
      return g.xx + 1; // Here is the closure
    }

    if (typeof g == 'undefined') {
      g = gg;
    }

    if (typeof g.xx == 'undefined') {
      g.xx = 1;
    }

    return g();
  }
}());
由于gg在IIFE结束之前没有值,因此只能在该点创建闭包,因此只能在以后首次运行函数时分配该值

请注意,g仍然必须在局部变量对象上解析,然后在范围链上解析,因此仍然有两个查找,并且闭包没有收益(至少没有逻辑收益)

编辑2 只是想澄清一下关于关闭的问题:

var xx = 1;
var ff = function(){
  return xx + 1;
}
从技术上讲,这不是一个终结,但不值得承认。标识符xx在作用域链上解析,当某些外部执行上下文完成时,ff无法访问作用域链上的任何变量。因此,闭包只在函数存在的时间内存在,因此它并不比词法范围更显著

相比之下:

var ff = (function() {

  var closureVariable;

  // This "inner" function has a closure with closureVariable
  // If value is undefined, get (return) the value. Otherwise, set it
  return function(value) {
    if (typeof value == 'undefined') {
      return closureVariable;
    }
    closureVariable = value;
  };
}());
在这种情况下,ff以独占方式访问closureVariable,该变量在创建它的函数完成后仍然可以访问:

// set the value
ff('foo');

// get the value
console.log(ff());  // foo
closureVariable仅可由ff访问(与全局变量不同),并在多次调用中保持不变(与局部变量不同)。正是闭包的这一特性使它们能够


另一个特点是,许多函数可以对同一变量进行闭包(或特权访问),模拟一种继承。

没有闭包,变量解析(xx和gg)是相同的。第二种方法还涉及到属性查找,因此速度应该较慢,但没有考虑浏览器的异常情况。更担心的是保持数据井然有序。与其他方面相比,这方面的性能差异将是极其微小的-例如驱动DOM。没有闭包,变量分辨率(xx和gg)是相同的。第二种方法还涉及到属性查找,因此速度应该较慢,但没有考虑浏览器的异常情况