其實函數引用的外部變數都是最後一次的值。 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style> #box{ width:100px; height:100px; b
其實函數引用的外部變數都是最後一次的值。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
<style>
#box{
width:100px;
height:100px;
background-color:pink;
}
</style>
<script src="index.js"></script>
</head>
<body>
<div id="box"></div>
</body>
</html>
///////////////////////////////js代碼//////////////////////////
window.onload = function(){
var box = document.getElementById("box");
var num = 0;
function a(){
console.log(num);
}
box.onclick = function(){
num ++;
a(); // 1,2,3,4....每次單擊都會加1,說明函數引用外部變數是引用那個變數的最後一次的值。
}
}
再來看一個例子:
window.onload = function(){
var box = document.getElementById("box");
var num = 0;
for(var i=0;i<10;i++){
box.onclick = function(){
console.log(i); //總是列印10
}
}
}
如果你知道作用域鏈就好辦多了,在這個函數裡面的i其實引用的是最後一次i的值,為什麼不是1,2,3,4...呢?因為在你for迴圈的時候,你並沒有執行這個函數,你這個函數是在你點擊的時候才執行的,當執行這個函數的時候,它發現它自己沒有這個變數i,於是向它的作用域鏈中查找這個變數i,因為當你單擊這個box的時候已經for迴圈完了,所以儲存在作用域鏈裡面的i的值就是10,最後就列印出來10了。
for(var i=0;i<10;i++){
function a(){
console.log(i);
}
a(); //1,2,3,4,5....
}
為什麼這樣就可以呢?因為你在迴圈變數i的時候已經執行了函數a,自然變數i是什麼就列印出來什麼。
現在知道為什麼綁定事件的時候列印出來的是最後一次的for迴圈的值了吧。
如果你知道理解這段話,我相信你知道怎麼去解決這個問題。
解決方法1:讓這個函數直接執行。
解決方法2:將每次for迴圈中的變數i保存到某個地方。
方法1:
window.onload = function(){
var box = document.getElementById("box");
var num = 0;
for(var i=0;i<10;i++){
box.onclick = a();
function a(){
console.log(i); //1,2,3,4.....
}
}
}
雖然這樣可以列印出每次的變數i的值,但是我們沒有點擊box的時候它已經執行完了,直接無視了點擊事件,也就是說這個點擊事件已經可有可無了,所以我們用這種方法在綁定事件中就顯得不那麼可用了,那我們用方法2試試吧。
方法2:
window.onload = function(){
var div = document.getElementsByTagName("div");
var num = 0;
for(var i=0;i<div.length;i++){
(function(i){
div[i].onclick = function(){
console.log(i);
}
})(i)
}
}
成功列印每個i的值,原理就是通過自執行函數,並且將變數i保存到這個自執行函數的參數中。如果你不知道什麼是自執行函數可以看初識js中的閉包這一節。
你們我們應該選擇那種方法呢?當然看你的情況了,如果沒有關於綁定事件的話,就是說讓這個函數直接執行的,那就用方法1,否則用方法2,另外方法2通用,但是因為裡面的i會一直保存到記憶體中比較消耗性能的原因,所以在沒有必要的情況下儘量不要用這種方式,其實還可以將i綁定到元素的屬性上。