javascript V8优化和;“泄露论据”;

javascript V8优化和;“泄露论据”;,javascript,v8,Javascript,V8,我在书中读到,建议小心使用参数对象,这没关系 var i = arguments.length, args = new Array(i); while (i--) args[i] = arguments[i]; 但是,这行不行 function makeArray (l) { var i = l.length, array = new Array(i); while (i--) array[i] = l[i]; return array; }; //..

我在书中读到,建议小心使用
参数
对象,这没关系

    var i = arguments.length, args = new Array(i);
    while (i--) args[i] = arguments[i];
但是,这行不行

function makeArray (l) {
    var i = l.length, array = new Array(i);
    while (i--) array[i] = l[i];
    return array;
};
//...
//EDIT: put the function on an object to better represent the actual case
var o = {};
o.f = function (callback) {
    var args = makeArray (arguments);
    callback.apply(args[0] = this, args);
};
“泄漏参数”是什么意思?它如何影响优化

我专注于V8,但我认为它也适用于其他编译器

为了证明它有效

函数makeArray(l){
变量i=l.长度,数组=新数组(i);
而(i--)数组[i]=l[i];
返回数组;
};
//...
//编辑:将函数放在对象上,以更好地表示实际情况
var o={};
o、 f=函数(回调){
var args=makeArray(参数);
callback.apply(args[0]=this,args);
};
o、 m=“你好,”;
功能测试(f,n){
警报(此.m+“”+n)
}

o、 f(测试,“它工作…”)
这是一个双重问题:

  • 您将丢失所有可能的优化和分支预测
    参数
    对象是不可预测的
  • 你泄漏了内存。真糟糕 考虑以下代码(运行它的风险由您自己承担!):

    函数a(){返回参数;}
    x=a(document.getElementsByTagName('*');
    窗口。_interval=setInterval(函数(){
    
    对于(var i=0;i而言,
    参数的问题与本地
    eval
    参数的问题相同:它们会导致别名。因此,即使您启用了此类函数的优化,您可能最终也会浪费时间,这是JIT的问题,因为在编译器中花费的时间不是运行代码的时间(尽管优化管道中的某些步骤可以并行运行)

    由于
    参数
    泄漏而产生的别名:

    function bar(array) {    
        array[0] = 2;
    }
    
    function foo(a) {
        a = 1;
        bar(arguments);
        // logs 2 even though a is local variable assigned to 1
        console.log(a);
    }
    foo(1);
    
    请注意,严格模式消除了这一点:

    function bar(array) {    
        array[0] = 2;
    }
    
    function foo(a) {
        "use strict";
        a = 1;
        bar(arguments);
        // logs 1 as it should
        console.log(a);
    }
    foo(1);
    

    但是严格模式也没有得到优化,我不知道任何合理的解释,除了基准测试不使用严格模式,而且很少使用严格模式。这可能会改变,因为许多es6功能需要严格模式,所以es6中不需要otoh
    参数,所以…

    不会
    函数a(arg){return arg;}
    产生相同的结果?@CoolBlue不,在这种情况下,您返回的是相同的变量。在我的情况下,您一次又一次地返回一个新的
    参数
    对象的引用。@CoolBlue我添加了一个代码来说明我的观点。您可以尝试一下。但要非常小心。您返回的
    参数
    会在中留下一个闭包de>a
    和通过
    参数的循环引用。被调用方
    。这是一场内存泄漏完美风暴…我的示例是在makeArray调用中添加对新
    参数
    对象的引用,但在'f``完成后我不会留下任何闭包。我缺少什么?我在示例中没有看到内存泄漏。@CoolBlue我没有看到任何c丢失。并且您的代码仍然有(某种程度上)部分功能与第一个示例相同。您的代码将
    arguments
    对象传递给另一个函数,然后用于调用另一个函数,该函数包含在
    arguments
    对象中,您可以将
    窗口
    对象分配给它。好的,但优化的唯一方法是将while循环置于复制
    参数
    在原始函数中,无法导出它的源代码…对吗?与其使用
    var o={};o.f=function(){[code]};
    ,不如使用
    var o={f:function(){[code]};
    。实际上它们是等价的;)是的,它们是。但不同的是,你正在使用我提供的代码创建一个对象,使用一个方法。使用你的代码,你创建一个空对象,然后修改它以插入一个新方法。好吧,最终结果是一样的。我这样做是为了更紧密地模拟我正在分析的实际代码。我知道有几种方法可以但你为什么建议按你建议的方式去做呢?有什么特别的原因吗?我想到了两个好处:1-最基本的是语法本身。你可以在那里声明每个方法和属性,而不需要做任何更改。你不需要到处乱翻来看看方法/属性是如何定义的。2-因为如果您一次完成所有操作,编译器可能会在创建对象和访问任何方法/属性时优化代码。