Javascript 進階 作用域 作用域鏈
阿新 • • 發佈:2019-02-15
轉載請標明出處:http://blog.csdn.net/lmj623565791/article/details/25076713
一直覺得Js很強大,由於長期不寫js程式碼,最近剛好溫故溫故。
1、Javascript沒有程式碼塊作用域的概念,區域性作用域是針對函式來說的。
2、如果不使用var宣告的變數,預設為全域性變數function fun() { for( var i = 0 ; i < 10 ; i++) {} //如果在Java中i此時應當屬於未宣告的變數,但是Js中i的作用域依然存在 console.log(i);//10 if(true) { var b = "helloworld"; } console.log(b);//helloworld } fun();
function fun02()
{
a = "helloworld";
var b = "welcome";
}
fun02();
console.log(a); // helloworld
console.log(b); // b is not defined
3、Js中的作用域鏈
先看個簡單的例子:只有一個函式物件,函式物件和其它物件一樣,擁有可以通過程式碼訪問的屬性和一系列僅供JavaScript引擎訪問的內部屬性。其中一個內部屬性是[[Scope]],由ECMA-262標準第三版定義,該內部屬性包含了函式被建立的作用域中物件的集合,這個集合被稱為函式的作用域鏈,它決定了哪些資料能被函式訪問。
var a = "hello";
function fun04()
{
a = "world";
var b ="welcome";
}
作用域鏈的圖:
注:圖中省略了,Global Scope中的window,document等,每個函式物件中的arguments,this等均未畫出。
function fun03() { var a = 10; return function(){ a*= 2 ; return a ; }; } var f = fun03(); f(); var x = f(); console.log(x); //40 var g = fun03(); var y = g(); console.log(y); //20
觀察上面程式碼,存在fun03,f,g三個函式物件。
下面是作用域鏈的圖:
注:每個函式物件一個作用域鏈,這裡直接畫在了一起;對於變數的查詢,先從鏈的0開始找。
函式物件 f 在程式碼中執行了2 次,所以a*2*2 = 40 ; 函式物件 g 在程式碼中執行了1次, 所以 a *2 = 20 ;
4、閉包
上面的例子可以看到,在fun03執行完成後,a的例項並沒有被銷燬,這就是閉包。個人對閉包的理解是:函式執行完成後,函式中的變數沒有被銷燬,被它返回的子函式所引用。
下面以一個特別經典的例子,同時使用作用域鏈解析:
window.onload = function()
{
var elements = document.getElementsByTagName("li");
for(var i = 0; i < elements.length ; i ++)
{
elements[i].onclick = function()
{
alert(i);
}
}
}
相信上面的程式碼肯定大家都寫過,本意是點選每個li,打印出它們的索引,可是事實上打印出的都是elements.length。這是為什麼呢?
看下上面的簡易的作用域鏈(省略了很多部分,主要是理解),此時每個onclick函式的i,指向的都是 onload 中的i 此時的 i = element.length.
下面看解決方案:
window.onload = function ()
{
var elements = document.getElementsByTagName("li");
for (var i = 0; i < elements.length; i++)
{
(function (n)
{
elements[n].onclick = function ()
{
alert(n);
}
})(i);
}
}
在onclick函式的外層,包了一層立即執行的函式,所以此時的n指向的 n 是立即執行的,所有都是1~elements.length 。