为什么这个JavaScript闭包数组保留旧值

时间:2016-03-02 18:47:17

标签: javascript arrays arguments closures

我遇到了java脚本闭包和数组的有趣情况。 我不确定javascript的哪一部分导致了arguments数组的缓存。

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 3

而不是

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脚本的哪个属性是发生这种情况的原因?

编辑: 该代码已被编辑以移除推动,并且更好地解释了SCENERIO

2 个答案:

答案 0 :(得分:2)

foo函数只接受三个参数,

function foo(param1, param2, param3) {

并且它只发送了三次

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

然后,push()推送到数组,所以当你有[1,2,3,4]时,只发送前三个,而不是第四个。

如果函数接受了四个参数



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]

答案 1 :(得分: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