Javascript关闭性能

roy*_*jas 15 javascript performance closures

我已经在javascript中工作了一段时间,并且通常做这样的事情只是为了缓存在深层结构或"命名空间"中声明的函数的属性值

//global scope
(function ($, lib) {
  //function scope 1
  var format = lib.format, // instead of calling lib.format all the time just call format
    touch = lib.pointer.touch, //instead of calling lib.pointer.touch each time just touch
    $doc = $(document),
    log = logger.log; //not console log...


  $doc.on('app:ready', function () {
    //function scope 2
    $doc.on('some:event', function (e) {
      //function scope 3
      //use the cached variables
      log(format('{0} was triggered on the $doc object', e.type);
    });

    $doc.on(touch, function (e) {
      //function scope 3
      log(format('this should be {1} and is... {0} ', e.type, touch);
    });
  }); 
}(jQuery, lib));
Run Code Online (Sandbox Code Playgroud)

我这样做是因为:

  • 像我一样懒惰,编写touch似乎更有吸引力的是编写lib.pointer.touch,即使具有花哨自动完成功能的强大IDE可以帮助解决这个问题,触摸也会更短.
  • 最小化器可以将单个私有变量转换为单个字母变量,所以它对我来说也是有意义的(我知道,我知道,从来没有过快地优化,但我认为这似乎是安全的)

所有以这种方式编写的代码似乎在移动设备和桌面浏览器上表现得相当不错,所以这似乎是一种安全的做法(在"实践中",双关语意图).但我因为这依赖于闭包,内部函数必须创建一个闭包来保存它声明的上下文我想知道...

  • 如果函数不使用外部上下文中的变量(自由变量)...是否仍保存了闭包上下文?(或者,如果我的树倒在树上,没有人在那里听到它,它是否仍然会发出撞击声?呵呵)我知道这可能因javascript引擎而异,因为ECMA没有提及是否需要保存不访问来自外部的变量时的上下文.

  • 如果上面的表达式是真的......这段代码会更有效吗?

    //global scope
    (function ($, lib) {
      //function scope 1
      var format = lib.format,
        touch = lib.pointer.touch,
        $doc = $(document),
        log = console.log;
    
      $doc.on('app:ready', function () {
    
        (function ($doc, touch, lib, format) {
          // since all the variables are provided as arguments in this function
          // there is no need to save them to the [[scope]] of this function
          // because they are local to this self invoking function now
          $doc.on('some:event', function (e) {
            //function scope 3
            //use the cached variables
            log(format('{0} was triggered on the $doc object', e.type);
          });
    
          $doc.on(touch, function (e) {
            //function scope 3
            log(format('this should be {1} and is... {0} ', e.type, touch);
          });
        }($doc, touch, lib, format));      
    
      }); 
    
    }(jQuery, lib));
    
    Run Code Online (Sandbox Code Playgroud)

它是否更有效,因为它将这些变量传递给自立立即调用函数?创建新功能的成本会对代码产生什么影响(负面还是正面)?

  • 如何以可靠的方式正确测量我的javascript库的内存消耗?我有100x小的javascript模块都在立即自我调用函数内部,主要是为了避免变量泄漏到全局上下文.所以它们都包含在与上面提到的代码块非常相似的模块中.

  • 它是否会更好地缓存变量,即使这意味着我将不得不重复变量的声明更接近它们将要使用的位置?

  • 我觉得寻找不在当前本地环境中的变量,引擎将首先查看父范围并迭代该级别的所有变量...每个级别的变量越多,可能更糟糕的是性能看起来对于变量.

  • 尝试从内部闭包中找到一个未定义的变量将是最昂贵的,因为根据定义,变量将首先在父作用域上搜索直到全局作用域,而不是找到它将迫使引擎最终到达全局作用域.真的吗?是优化这种查找的引擎?

最后......我知道我不想将我的代码实现为第二个例子,主要是因为它会使代码难以阅读,而且我对使用第一种方法的最终输出的最小化大小很有帮助.我的问题是出于好奇心,并试图更好地理解这个非常好的javascript功能.

根据这个测试......

http://jsperf.com/closures-js

似乎第二种方法更快.但是只有在迭代疯狂的次数时才会显而易见......现在我的代码没有做那么多的迭代......但由于我的编码方式,可能会消耗更多的内存......

更新:有人指出我这个问题太大了.对不起,我会试着打破小部分.正如我所说,这个问题主要是出于好奇心,即使在移动设备中,性能也几乎可以忽略不计.感谢您的所有反馈.

Jua*_*des 10

我认为这是不成熟的优化.您已经知道在大多数情况下性能不是问题.即使在紧密的循环中,性能也不会降低那么糟糕.通过从关闭中删除不需要的变量,让JavaScript引擎在Chrome开始时自行优化.

一个重要的事情是,不要让你的代码更难以阅读不必要的优化.您的示例需要更多代码,阻碍开发.在某些情况下,我们被迫使代码更难阅读,因为我们知道应用程序的某个特定部分是内存/性能密集型的,但只有在那时我们应该这样做.

如果你在下面的代码中添加一个断点(在Chrome中),你会看到world变量已经从闭包中优化了,看看Scope变量http://jsfiddle.net/4J6JP/下的'Closure'节点1 /

在此输入图像描述.

(function(){
   var hello = "hello", world="world";
    setTimeout(function(){
        debugger;
        console.log(hello);
    });
})()
Run Code Online (Sandbox Code Playgroud)

请注意,如果在该内部函数中添加eval,则所有投注都将关闭,并且无法优化闭包.

  • 无论如何,我认为这种变化并不明显.坚持阅读最容易阅读,直到你发现它是一个问题.当您处理特别是内存或性能密集的代码段时,它才会引人注意 (3认同)
  • 谢谢老兄,所以作为你的结论,至少关心闭包的性能没有多大意义,除非它们真的成为一个问题,对吗?浏览器似乎在优化闭包方面做得很好。所以在自调用函数中拥有 100 多个模块应该不是问题吧? (2认同)