2011-09-03 23 views
1

我有兩個函數,一個函數調用另一個函數。JavaScript範圍問題:變量未被識別

下面是一個簡單的類比我創建的代碼,其結構我有:

function test1(){ 
    alert(a);//a is not identified here even when test1() is called under test2 which has a defined in scope 
    alert(b);//b is identified here 
} 

function test2(){ 
    var a  =  'a';//Defining a 
    test1();//Calling test1() 
} 
var b = 'b'; 
test2(); 

如根據上面的代碼中,函數TEST1()是能夠識別變量b但不變量a。

我的問題是,爲什麼變量a不在test1函數的範圍內,即使我們在test2()中調用test1()時,它定義了變量a?

在此先感謝。

回答

2

函數在創建時記住它們的作用域鏈,而不是在它們被調用時。

注意b得到"hoisted",所以你的代碼實際上做到這一點:

var b; // push b on scope chain 

function test1(){ // store scope chain [b] 
    alert(a); 
    alert(b); 
} 

function test2(){ // store scope chain [b] 
    var a; // push a on scope chain 
    a = 'a'; 
    test1(); //Calling test1() which still has scope chain [b], not [b,a] 
} 
b = 'b'; 
test2(); 
+1

「函數在創建時記住它們的作用域鏈,而不是在它們被調用時。這似乎是整個問題的關鍵。 – netemp

3

您的期望是錯的變量的作用域,

根據你的代碼b是2種功能的全局變量和atest2功能的範圍不僅因爲它是withing test2, 如果定義你想要的東西像你期望你可以在test2範圍這樣定義test1功能,

function test2(){ 
    var a  =  'a'; 
    test1(); 
    function test1(){ 
     alert(a); 
     alert(b); 
    } 
} 
var b = 'b'; 
test2(); 
+0

@NetEmp有關作用域更多信息,請參閱[維基百科文章](http://en.wikipedia.org/wiki/Scope_(programming)#Lexical_versus_dynamic_scoping)。 Javascript使用詞法範圍,因爲動態範圍是邪惡的。 – sethobrien

+0

感謝sethobrien – netemp

1

JavaScript有「功能範圍」,這意味着在AF定義的東西功能以外的功能不可見。所以變量'a'在test2之外是不可見的。然而,變量'b'是一個全局變量,因此它在每個範圍內都可見。

函數作用域也意味着內部函數可以訪問外部函數中定義的東西,但不會在這裏播放...... test1在test2中是從調用的,但它不是test2的內部函數。要看到這個動作你需要定義TEST2內test1的函數體...

function test2(){ 
    var a  =  'a';//Defining a 
    test1();//Calling test1() 

    function test1(){ 
     alert(a);//a is identified here because of function scope 
     alert(b);//b is identified here because it's global 
    } 
} 
+0

感謝IanR,所以只有內部函數可以訪問父類中定義的值而不是被調用的函數。 – netemp

+0

是的 - 就是這樣。 – IanR

0

根據你的職責,你已經宣佈和函數中定義的變量「一個」「test2()「,因此變量」a「的範圍受限於該函數本身,訪問該變量將返回」undefined「。但它不是全局聲明和定義的變量「b」的情況,所以它可以在腳本部分的任何地方訪問。

希望這可以幫助你。

2

這是一個很好的做法,調用函數與參數。這將使您的代碼易於閱讀和維護。只需添加函數的參數使代碼工作:

function test1(a,b){ 
    alert(a); 
    alert(b); 
} 

function test2(b){ 
    var a = 'a'; 
    test1(a,b); 
} 
var b = 'b'; 
test2(b); 

如果我想知道我在函數聲明使用參數,一個解決方案是使用arguments object裏面的代碼:

function test1(){ 
    alert(arguments[0]); 
    alert(arguments[1]); 
} 

function test2(){ 
    var a = 'a'; 
    test1(a,arguments[0]); 
} 
var b = 'b'; 
test2(b); 

如果你想要你可以製作arguments with default values。由於在JavaScript中,你不能老是在函數參數列表做到這一點,它在函數體完成:

function test1(a,b){ 
    a = a || 'a'; 
    b = b || 'b'; 
    alert(a); 
    alert(b); 
} 
function test2(b){ 
    var a = 'a'; 
    test1(a);//here b is not passed to the function and b will get the default value 
} 
var b = 'some new string for b'; 
test2(b); 

住在jsfiddle

+0

您分享的方法很好。謝謝。 – netemp

+0

如果你喜歡它,你可以upvote :) – Bakudan