亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

通過JS運行機制的角度說說作用域

發布時間:2020-09-16 23:14:19 來源:腳本之家 閱讀:147 作者:不思 欄目:web開發

前言

任何程序設計語言都有作用域的概念,簡單的說,作用域就是變量與函數的可訪問范圍。JS中的作用域、閉包、this機制和原型往往是最難理解的概念之一。筆者將通過幾篇文章和大家談談自己的理解,希望對大家的學習有一些幫助。如果有什么理解偏差的地方,希望大家可以評論指出,相互學習。

有過一定編程經驗的同學,一定不會對作用域感到陌生,在C/C++/Java中等語言中,作用域從來沒有JavaScript中的作用域那樣令人困惑以致于成為一個大多數JS開發者都難以跨過的門檻。

作用域形成機制

JS中存在的三種作用域類型:全局作用域,函數作用域和ES6中新加入的塊級作用域。

var a = 1;

function foo() {
 var b = 2;
 console.log(a);		// 1
 console.log(b);		// 2
 console.log(c);		// ReferenceError
}

function foo1() {
 var c = 3;
 console.log(a);		// 1
 console.log(b);		// ReferenceError
 console.log(c);		// 3
}

console.log(a);			// 1
console.log(b); 		// ReferenceError
console.log(c);			// ReferenceError
foo();
foo1();

從上面的例子可以看到,每個函數內部形成了屬于自己的作用域,函數內部聲明的變量僅僅在定義的函數內部才可以訪問。全局作用域中可以訪問到的有a,foo,foo作用域中可以訪問到的有b,foo,a,foo1的作用域中可以訪問到的有c,foo,a。因為foo的作用域嵌套在全局作用域之中,當console.log(a);執行的時候,JS在foo的作用域查找不到a,就會到它的上層(這里是foo的上層直接就是全局作用域)查找,發現這里聲明了一個a,將它的值打印了出來。這種從里到外的查找就是根據作用域鏈查找。foo1和foo的作用域沒有嵌套關系,所以相互隔離。

如果函數中使用了未聲明的變量怎么辦?

function foo() {
	a = 2;
}

foo();
console.log(a);		// 2

JS引擎在foo中查找不到a的聲明,便會到它的上層(這里是全局作用域中)查找,這個時候還是沒有查找到a的聲明,在非嚴格模式下,JS引擎會在全局中自動聲明一個a,這個時候,未經聲明的變量a實際上泄漏到了全局作用域中。

只有使用未聲明的變量才會出現變量泄漏的問題么,其實,不僅僅這種寫法會出現,更常見的也會出現在for循環和if代碼塊中也會出現。

for(var i=1;i<10;i++) {
 console.log(i);
}

console.log(i);		// 10,	這里的i泄漏到了全局作用域中

if(true) {
 var a = 2;
}

console.log(a);		// 2, 這里的a也泄漏到了全局變量之中

如果你學習過C語言系列的語法,往往很容易感到困惑,if和for居然沒有作用域,這真是太奇怪了。這一切的問題的根源,都是由于ES6之前沒有塊級作用域導致的。所以可想而知,if包裹的代碼塊,同樣里面的聲明也是暴露出來的~

一切問題的解決直到ES6中引入了let和const得以完美的解決。使用let和const,將可以使用塊級作用域,使得聲明變量泄漏的問題得以解決。

for(let i=1;i<10;i++) {
 console.log(i);
}

console.log(i);		// ReferenceError

if(true) {
 let a = 2;
}

console.log(a);		// ReferenceError

聲明提升機制

對于在JS中聲明的不論是變量還是函數,基本上都會存在著變量聲明提升的行為,將變量的聲明提升到所在作用域的頂端。ES6中的let和const不會,在未聲明之前都不可以使用。

看看下面的代碼

console.log(a);				// undefined
console.log(b);				// undefined
console.log(foo);			// Function
console.log(foo2);		// ReferenceError

function foo () {
 console.log('聲明提升了哈');
}

var a = 1;

var b = function foo2() {
 console.log('不同的函數聲明方式提升的結果也不一樣哦');
};

JS 引擎解釋這段代碼之前首先對代碼中所有的變量進行了聲明的提升,函數聲明的提升的優先級是高于普通變量的,函數聲明會整個提升到所在作用域的頂端(但是以函數表達式方式聲明的函數不會),代碼實際上是下面這個樣子:

function foo () {
 console.log('聲明提升了哈');
}
var a;
var b;
var foo2;

console.log(a);
console.log(b);
console.log(foo);
console.log(foo2);

b = function foo2 () {
 console.log('不同的函數聲明方式提升的結果也不一樣哦');
}

靜態作用域機制(詞法作用域)

關于JS中的作用域,需要明確的一點就是,JS中只存在靜態作用域(詞法作用域)。靜態作用域是什么意思呢?意思就是它的作用域在你寫下代碼的時候就已經確定了,和函數的調用順序無關,了解這一點。就可以對一些常見的現象進行解釋。

var a = 2;
function foo() {
 console.log(a);
}

var obj = {
 a: 3,
 foo: foo
}

obj.foo();		// 2

foo中的a在代碼寫完時就確認了,指向了全局作用域中的a,一旦確定就無法更改了。同理,下面的代碼

function foo() {
 console.log(b);			// ReferenceError
}

function foo1 () {
 var b = 1;
 foo();
}

foo1();

這里,JS引擎在全局作用域中查找不到b,所以會拋出一個異常。所以可以明確的道理是,foo的作用域和foo1的作用域仍然是相互獨立的,不會因為調用時候的順序而更改作用域的嵌套順序,靜態作用域在代碼書寫時就已經確定無法更改了,明白這一點在分析JS代碼的時候尤為重要。

坑外話

變量的遮蔽效應

在函數中定義的變量會遮蔽上層作用域中同名的變量,兩個變量互不影響。

var a = 1;
function foo() {
 var a = 2;
 console.log(a);	// 2
}
console.log(a);		// 1

Try-Catch 中的塊級作用域

try-catch的catch中會創建一個塊級作用域,該作用域內變量的表現同樣遵守變量的聲明提升規則。

try {
 throw undefined;
}catch(e) {
 a = 1;
 console.log(e);		// undefined
}

console.log(a);			// 1,	變量提升規則
console.log(e);			// ReferenceError,catch的塊作用域中定義的變量

隱式聲明

以參數形式傳入的變量在函數內部實際上存在的隱式的聲明,使用時不算作未聲明的變量。

function foo(a) {
 a = 1;
 console.log(a);
}

foo();						// 1
console.log(a);		// ReferenceError

本來想一篇文章寫完作用域和閉包的,想例子實在是累,就拆作兩篇吧,逃~

總結

以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,謝謝大家對億速云的支持。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

登封市| 垫江县| 牟定县| 阳山县| 英吉沙县| 襄垣县| 广宁县| 西畴县| 富蕴县| 土默特右旗| 阿合奇县| 武宣县| 金阳县| 抚州市| 广灵县| 融水| 襄樊市| 香河县| 茌平县| 游戏| 万载县| 平乡县| 长岛县| 宁晋县| 淳安县| 威远县| 合江县| 宣汉县| 泾川县| 岫岩| 东乡族自治县| 瑞金市| 宝丰县| 定远县| 鄂托克前旗| 宕昌县| 阿城市| 克东县| 云阳县| 乳山市| 凉城县|