首頁  >  文章  >  web前端  >  JS核心系列:淺談函數的作用域

JS核心系列:淺談函數的作用域

大家讲道理
大家讲道理原創
2017-01-24 11:34:011019瀏覽

一、作用域(scope)

所謂作用域就是:變數在聲明它們的函數體以及這個函數體嵌套的任意函數體內都是有定義的。

function scope(){
    var foo = "global";
    if(window.getComputedStyle){
        var a = "I'm if";
        console.log("if:"+foo); //if:global
    }
    while(1){
        var b = "I'm while";
        console.log("while:"+foo);//while:global
        break;
    }
    !function (){
        var c = "I'm function";
        console.log("function:"+foo);//function:global
    }();
    console.log(
         foo,//global
         a, // I'm if
         b, // I'm while
         c  // c is not defined
    );
}
scope();

(1)scope函數中定義的foo變量,除過自身可以存取以外,還可以在if語句、while語句和內嵌的匿名函數中存取。 因此,foo的作用域就是scope函數體。

(2)在javascript中,if、while、for 等程式碼區塊不能形成獨立的作用域。因此,javascript中沒有區塊級作用域,只有函數作用域。

 但是,在JS中有一種特殊情況:

 如果一個變數沒有使用var聲明,window便擁有了該屬性,因此這個變數的作用域不屬於某一個函數體,而是window 。

function varscope(){
    foo = "I'm in function";
    console.log(foo);//I'm in function
}
varscope();
console.log(window.foo); //I'm in function

二、作用域鏈(scope chain)

     所謂作用域鏈是:一個函數體中嵌套了一個多層函數體,並在一個不同的變數體中定義了同一變數體中, 當其中一個函數存取這個變數時,便會形成一條作用域鏈(scope chain)。

foo = "window";
function first(){
    var foo = "first";
    function second(){
       var foo = "second";
       console.log(foo);
    }
    function third(){
       console.log(foo);
    }
    second(); //second
    third();  //first
}
first();

ond時,JS引擎會將second的作用域放置鍊錶的頭部,其次是first的作用域,最後是window對象,於是會形成如下作用域鏈:

second->first->window,此時,JS引擎沿著此作用域鏈找出變數foo, 查到的是"second"

當執行third時,third形成的作用域鏈:third->first->window, 因此查到的是: "frist"

特殊情況:with語句

JS中的with語句主要用來暫時擴展作用域鏈,將語句中的物件加入作用域的頭部。 with語句結束後,作用域鏈恢復正常。

foo = "window";
function first(){
    var foo = "first";
    function second(){
       var foo = "second";
       console.log(foo);
    }
    function third(obj){
       console.log(foo); //first
       with (obj){
           console.log(foo); //obj
       }
       console.log(foo); //first
    }
    var obj = {foo:'obj'};
    third(obj);
}
first();

在執行third()時,傳遞了一個obj對象,obj中有屬性foo, 在執行with語句時,JS引擎將obj放置在了原始鍊錶的頭部,於是形成的作用域鏈如下:

obj->third->first->window, 此時查找到的foo就是obj中的foo,因此輸出的是:"obj", 而在with之前和之後,都是沿著原來的鍊錶進行查找,從而說明,在with語句結束後,作用域鏈已恢復正常。

三、this 關鍵字

     在一個函數中,this必須指向當前函數的所有者物件, , 也才能知道它的呼叫對象。      這句話總結了關於this的一切,切記,切記,切記!(ps:重要的事情說三遍!)

window.name = "window";
function f(){
    console.log(this.name);
}
f();//window

var obj = {name:'obj'};
f.call(obj); //obj
在執行f()時,此時呼叫者是window對象,因此輸出"window"f.call(obj) 是把f()放在obj對像上執行,相當於obj.f(),此時f中的this就是obj,所以輸出的是"obj"

四、實戰應用code1:

var foo = "window";
var obj = {
    foo : "obj",
    getFoo : function(){
        return function(){
            return this.foo;
        };
    }
};
var f = obj.getFoo();
f(); //window
code2:this對於運行,歡迎討論!

程式碼解析:

var foo = "window";
var obj = {
    foo : "obj",
    getFoo : function(){
        var that = this;
        return function(){
            return that.foo;
        };
    }
};
var f = obj.getFoo();
f(); //obj

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn