這篇文章帶給大家的內容是關於ES5中執行環境和作用域的詳細介紹(程式碼範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。
前言:最近在細讀Javascript高級程式設計,對於我而言,中文版,書中很多地方一筆帶過,所以用自己所理解的,嘗試細緻解讀下。如有紕漏或錯誤,會非常感謝您的指出。文中絕大部分內容引用自《JavaScript高級程式設計第三版》
執行環境(execution context)
執行環境(execution context,為了簡單起見,有時也成為環境)是JavaScript中最為重要的概念。
執行環境,定義了變數或函數有權存取其他數據,並決定了它們各自的行為。
每個執行環境都有一個與之關聯的變數物件(variable object),環境中定義的所有變數和函數都保存在這個物件中。
雖然我們寫的程式碼無法存取這個對象,但解析器在處理資料時會在後台使用它。
全域執行環境時最外圍的一個執行環境。
根據ECMAScript實作所在的宿主環境不同,表示執行環境的物件也不一樣。
在網頁瀏覽器中,全域執行環境被認為是window對象,因此所有全域變數和函數都是作為window對象的屬性和方法而創建的。
(變數的生命週期),某個執行環境中的所有程式碼執行完畢後,該環境被銷毀,保存在其中的所有變數和函數定義也隨之銷毀)
全域執行環境直到應用程式退出-例如關閉網頁或瀏覽器時才會被銷毀。
每個函數都有自己的執行環境。當執行流進入函數時,函數的環境就會被推入一個環境堆疊中。在函數執行之後,堆疊將其環境彈出,把控制權傳回給先前的執行環境。 ECMAScript程式中的執行流程正是由這個方便的機制所控制。
作用域鏈(scope chain)
當程式碼在一個環境中執行時,會建立變數物件的一個作用域鏈(scope chain)。
作用域鏈的用途,是保證對執行環境,有權存取的所有變數和函數的有序存取。
作用域鏈的前端,總是目前執行的程式碼所在環境的變數物件。 (也可以理解為「就近原則」)。
如果這個環境是函數,則將其活動物件(activation object)作為變數物件。
函數執行環境中的活動物件在最開始時,只包含一個變量,即arguments物件(這個物件在全域環境中是不存在的)作為變數物件。
作用域鏈中的下一個變數物件來自包含(外部)環境,而再下一個變數物件則來自下一個包含環境,這樣,一直延續到全域執行環境。
全域執行環境的變數對象,總是作用域鏈中的最後一個對象。
標識符解析是沿著作用域鏈一級一級搜尋標識標識符的過程。
搜尋過程總是從作用域鏈的前端開始,然後逐級向後回溯,直到找到標識符為止(如果找不到標識符,通過會導致錯誤發生)。
var color = "blue"; function changeColor() { if(color === "blue") { color = "red"; } else { color = "blue"; } } changeColor(); console.log("Color is now " + color); // "color is now red"
在這個簡單的例子中,函數changeColor()的作用域鏈包含兩個物件:
它自己的變數物件(其中定義著arguments物件)和全域環境的變數物件。
可以在函數內部存取變數color,就是因為可以在這個作用域鏈中找到它。
此外,在局部作用中定義的變數可以在局部環境中與全域變數互換使用。
var color = "blue"; function changeColor() { var anotherColor = "red"; function swapColors(){ //这里可以访问color、anotherColor和tempColor var tempColor = anotherColor; anotherColor = color; color = tempColor; } //这里可以访问color和anotherColor,但不能访问tempColor swapColors(); } //这里只能访问color changeColor();
以上程式碼,涉及3個執行環境:
全域環境(在web瀏覽器中就是window)
函數changeColor()的局部環境
函數swapColors()的局部局部
全域環境中有一個變數color和一個函數changeColor ()。 changeColor()的局部環境中有一個名為anotherColor的變數和一個名為swapColors()的函數,但它也可以存取全域環境中的變數color。 swapColors()的局部環境中有一個變數tempColor,而變數只能在這個環境中存取。
無論全域環境或changeColor()的局部環境都無權存取tempColor。
然而,在swapColors()內部,則可以存取其他兩個環境中的變量,因為那兩個環境是它的父執行環境。
window, color, changeColor() | anotherColor, swapColors() | tempColor
內部環境可以透過作用域鏈存取所有的外部環境,但外部環境無法存取內部環境中的任何變數和函數。
這些環境之間的聯繫是線性、有順序的。
每个环境都可以向上搜索作用域链,以查询变量和函数名。但是,任何环境都不能通过向下搜索作用域链而进入另一个执行环境。
函数参数也被当做变量来对待,因此其访问规则与执行环境中的其他变量相同。
没有块级作用域(ES5中没有)
JavaScript没有块级作用域经常会导致理解上的困惑。
在其他类C的语言中,由花括号封闭的代码块都有自己的作用域(如果用ECMAScript的话来讲,就是它们自己的执行环境),因而支持根据条件来定义变量。
if(true) { var color = "blue"; } console.log(color); //"blue"
这里是在有一个if语句中定义了变量color。
如果是在C、C++或Java中,color会在if语句执行完毕后被销毁。
但在JavaScript中,if语句中的变量声明会将变量添加当前的执行环境(在这里是全局环境window)中。
在使用for语句时尤其要牢记这一差异。
for(var i = 0; i <p>对于有块级作用域的语言来说,for语句初始化变量的表达式所定义的变量,只会存在于循坏的环境之中。而对于JavaScript来说,由for语句创建的变量i即使在for循环结束之后,也依旧会存在于循坏外部的执行环境中。</p><h3 id="声明变量">声明变量</h3><p><strong>使用var声明的变量会自动被添加到最接近的环境中,在函数内部,最接近的环境就是函数的局部环境。</strong></p><p>如果初始化变量时没有使用var声明,该变量会自动被添加到全局作用域。</p><pre class="brush:php;toolbar:false">function add(num1, num2) { var sum = num1 + num2; return sum; } var result = add(10,20); //30 console.log(sum); //sum is not defined
以上代码中的函数add()定义了一个名为sum的局部变量,该变量包含加法操作的结果。
虽然结果值从函数中返回了,但变量sum在函数外部是访问不到的。
如果省略这个例子中的var关键字,那么当add()执行完毕后,sum也将可以访问到。
function add(num1, num2) { sum = num1 + num2; return sum; } var result = add(10,20); // 30 console.log(sum); 30
在这个例子中的变量sum在被初始化赋值时没有使用var关键字。
于是,当调用完add()之后,添加到全局环境中的变量sum将继续存在。
即使函数已经执行完毕,后面的代码依旧可以访问它。
在编写JavaScript代码的过程中,不声明而直接初始化变量时一个常见的错误,这样会导致一些不可预估的意外。养成良好的习惯,在初始化变量之前,一定要先声明,这样就可以避免类似问题。在严格模式下,初始化未经声明的变量会导致错误。
2.查询标识符
当在某个环境中为了读取或写入而引用一个标识符时,必须通过搜索来确定该标识符实际代表什么。搜索过程从作用域链的前端开始,向上逐级查询与给定名字匹配的标识符。
如果在局部环境中找到了该标识符,搜索过程停止,变量就绪。
如果在局部环境中没有找到该变量,则继续沿作用域向上搜索。
搜索过程将一直追溯到全局环境的变量对象。
如果在全局环境中也没有找到这个标识符,则意味着该变量尚未声明。
var color = "blue"; function getColor() { return color; } console.log(getColor()); // "blue" /* window = { color, getColor = function() { return color; } } */
调用本例中的函数getColor()时会引用变量color。
为了确定变量color的值,将开始一个两步的搜索过程。
首先,在getColor()的局部环境中搜索变量对象,查找其中是否包含一个名为color的标识符。
然后,没有找到,对不?那就到外面的环境中找,在全局作用域中找到名为color的标识符。
搜索到了定义这个变量的变量对象,搜索过程宣告结束。
在这个搜索过程中,如果存在一个局部的变量的定义,则搜索会自动停止(找到了,我就不找了),不再进入另一个变量对象。换句话说,如果局部环境中存在着同名标识符,就不会使用位于父环境中的标识符。
var color = "blue"; function getColor() { var color = "red"; return color; } console.log(getColor()); //"red"
修改后的代码在getColor()函数中声明了一个名为color的局部变量。
调用函数时,该变量就会被声明。而当函数中的第二行代码执行时,意味着必须找到并返回变量color的值。
搜索过程,首先从局部环境中开始,而且在这里发现了一个名为color的变量,其值为“red”。
变量已经在函数的局部环境中找到了,所以搜索停止,return语句就使用这个局部变量,并为函数返回“red”。
如果不使用window.color都无法访问全局color变量。
变量查询也不是没有代价的。很明显,访问局部变量要比访问全局变量更快,因为不用向上搜索作用域链。JavaScript引擎在优化标识符查询方面做得不错,因此这个差别在将来恐怕可以忽略不记。
但是,我们还是要养成良好的编程习惯。虽说,这个差别可以忽略不记。
以上是ES5中執行環境和作用域的詳細介紹(程式碼範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

去掉重复并排序的方法:1、使用“Array.from(new Set(arr))”或者“[…new Set(arr)]”语句,去掉数组中的重复元素,返回去重后的新数组;2、利用sort()对去重数组进行排序,语法“去重数组.sort()”。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于Symbol类型、隐藏属性及全局注册表的相关问题,包括了Symbol类型的描述、Symbol不会隐式转字符串等问题,下面一起来看一下,希望对大家有帮助。

怎么制作文字轮播与图片轮播?大家第一想到的是不是利用js,其实利用纯CSS也能实现文字轮播与图片轮播,下面来看看实现方法,希望对大家有所帮助!

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于对象的构造函数和new操作符,构造函数是所有对象的成员方法中,最早被调用的那个,下面一起来看一下吧,希望对大家有帮助。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于面向对象的相关问题,包括了属性描述符、数据描述符、存取描述符等等内容,下面一起来看一下,希望对大家有帮助。

方法:1、利用“点击元素对象.unbind("click");”方法,该方法可以移除被选元素的事件处理程序;2、利用“点击元素对象.off("click");”方法,该方法可以移除通过on()方法添加的事件处理程序。

foreach不是es6的方法。foreach是es3中一个遍历数组的方法,可以调用数组的每个元素,并将元素传给回调函数进行处理,语法“array.forEach(function(当前元素,索引,数组){...})”;该方法不处理空数组。

本篇文章给大家带来了关于JavaScript的相关知识,其中主要介绍了关于BOM操作的相关问题,包括了window对象的常见事件、JavaScript执行机制等等相关内容,下面一起来看一下,希望对大家有帮助。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

SublimeText3漢化版
中文版,非常好用

PhpStorm Mac 版本
最新(2018.2.1 )專業的PHP整合開發工具

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

MantisBT
Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。