2016-03-02 90 views
1

我遇到了java-script关闭和数组的有趣情况。 我不确定javascript的哪个部分导致了参数数组的缓存。为什么JavaScript封闭数组保留旧值

var SLICE = Array.prototype.slice; 
 

 
    var attach = function(method) { 
 
    var args = SLICE.call(arguments, 1); 
 
    return function() { 
 
     args = args.concat(SLICE.call(arguments, 0)); 
 
     method.apply(null, args); 
 
    }; 
 
    }; 
 

 
    function foo(param1, param2, param3) { 
 
    console.log(param1, param2, param3); 
 
    }; 
 

 
    var bar = attach(foo, 1, 2); 
 
    bar(3); 
 
    bar(4);

上述代码的输出是

代替

1 2 3 
1 2 4 

获得正确的输出,如果代码改变为

var SLICE = Array.prototype.slice; 
 

 
    var attach = function(method) { 
 
    var args = SLICE.call(arguments, 1); 
 
    return function() { 
 
     method.apply(null, args.concat(SLICE.call(arguments, 0))); 
 
    }; 
 
    }; 
 

 
    function foo(param1, param2, param3) { 
 
    console.log(param1, param2, param3); 
 
    }; 
 

 
    var bar = attach(foo, 1, 2); 
 
    bar(3); 
 
    bar(4);

输出是

1 2 3 
1 2 4 

我想明白了,其中的Java脚本的性能会发生这种情况背后的原因是什么?

编辑: 代码被修改,以去除推,并解释越好之情况

+0

因为'push'变异的'args'。 – Bergi

+0

@Bergi,删除了推送,以更好地解释发生的情况 –

回答

2

foo函数只接受三个参数,

function foo(param1, param2, param3) { 

而且它永远只被派出三名

method(args[0], args[1], args[2]); 

还有,push()推到阵列,所以当你有[1,2,3,4] onl三个第一个被派出,而不是第四个。

有函数接受四个参数

var SLICE = Array.prototype.slice; 
 

 
var attach = function(method) { 
 
    var args = SLICE.call(arguments, 1); 
 

 
    return function() { 
 
     for (var key in arguments) { 
 
      args.push(arguments[key]); 
 
     } 
 
     method(args[0], args[1], args[2], args[3]); 
 
    }; 
 
}; 
 

 
function foo(param1, param2, param3, param4) { 
 
    console.log(param1, param2, param3, param4); 
 
}; 
 

 
var bar = attach(foo, 1, 2); 
 
bar(3); 
 
bar(4);

你会越来越控制台1 2 3 4

换句话说,这与缓存没有关系,或者没有添加值,只是当新值被推送到数组时不能接受足够的参数。

的更好的方法是,其接受任意数目的参数

var SLICE = Array.prototype.slice; 
 

 
var attach = function(method) { 
 
    var args = SLICE.call(arguments, 1); 
 

 
    return function() { 
 
     args = args.concat(SLICE.call(arguments)); 
 
     method.apply(null, args) 
 
    }; 
 
}; 
 

 
function foo() { 
 
    console.log(arguments); 
 
}; 
 

 
var bar = attach(foo, 1, 2); 
 
bar(3); 
 
bar(4);

在问题的第二代码段不继续添加到阵列的原因功能是因为数组没有存储,concat返回一个新的数组,它不会改变原来的,所以它必须是

args = args.concat(array); 

来存储更改。由于您不存储更改,因此每次调用内部函数时,都会使用原始数组[1,2]并向其中添加一个值,然后将其返回。

,因为它不是存储,调用bar(3)需要[1,2],并增加了3,和你结束了[1,2,3]第一次。
下一次调用该函数时,它只是执行相同的操作,需要[1,2]并添加4等,而最终用[1,2,4]代替。

+0

我明白这是因为参数被拼接的方式,所以,我编辑了代码以更好地解释场景。我不想更改foo的结构或传递给它的参数的数量 –

+1

@goku - 第二个代码片段不会继续添加到数组的原因是因为数组未存储,每当内部函数调用它的时候,需要原始数组''[1,2]'并为其添加一个值,然后返回它,它不会被存储,所以下次调用该函数时,它只会执行相同的操作,它会使用[[1] ,2]'并且加上'4'等。 – adeneo

+0

非常感谢评论,你可以发布这个答案吗?我会接受这个。 –

0

除了adeneo的回答,您可以使用Function.prototype.bind()来实现你attach功能:

function attach(method, a, b) { 
    return method.bind(method, a, b); 
} 

function foo(param1, param2, param3) { 
    console.log(param1, param2, param3); 
}; 

var bar = attach(foo, 1, 2); 
bar(3); 
bar(4); 
//output is 
// 1 2 3 
// 1 2 4