摘要:我們再來看一下第一段代碼小紅小黑腳本出錯腳本出錯在這段代碼中變量與函數,都擁有局部作用域。作用域鏈的最前端,始終都是當前執行代碼所在的作用域的變量對象。
全局作用域個人博客原址
無論什么語言中,作用域都是一個十分重要的概念,在JavaScript中也不例外,作用域定義了變量或者函數有權訪問的范圍,決定了它們各自的行為。要理解JavaScript中的作用域首先就要知道:在let出現之前,JS中變量的作用域只有兩種:全局作用域和局部作用域。(本文也只討論這兩種作用域)
全局作用域是最外圍的一個執行環境,可以在代碼的任何地方訪問到。在瀏覽器中,我們的全局作用域就是window。因此在瀏覽器中,所有的全局變量和函數都是作為window對象的屬性和方法創建的。
下面就來看看全局作用域的創建方式:
全局變量與全局函數
var name = "小紅"; function doSomething(){ var anotherName = "小黑"; function showName(){ console.info(name) console.info(anotherName) } showName(); } console.info(name);//小紅 console.info(anotherName);//【腳本出錯】 doSomething();//小紅---小黑 showName();//【腳本出錯】
通過代碼可以很清楚的看出來,我在前面所說的 作用域定義了變量或者函數有權訪問的范圍 ,在這里我們定義了一個全局的變量name與全局函數doSomething(),他可以在任何地方被直接訪問。但是我們又在函數內部創建了變量anotherName與函數showName(),通過代碼中的調用情況可以發現,我們在外部調用它時提示【腳本出錯】,因為他們處于局部作用域內(稍后講),而 外部環境不能訪問內部環境的任何變量與函數。這就涉及到了作用域的概念(稍后講)
未聲明直接定義的變量
function showName() { var fullName = "小紅"; anotherName = "小黑"; console.info(fullName) } showName();//小紅 console.info(anotherName);//小黑 console.info(fullName);//【腳本出錯】
在這樣的情況下,變量anotherName擁有全局作用域,而fullName在函數外部無法訪問到。(注:在高程中明確說明,不聲明而直接初始化變量是錯誤做法,應該避免這樣的情況嚴格模式下,初始化未聲明的變量將報錯)
所有window對象上的屬性都具有全局作用
這個實際上在上面已經提到了:所有的全局變量和函數都是作為window對象的屬性和方法創建的。,自然window對象它本身所具有的屬性和方法,同樣是處于全局作用域,例如:window.location,window.name等等。
局部作用域其實在上面的代碼中,為了展示全局作用域的效果,我們就已經創造了局部作用域。局部作用域和全局作用域正好相反,局部作用域一般只在固定的代碼片段內可訪問到,最常見的就是函數內部,所以在很多地方就會有人把它稱為函數作用域。(記住let之前無塊級作用域)。我們再來看一下第一段代碼:
var name = "小紅"; function doSomething(){ var anotherName = "小黑"; function showName(){ console.info(name) console.info(anotherName) } showName(); } console.info(anotherName);//【腳本出錯】 showName();//【腳本出錯】
在這段代碼中變量 anotherName,與函數 showName(),都擁有局部作用域。因此它不能被外部所訪問,那么問題就來了,為什么全局變量他就能在局部作用域內被訪問到呢?這就是 JavaScript 中的作用域鏈概念!
作用域鏈在JS中:”一切皆是對象, 函數也是”。
在 JavaScript 中,每個函數都有著自己的作用域,在每次調用一個函數的時候 ,就會進入一個函數內的作用域,而當函數執行返回以后,就返回調用前的作用域。
當代碼在一個作用域內執行時,就會根據其上下文創建一個作用域鏈,該作用域鏈的用途就是控制當前作用域對于內所有的變量與函數的有序訪問。作用域鏈的最前端,始終都是當前執行代碼所在的作用域的變量對象。
var name = "小紅"; function changeName(){ if(name ==="小紅"){ name="小黑"; }else{ name ="小紅"; } } changeName(); console.info("新名字:"+name);//小黑
在這個例子中,changName()被定義在全局作用域下,他的作用域鏈包含著包含兩個對象:1.它本身的變量對象(函數都會包含arguments對象),2.全局環境對象。之所以能在函數內部訪問到變量name,就是因為在它的作用域中,能找到它。(JS的標識符解析,是沿著作用域鏈一級一級的查找搜索的過程,從作用域鏈的最前端開始直到全局環境,最終沒有查找到時將報錯。)我們再回過頭來稍微改一下第一段代碼:并且看看他們能訪問到那些變量:
var name = "小紅"; function doSomething(){ var anotherName = "小黑"; function showName(){ var author ="三省吾身丶丶"; console.info(name) console.info(anotherName) // 在這里可以訪問到 name 、anotherName 、author } showName(); // 在這里可以訪問到 name anotherName ,不能訪問到 author } doSomething(); // 在這里只能訪問到 name
要想理解這種作用域其實也很簡單,作用域就像是一架 每一個臺階都是相對封閉(同級),并且只能上不能下的梯子,在越底層的臺階上,它能走的步數越多(作用域鏈越長)。為了找到它想要的東西,就開始爬臺階,每爬一步臺階,都能看到這一級臺階上有什么東西,直到最頂上的那一階。(找到了就帶回去一起玩耍,玩完了之后還得換回去,要是最后都沒找到就掉下去摔死了)
坑與示例解析在了解坑之前,其實只要記住權威指南里面的一句話,就可以躲過很多這方面的坑了,那就是:JavaScript中的函數運行在它們被定義的作用域里,而不是它們被執行的作用域里
下面就來看看這一個例子:
var name = "小紅"; function showName() { console.info(name); } function show() { var name = "小黑"; showName(); } show();
結果會是什么呢?
小紅
如果你記住并且理解了上面的話,那么應該可以得到這個結果。用作用域鏈的角度解析:執行show()函數時,進入function show(){}的作用域內,然后執行showName()函數,再進入到function showName(){}的作用域內,要輸出name,就在當前作用域找,但是找不到,然后就向上爬一層,在全局環境中找到了var name = "小紅";,所以show()就輸出了小紅。
再來看一個這個例子的改動版本
var name = "小紅"; function show() { var name = "小黑"; function showName() { console.info(name); } showName(); } show();
結果是:小黑
解析:執行show()函數時,進入function show(){}的作用域內,然后執行showName()函數,再進入到function showName(){}的作用域內,要輸出name,就在當前作用域找,發現本身找不到,就向上爬一層到了show()里面,發現已經找到了var name = "小黑";,那么就停止查找,輸出了小黑
。
先到這,不知道有沒有對作用域有了更多的了解呢?感覺有些地方還了解的不夠透徹,希望在開發項目的過程中能有更深的理解。
如果有錯誤之處,請指正。謝謝!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/79954.html
摘要:關于作用域實現的描述任何執行上下文時刻的作用域,都是由作用域鏈來實現的。在一個函數被定義的時候,會將它此時的作用域鏈鏈接到這個函數對象的屬性。參考資料鳥哥作用域原理理解作用域和作用域鏈阮一峰老師微博上的關于作用域的一道題 javascript作用域原理學習 在每次調用一個函數的時候,就會進入一個函數內的作用域,當從函數返回 以后,就會返回調用前的作用域。 ECMA262關于作...
摘要:函數的作用域也可被分為全局作用域和局部作用域函數作用域被定義在指定函數內部的函數被稱為局部函數或內部函數。局部變量在函數內部聲明的變量被成為局部變量,它只能在函數的內部進行訪問。 作用域 概述 變量和函數都具有作用域 作用域就是變量和函數的可被訪問的范圍 控制著變量和函數的可見性和生命周期。變量的作用域可被分為全局作用域和局部作用域(函數作用域) 如果變量是被定義在全局作用域的話 在J...
摘要:閉包是怎么通過作用域鏈霸占更多內存的本文是作者學習高級程序設計第一小節的一點個人理解,詳細教程請參考原教材。函數執行過程創建了一個函數的活動對象,作用域鏈的最前端指向這個對象。函數執行完畢返回值后執行環境作用域鏈和活動對象一并銷毀。 JavaScript 閉包是怎么通過作用域鏈霸占更多內存的? 本文是作者學習《JavaScript 高級程序設計》7.2第一小節的一點個人理解,詳細教程請...
摘要:一前言這個周末,注意力都在學習基礎知識上面,剛好看到了閉包這個神圣的東西,所以打算把這兩天學到的總結下來,算是鞏固自己所學。因此要注意閉包的使用,否則會導致性能問題。五總結閉包的作用能夠讀取其他函數內部變量。 # 一、前言 這個周末,注意力都在學習基礎Js知識上面,剛好看到了閉包這個神圣的東西,所以打算把這兩天學到的總結下來,算是鞏固自己所學。也可能有些不正確的地方,也請大家看到了,麻...
摘要:全局執行環境的變量對象始終是作用域鏈中的最后一個變量對象。綜上,每個函數對應一個執行環境,每個執行環境對應一個變量對象,而多個變量對象構成了作用域鏈,如果當前執行環境是函數,那么其活動對象在作用域鏈的前端。 1.幾個概念 先說幾個概念:函數、執行環境、變量對象、作用域鏈、活動對象。這幾個東東之間有什么關系呢,往下看~ 函數 函數大家都知道,我想說的是,js中,在函數內部有兩個特殊...
閱讀 2472·2021-09-29 09:34
閱讀 3308·2021-09-23 11:21
閱讀 2501·2021-09-06 15:00
閱讀 1128·2019-08-30 15:44
閱讀 2029·2019-08-29 17:23
閱讀 3001·2019-08-29 16:44
閱讀 3060·2019-08-29 13:13
閱讀 1939·2019-08-28 18:12