2016-03-02 19 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