摘要:在中的應用采用詞法作用域,也就是靜態(tài)作用域。那什么又是詞法作用域或者靜態(tài)作用域呢請繼續(xù)往下看靜態(tài)作用域與動態(tài)作用域因為采用的是詞法作用域函數(shù)的作用域在函數(shù)定義的時候就決定了。
開篇
當我們在開始學習任何一門語言的時候,都會接觸到變量的概念,變量的出現(xiàn)其實是為了解決一個問題,為的是存儲某些值,進而,存儲某些值的目的是為了在之后對這個值進行訪問或者修改,正是這種存儲和訪問變量的能力將狀態(tài)給了程序。我們的程序中到處都充斥著對于狀態(tài)的判斷,根據(jù)不同的狀態(tài)執(zhí)行不同的邏輯。
我們試想一下,如果沒有狀態(tài)這個概念,程序雖然也能夠執(zhí)行一些簡單的任務,但是它會受到很多的限制,所能完成的功能是有限制的,舉個例子,沒有狀態(tài)你是如何執(zhí)行循環(huán)語句?沒有狀態(tài)如何更加優(yōu)雅地使用邏輯結(jié)構(gòu)?
仔細想想,好像是寸步難行,當然引入變量后幫我們解決了這個問題。
但是,引入變量和狀態(tài)的概念之后會引起幾個問題:這些變量住在哪里?換句話說,它們存儲在哪里?最重要的是,程序需要它們的時候如何找到它們?
今天我們就一起學習一下這套存儲和查找變量的規(guī)則,這套規(guī)則我們稱之為:作用域。
作用域我們來拆解一下這個詞語,所謂的“域”我們可以理解為:范圍、區(qū)域,加上“作用”兩個字所要表述的問題就是作用的范圍、區(qū)域,比如國家的行政區(qū)域劃分是為了便于管理,類比到程序源代碼中作用域的出現(xiàn)也是為了便于對于變量做管理。
好,這里我們簡單做一下總結(jié):
定義:作用域是指程序源代碼中定義變量的區(qū)域。
作用:作用域規(guī)定了如何查找變量,也就是確定當前執(zhí)行代碼對變量的訪問權(quán)限。
在javaScript中的應用 :JavaScript采用詞法作用域(lexical scoping),也就是靜態(tài)作用域。
那什么又是 詞法作用域或者靜態(tài)作用域呢?
請繼續(xù)往下看
靜態(tài)作用域與動態(tài)作用域因為javaScript采用的是詞法作用域,函數(shù)的作用域在函數(shù)定義的時候就決定了。
而詞法作用域相對的是動態(tài)作用域,函數(shù)的作用域是在函數(shù)調(diào)用的時候才決定的。
讓我們看一個例子來理解詞法作用域和動態(tài)作用域之間的區(qū)別:
var value = 1; function foo() { console.log(value); } function bar() { var value = 2; foo(); } bar(); // 結(jié)果是 ???
上面的代碼中:
1.我們首先定義了一個value,并賦值為1;
2.聲明一個函數(shù)foo,函數(shù)的功能是打印 value 這個變量的值;
3.聲明一個函數(shù)bar,函數(shù)內(nèi)部重新創(chuàng)建了一個變量 value 這個變量賦值為2;
在函數(shù)內(nèi)部執(zhí)行了 foo() 這個函數(shù);4.執(zhí)行 bar() 這個函數(shù)
假設(shè)javaScript采用靜態(tài)作用域,讓我們分析下執(zhí)行過程:
執(zhí)行foo函數(shù),首先從 foo 函數(shù)內(nèi)部查找是否有變量 value ,如果沒有
就根據(jù)書寫的位置,查找上面一層的代碼,我們發(fā)現(xiàn)value等于1,所以結(jié)果會打印 1。
假設(shè)javaScript采用動態(tài)作用域,讓我們分析下執(zhí)行過程:
執(zhí)行foo函數(shù),依然是從 foo 函數(shù)內(nèi)部查找是否有局部變量 value。如果沒有,
就從調(diào)用函數(shù)的作用域,也就是 bar 函數(shù)內(nèi)部查找 value 變量,所以結(jié)果會打印 2。
上面在區(qū)分靜態(tài)作用于和動態(tài)作用域的時候,我們已經(jīng)說了如果是靜態(tài)作用域,那么函數(shù)在書寫定義的時候已經(jīng)確定了,而動態(tài)作用域是函數(shù)執(zhí)行過程中才確定的。
JavaScript采用的是靜態(tài)作用域,所以這個例子的結(jié)果是 1。
我們在控制臺中輸入執(zhí)行上面的函數(shù),檢驗一下執(zhí)行結(jié)果果然是 1。
那什么語言是采用的動態(tài)的作用域呢? 其實bash 就是動態(tài)作用域,
我們可以新建一個 scope.bash 文件將下列代碼放進去,執(zhí)行一下這個腳本文件:
#!/bin/bash value=1 function foo () { echo $value; } function bar () { local value=2; foo; } bar
上面代碼運行的結(jié)果輸出2很好解釋,雖然在代碼最上層定義了 value并賦值為1,但是在調(diào)用foo函數(shù)的時候,在查找 foo 內(nèi)部沒有 value 變量后,會在foo 函數(shù)執(zhí)行的環(huán)境中繼續(xù)查找,也就是在bar 函數(shù)中查找,很幸運我們找到了。
思考最后,讓我們看一個《JavaScript權(quán)威指南》中的例子:
// 例1: var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f(); } checkscope(); // 例2: var scope = "global scope"; function checkscope(){ var scope = "local scope"; function f(){ return scope; } return f; } checkscope()();
讓我們來分析一下上面例1的代碼:
1、定義一個變量 scope 并賦值 global scope;
2、聲明一個函數(shù) checkscope ,在這個函數(shù)中 定義一個變量 scope 并賦值 local scope;
3、在checkscope 函數(shù)中 又定義一個函數(shù) f ,這個函數(shù) 只做了一件事:返回scope 這個變量;
4、最后返回并執(zhí)行 f 這個函數(shù);
5、調(diào)用checkscope
按照我們上面解釋的javaScript中靜態(tài)作用域理解,在執(zhí)行 checkscope 這個函數(shù)的時候在函數(shù)內(nèi)部執(zhí)行的是f 這個函數(shù),首先在 f 這個函數(shù)內(nèi)部查找 scope 這個變量發(fā)現(xiàn)沒有,繼續(xù)在定義函數(shù)f的上面一層查找,發(fā)現(xiàn)在checkscope 這個函數(shù)作用域內(nèi) 找到了scope的值 直接返回,至于 checkscope外面定義的scope沒有理睬。
讓我們來分析一下上面例2的代碼:
1、定義一個變量 scope 并賦值 global scope;
2、聲明一個函數(shù) checkscope 在這個函數(shù)中 定義一個變量 scope 并賦值 local scope;
3、在checkscope 函數(shù)中 又定義一個函數(shù) f 這個函數(shù) 只做了一件事:返回scope 這個變量;
4、最后單純的返回 f 這個函數(shù);
5、調(diào)用checkscope
按照我們上面解釋的javaScript中靜態(tài)作用域理解,在執(zhí)行 checkscope 這個函數(shù)的時候在函數(shù)內(nèi)返回了函數(shù)f實際是在最外面調(diào)用的f但是由于javaScript是采用的詞法作用域,因此函數(shù)的作用域基于函數(shù)創(chuàng)建的位置。
而引用《JavaScript權(quán)威指南》的回答就是:
JavaScript 函數(shù)的執(zhí)行用到了作用域鏈,這個作用域鏈是在函數(shù)定義的時候創(chuàng)建的。嵌套的函數(shù) f() 定義在這個作用域鏈里,其中的變量 scope 一定是局部變量,不管何時何地執(zhí)行函數(shù) f(),這種綁定在執(zhí)行 f() 時依然有效。
但是在這里真正想讓大家思考的是:
雖然兩段代碼執(zhí)行的結(jié)果一樣,但是兩段代碼究竟有哪些不同呢?
敬請期待下面一篇關(guān)于javaScript 中的執(zhí)行上下文棧的相關(guān)內(nèi)容。
參考:
1、《你不知道的Javascript上卷》
2、JavaScript深入之詞法作用域和動態(tài)作用域
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/101512.html
摘要:作用域作用域是指程序源代碼中定義變量的區(qū)域。采用詞法作用域,也就是靜態(tài)作用域。而與詞法作用域相對的是動態(tài)作用域,函數(shù)的作用域是在函數(shù)調(diào)用的時候才決定的。前面我們已經(jīng)說了,采用的是靜態(tài)作用域,所以這個例子的結(jié)果是。 JavaScript深入系列的第二篇,JavaScript采用詞法作用域,什么語言采用了動態(tài)作用域?兩者的區(qū)別又是什么?還有一個略難的思考題,快來看看吧。 作用域 作用域是指...
摘要:開篇作用域是每種計算機語言最重要的基礎(chǔ)之一,因此要想深入的學習作用域和作用域鏈就是個繞不開的話題。這樣由多個執(zhí)行上下文的變量對象構(gòu)成的鏈表就叫做作用域鏈。這時候執(zhí)行上下文的作用域鏈,我們命名為至此,作用域鏈創(chuàng)建完畢。 開篇 作用域是每種計算機語言最重要的基礎(chǔ)之一,因此要想深入的學習JavaScript,作用域和作用域鏈就是個繞不開的話題。 在《深入學習js之—-執(zhí)行上下文棧》中我們提到...
摘要:函數(shù)作用域和塊作用域前面講了是詞法作用域,那么什么時候會創(chuàng)建作用域呢主要是基于函數(shù)級別的作用域,也就是每一個函數(shù)都會創(chuàng)建一個作用域。函數(shù)會被當作函數(shù)表達式而不是一個標準的函數(shù)聲明來處理。 什么是作用域 來一段《你不知道的JavaScript-上卷》中的原話: 幾乎所有編程語言最基本的功能之一,就是能夠儲存變量當中的值,并且能在之后對這個 值進行訪問或修改,這些變量住在哪里?換句話說,它...
摘要:下面,讓我們以一個函數(shù)的創(chuàng)建和激活兩個時期來講解作用域鏈是如何創(chuàng)建和變化的。這時候執(zhí)行上下文的作用域鏈,我們命名為至此,作用域鏈創(chuàng)建完畢。 JavaScript深入系列第五篇,講述作用鏈的創(chuàng)建過程,最后結(jié)合著變量對象,執(zhí)行上下文棧,讓我們一起捋一捋函數(shù)創(chuàng)建和執(zhí)行的過程中到底發(fā)生了什么? 前言 在《JavaScript深入之執(zhí)行上下文棧》中講到,當JavaScript代碼執(zhí)行一段可執(zhí)行代...
摘要:在代碼執(zhí)行時,對應的作用域鏈常常是保持靜態(tài)的。當語句執(zhí)行完畢后,會把作用域鏈恢復到原始狀態(tài)。在全局作用域中創(chuàng)建的函數(shù),其作用域鏈會自動成為全局作用域中的一員。 列表項目 前言 學習了javascript已經(jīng)很久了,關(guān)于這個語言中的這兩個特性也是早已耳熟能詳,但是在實際的使用的過程中或者是遇到相關(guān)的問題的時候,還是不能很好的解決。因此我覺得很有必要深入的學習并且記錄這個問題,以便在今后的...
閱讀 2056·2021-10-08 10:04
閱讀 3086·2021-09-22 10:02
閱讀 2236·2019-08-30 15:56
閱讀 829·2019-08-30 15:54
閱讀 925·2019-08-30 15:54
閱讀 1280·2019-08-30 15:53
閱讀 2512·2019-08-30 11:21
閱讀 3561·2019-08-30 10:56