这两段实现有区别么?



  • 我在做console-panel项目时,有这样一段代码,实现的是代理系统的console方法,先前的实现是这样的:

    function proxyStockConsole(console,consoleStack){
            const methods = ['log','error','info','warn'];
    
            for(let m of methods){
                var stockM = console[m];
                var newName = '_'+m;
                if(console[newName]){
                    continue;
                }
                console[newName] = stockM;
                console[m] = function(){
                    consoleStack.add(m,arguments[0]);
                    stockM.apply(console,arguments)
                };
            }
        }
    

    功能上倒是没有区别,但在chrome dev console打印出来时,却跟原来的不一样,所有经过代理的日志,背景变成了黄色就跟warn消息一样 , 显然跟原来的方式在本质上有区别.

    所以我昨天换了一种实现,参考react-native系统添加yellowbox的方式:

    function proxyStockConsole(console, consoleStack, keepYellow) {
                //disable yellowbox added in v0.16
                if (keepYellow === false ) {
                    console.disableYellowBox = true;
                }
                const {log,error,info,warn} = console;
    
                const proxy = (f,name)=>{
                    console[name] = function(){
                        consoleStack.add(name, arguments[0]);
                        f.apply(console, arguments)
                    };
                };
                proxy(log,'log');
                proxy(warn,'warn');
                proxy(error,'error');
                proxy(info,'info');
    
           }
    

    chrome dev console里的黄色背景就没了.
    求javascript高手们带带我这个rookie,普及一下,这两种有什么区别?



  • 因为var的有效区间是当前function而非当前block,因此在前一段代码里,经过若干次循环后,函数内局部变量中的stockM最终为methods['warn']。

    当console.log/error被调用时,实际执行的stockM也是原来的console.warn,这就是为啥有黄色背景了。

    而后一段代码,f作为参数传递,因此尽管有效区间仍然是function,但被限制在了小function内,因此每次proxy函数被调用,所用到的f变量都是一个不同的引用。

    只要做到这一点,代码可以不必写的这么复杂,完全可以这样:

    function proxyStockConsole(console,consoleStack){
      ['log','error','info','warn'].forEach(v=>{
        var f = console[v]; // 注意虽然还是一个局部变量,但对数组中的每一项都会执行一次,因此不会影响到其它的值。
        console['_'+v] = f;
        console[v] = function(){
          consoleStack.add(v, arguments[0]);
          f.apply(console, arguments)
        }
      })
    }
    

    这和一个经典问题一致:

    for (var i = 0;i < 10; i++){
      setTimeout(function(){
        console.log(i);
      });
    }
    

    最终打印出来的是10个10,而不是从0到9十个数字。



  • 明白了 初级错误~~