亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

詳解JavaScript中的作用域

 更新時(shí)間:2023年08月31日 09:15:44   作者:阿宇的編程之旅  
作用域是JavaScript中一個(gè)重要的概念,它決定了變量和函數(shù)在代碼中的可訪問(wèn)性和可見(jiàn)性,了解JavaScript的作用域?qū)τ诰帉懜咝А⒖删S護(hù)的代碼至關(guān)重要,本文將深入介紹JavaScript作用域相關(guān)的知識(shí)點(diǎn),其中包括作用域類型,作用域鏈,變量提升以及閉包等

什么是作用域

JS中的作用域是一個(gè)存儲(chǔ)變量、函數(shù)以及對(duì)象的位置,每個(gè)變量、函數(shù)和對(duì)象都被存儲(chǔ)在一個(gè)特定的作用域中,它是指變量和函數(shù)在代碼中的可訪問(wèn)范圍,作用域決定了代碼中哪些部分可以訪問(wèn)特定的變量和函數(shù),通過(guò)作用域,我們可以將變量和函數(shù)封裝在不同的作用域中,使其在合適的范圍內(nèi)可訪問(wèn)

就像上圖中的示例,F(xiàn)oo1無(wú)法獲取Foo2中的var4變量

作用域類型

常見(jiàn)的作用域類型包括全局作用域(Global Scope)、局部作用域(Local Scope)和塊級(jí)作用域(Block Scope),JS也不例外

全局作用域

全局作用域是在整個(gè)代碼中都可訪問(wèn)的作用域。在瀏覽器環(huán)境中,全局作用域通常是指window對(duì)象;在node環(huán)境下,則是globalThis或global

在全局作用域中聲明的變量或函數(shù)是全局變量或全局函數(shù),在代碼任何地方都可以訪問(wèn)和使用

比如上面圖示中的Foo4可以訪問(wèn)到全局作用域的變量及函數(shù)

const var1 = "var1";
const var2 = "var2";
function Foo1() {
  const var3 = "var3";
}
function Foo2() {
  const var4 = "var4";
  function Foo3() {}
}
function Foo4() {
  console.log(var1, var2, Foo1, Foo2); // var1 var2 [Function: Foo1] [Function: Foo2]
}
Foo4();

局部作用域

JS中的局部作用域一般代指函數(shù)作用域(Function Scope),它是在函數(shù)內(nèi)部聲明的作用域,函數(shù)內(nèi)部的變量和函數(shù)只能在函數(shù)內(nèi)部訪問(wèn),外部無(wú)法直接訪問(wèn)

就像上述Foo3的效果,可以訪問(wèn)到全局以及當(dāng)前所在函數(shù)的作用域的變量及函數(shù)

const var1 = "var1";
const var2 = "var2";
function Foo1() {
  const var3 = "var3";
}
function Foo2() {
  const var4 = "var4";
  function Foo3() {
    console.log(var4, Foo3); // var4 [Function: Foo3]
  }
  Foo3();
}
Foo2();

塊級(jí)作用域

塊級(jí)作用域是在代碼塊(通常是由大括號(hào){}包裹起來(lái)的部分)內(nèi)聲明的作用域。比如if(){...}、for(...){...}、try{...}等

ES6之前

在ES6之前,由于變量都是使用var聲明的,所以沒(méi)有塊級(jí)作用域此類概念,只有全局作用域和函數(shù)(局部)作用域。那么需要模擬塊級(jí)作用域如何怎么操作呢?

答案是使用立即執(zhí)行函數(shù)表達(dá)式(IIFE):通過(guò)將代碼包裝在匿名函數(shù)中并立即執(zhí)行該函數(shù),可以創(chuàng)建一個(gè)獨(dú)立的作用域,使得內(nèi)部聲明的變量在函數(shù)外部不可訪問(wèn)

(function () {
  var var5 = "var5";
  console.log(var5); // var5
})();
console.log(var5); // var5 is not defined

ES6以后

在es6以后,官方推出了塊級(jí)作用域的概念,使用let和const關(guān)鍵字聲明的變量具有塊級(jí)作用域,它們只能在聲明的代碼塊內(nèi)部訪問(wèn)。

if (true) {
  let var5 = "var5";
  console.log(var5); // var5
}
console.log(var5); // var5 is not defined

作用域鏈

作用域鏈(Scope Chain)是JS用于解析標(biāo)識(shí)符(變量和函數(shù))的機(jī)制,它是由多個(gè)嵌套的作用域組成的,它決定了變量和函數(shù)的查找順序。

上面我們說(shuō)到局部作用域時(shí)談到的Foo3可以訪問(wèn)全局以及當(dāng)前函數(shù)作用域中的標(biāo)識(shí)符這個(gè)特點(diǎn)就歸功于作用域鏈這個(gè)概念。當(dāng)訪問(wèn)一個(gè)變量時(shí),JS引擎會(huì)先從當(dāng)前作用域開(kāi)始查找,如果找不到這個(gè)名稱的標(biāo)識(shí)符則繼續(xù)向上一級(jí)作用域查找,直到找到變量或達(dá)到全局作用域?yàn)橹?,如果在全局作用域中仍然找不到,則認(rèn)為該標(biāo)識(shí)符未定義。

變量提升

變量提升的概念出現(xiàn)在面試題中的頻率十分高,對(duì)于開(kāi)發(fā)者來(lái)說(shuō)也是不可忽略的重要知識(shí)點(diǎn);

基礎(chǔ)概念

變量提升是JS在代碼執(zhí)行前將變量和函數(shù)聲明提升到作用域頂部的行為,它由JavaScript引擎在代碼執(zhí)行前的編譯階段處理。變量提升影響了整個(gè)作用域范圍內(nèi)的代碼,它允許我們?cè)诼暶髦笆褂米兞?,但是需要注意一點(diǎn):只有變量聲明被提升,賦值不會(huì)提升。了解了上述概念后,我們思考下面的代碼:

console.log(var6); // undefined
var var6 = 10;

上面的代碼相當(dāng)于

var var6;
console.log(var6); // undefined
var6 = 10;

優(yōu)先級(jí)問(wèn)題

當(dāng)同一個(gè)作用域中同時(shí)出現(xiàn)同名的函數(shù)和變量時(shí),函數(shù)提升的優(yōu)先級(jí)更高,也就是說(shuō)函數(shù)會(huì)在變量之上聲明,參考下面的代碼

var a = 10;
function a() {}
console.log(a); // 10

可以看成是

var a; // 函數(shù)a
var a; // 變量a
a = function () {};// 使用function聲明函數(shù)可以看成是聲明+賦值
a = 10;
console.log(a); // 10

何以見(jiàn)得?思考以下代碼

function a() {}
var a;
console.log(a); // [Function: a]

當(dāng)把a(bǔ)的賦值去除時(shí),函數(shù)的賦值順序就可以得到驗(yàn)證,相當(dāng)于:

var a; // 函數(shù)a
var a; // 變量a
a = function () {};
console.log(a); // [Function: a]

閉包

定義

當(dāng)函數(shù)開(kāi)始執(zhí)行時(shí),函數(shù)中的變量以及函數(shù)會(huì)壓入棧中,那么此時(shí)如果當(dāng)前的作用域中有另一個(gè)函數(shù)正在使用該作用域的變量,該變量占用的內(nèi)存也不會(huì)被垃圾回收機(jī)制回收,這個(gè)現(xiàn)象就是閉包

換句話說(shuō),閉包是指函數(shù)能夠"記住"并訪問(wèn)其創(chuàng)建時(shí)的詞法環(huán)境,在函數(shù)定義的詞法作用域之外執(zhí)行同樣適用

思考以下代碼

const foo = (function iife() {
  const num = 10;
  function foo() {
    return num;
  }
  return foo;
})();
console.log(foo()); // 10

上述代碼中使用立即執(zhí)行函數(shù)iife作為外部函數(shù)的作用域,它返回內(nèi)部函數(shù)foo,而foo函數(shù)使用了iife函數(shù)中的num變量,形成了閉包,最后在iife函數(shù)的外部使用foo時(shí)依然可以訪問(wèn)num變量

特點(diǎn)

  • 即使外部函數(shù)已經(jīng)執(zhí)行完畢,內(nèi)部函數(shù)依然可以訪問(wèn)外部函數(shù)作用域中的變量(當(dāng)棧將函數(shù)彈出時(shí),變量依然處于內(nèi)存中)
  • 閉包可以持有對(duì)外部變量的引用,使得外部變量的值在內(nèi)部函數(shù)中保持活動(dòng)狀態(tài)(不被垃圾回收機(jī)制回收)
  • 閉包中的內(nèi)部函數(shù)可以修改并更新外部變量的值
  • 閉包的函數(shù)可以獲取到創(chuàng)建時(shí)的整個(gè)作用域鏈的標(biāo)識(shí)符
  • 閉包可能會(huì)導(dǎo)致內(nèi)存泄漏,被閉包引用的變量無(wú)法被垃圾回收機(jī)制處理

使用場(chǎng)景

封裝私有變量

JS中沒(méi)有TS的private關(guān)鍵詞,無(wú)法直接定義私有變量,但是可以通過(guò)閉包產(chǎn)生私有環(huán)境作用域(ES2022后引入了#關(guān)鍵字,用于定義私有變量,相比于使用閉包,更直觀和方便)

const Animal = (function () {
  const name = "dog";
  function Animal() {}
  Animal.prototype.getName = function () {
    return name;
  };
  return Animal;
})();
console.log(new Animal().getName()); // dog

延長(zhǎng)變量周期

延長(zhǎng)變量的生命周期也是閉包的特性之一,該效果通過(guò)內(nèi)部函數(shù)對(duì)外部作用域的可訪問(wèn)性實(shí)現(xiàn)

function delayMessage(msg) {
  return function () {
    return msg;
  };
}
const msg = delayMessage("msg");
console.log(msg()); // msg

模塊化、命名空間

我們使用JS中的立即執(zhí)行函數(shù)實(shí)現(xiàn)了命名空間功能,達(dá)到模塊化的效果

var moduleA = (function () {
  var privateVariable = "Hello";
  // 私有函數(shù)
  function privateMethod() {
    console.log(privateVariable);
  }
  return {
    // 公共函數(shù)
    publicMethod: function () {
      privateMethod();
    },
  };
})();
moduleA.publicMethod(); // Hello
console.log(moduleA.privateVariable); // undefined

緩存

閉包還可以用于創(chuàng)建緩存函數(shù),以提高函數(shù)的執(zhí)行效率。緩存函數(shù)可以將輸入?yún)?shù)與其對(duì)應(yīng)的結(jié)果保存在內(nèi)部,避免重復(fù)計(jì)算

function createCache() {
  var cache = {};
  return function (key, val) {
    if (!cache[key]) {
      cache[key] = val;
      console.log("保存");
    }
    return cache[key];
  };
}
var cacheModule = createCache();
cacheModule("num1", "123"); // 保存
cacheModule("num2", "456"); // 保存
cacheModule("num1", "123");
cacheModule("num2", "456");

ES6的作用域

在ES6以后引入了const、let和箭頭函數(shù),這三者對(duì)作用域分別有什么影響呢?

const、let

塊級(jí)作用域

上面說(shuō)到const、let的出現(xiàn)奠定了JS中的塊級(jí)作用域的概念,使if、for等語(yǔ)句中也存在作用域這一功能;然而不僅僅是條件語(yǔ)句、循環(huán)語(yǔ)句,使用{...}定義的范圍都是塊級(jí)作用域,這意味著在塊級(jí)作用域內(nèi)部聲明的變量只在該作用域內(nèi)有效,并且在作用域外部無(wú)法訪問(wèn)

{
  let msg = "hello";
  console.log(msg); // hello
}
console.log(msg); // msg is not defined

變量提升

使用let和const聲明的變量不會(huì)被提升到作用域的頂部,它們只能在聲明后才能被訪問(wèn);這點(diǎn)與var不太一樣

暫時(shí)性死區(qū)

暫時(shí)性死區(qū)指的是在變量聲明前訪問(wèn)變量會(huì)拋出錯(cuò)誤。只有在變量聲明語(yǔ)句執(zhí)行完成之后,變量才會(huì)進(jìn)入有效狀態(tài),才能被訪問(wèn)和使用。這點(diǎn)效果與上面的變量提升效果一樣

不可重復(fù)聲明

在同一個(gè)作用域中不能被重復(fù)聲明,否則會(huì)報(bào)錯(cuò);而使用var定義變量時(shí)后聲明的會(huì)覆蓋先聲明的

這三個(gè)特點(diǎn)可以參考下面的代碼:

console.log(var1); // 在賦值前使用了變量“var1”
const var1 = 11;
let var2 = 22; // 無(wú)法重新聲明塊范圍變量“var2”
let var2 = 22;

箭頭函數(shù)

箭頭函數(shù)在JavaScript中仍然與普通函數(shù)一樣有函數(shù)作用域的概念

題外話

動(dòng)態(tài)作用域與詞法作用域

作用域的種類有兩種:分別是動(dòng)態(tài)作用域和詞法作用域(靜態(tài)作用域)。上述我們介紹的是詞法作用域,什么是詞法作用域?

詞法作用域

詞法作用域是基于代碼的靜態(tài)結(jié)構(gòu)來(lái)確定變量的訪問(wèn)規(guī)則。也就是說(shuō)它由變量和函數(shù)在代碼中的聲明位置而不是調(diào)用的位置來(lái)確定,思考下面的代碼

function foo1() {
  var var1 = 10; // foo2可訪問(wèn)的作用域
  // 聲明foo2的作用域
  return function foo2() {
    console.log(var1);// 10
  };
}
var foo2 = foo1();
function foo3() {
  var var1 = 20; // foo2不可訪問(wèn)的作用域
  // 執(zhí)行foo2的作用域
  foo2();
}
foo3();

在foo1中聲明了函數(shù)foo2,在foo3中執(zhí)行foo2,可以看到,foo2取的var1是聲明foo2的作用域中的變量(10)。這個(gè)現(xiàn)象說(shuō)明JS采用的是詞法作用域。

動(dòng)態(tài)作用域

那么反之,如果還是上述代碼,foo2取的var1是執(zhí)行foo2的作用域中的變量(20),就說(shuō)明語(yǔ)言采用的是動(dòng)態(tài)作用域

總結(jié)

JavaScript作用域與變量提升是編寫高質(zhì)量代碼所必須掌握的重要概念。本文介紹了作用域的定義、作用和目的,以及JavaScript中的不同作用域類型,包括全局作用域、函數(shù)作用域和塊級(jí)作用域。我們還討論了變量提升的概念、原理和影響范圍,以及作用域鏈和閉包的關(guān)系。此外,還探討了ES6的作用域,并對(duì)比了其與早期作用域的區(qū)別。最后針對(duì)動(dòng)態(tài)作用域與詞法作用域作了一個(gè)簡(jiǎn)單的說(shuō)明。

以上就是詳解JavaScript中的作用域的詳細(xì)內(nèi)容,更多關(guān)于JavaScript作用域的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 自己編寫的支持Ajax驗(yàn)證的JS表單驗(yàn)證插件

    自己編寫的支持Ajax驗(yàn)證的JS表單驗(yàn)證插件

    創(chuàng)建一個(gè)JavaScript表單驗(yàn)證插件,可以說(shuō)是一個(gè)繁瑣的過(guò)程,涉及到初期設(shè)計(jì)、開(kāi)發(fā)與測(cè)試等等環(huán)節(jié)。實(shí)際上一個(gè)優(yōu)秀的程序員不僅是技術(shù)高手,也應(yīng)該是善假于外物的。本文介紹的這個(gè)不錯(cuò)的JavaScript表單驗(yàn)證插件,支持ajax驗(yàn)證,有需要的小伙伴可以參考下
    2015-05-05
  • 前端高頻面試題之JS中堆和棧的區(qū)別和瀏覽器的垃圾回收機(jī)制

    前端高頻面試題之JS中堆和棧的區(qū)別和瀏覽器的垃圾回收機(jī)制

    本文給大家分享前端高頻面試題JS中堆和棧的區(qū)別和瀏覽器的垃圾回收機(jī)制,本文分文別類給大家介紹了棧(stack)和堆(heap)的區(qū)別基本類型和引用類型的相關(guān)知識(shí),瀏覽器垃圾回收機(jī)制包括基本概念給大家介紹的非常詳細(xì),需要的朋友參考下吧
    2023-10-10
  • javascript高仿熱血傳奇游戲?qū)崿F(xiàn)代碼

    javascript高仿熱血傳奇游戲?qū)崿F(xiàn)代碼

    這篇文章主要介紹了javascript高仿熱血傳奇游戲的實(shí)現(xiàn)代碼,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • 仿jQuery的siblings效果的js代碼

    仿jQuery的siblings效果的js代碼

    取一個(gè)DOM元素的兄弟節(jié)點(diǎn),仿jQuery的siblings方法,用原生JS代碼完成
    2011-08-08
  • js腳本編寫簡(jiǎn)單刷票投票系統(tǒng)

    js腳本編寫簡(jiǎn)單刷票投票系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了js腳本編寫簡(jiǎn)單刷票投票系統(tǒng),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • JavaScript控制音頻和視頻的播放、暫停、音量

    JavaScript控制音頻和視頻的播放、暫停、音量

    HTML<video>元素用于在HTML或者XHTML文檔中嵌入媒體播放器,用于支持文檔內(nèi)的視頻播放,你也可以將<video>標(biāo)簽用于音頻內(nèi)容,在前端中實(shí)現(xiàn)音頻和視頻播放通常涉及使用HTML5的<audio>和<video>元素以及JavaScript來(lái)控制這些媒體元素的播放、暫停、音量等屬性
    2023-10-10
  • JavaScript實(shí)現(xiàn)簡(jiǎn)單驗(yàn)證碼

    JavaScript實(shí)現(xiàn)簡(jiǎn)單驗(yàn)證碼

    這篇文章主要為大家詳細(xì)介紹了JavaScript實(shí)現(xiàn)簡(jiǎn)單驗(yàn)證碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-08-08
  • 微信小程序上拉加載和下拉刷新功能實(shí)現(xiàn)

    微信小程序上拉加載和下拉刷新功能實(shí)現(xiàn)

    這篇文章主要介紹了微信小程序上拉加載和下拉刷新功能實(shí)現(xiàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧
    2024-06-06
  • javascript 判斷頁(yè)面訪問(wèn)方式電腦或者移動(dòng)端

    javascript 判斷頁(yè)面訪問(wèn)方式電腦或者移動(dòng)端

    這篇文章主要介紹了 判斷頁(yè)面訪問(wèn)方式電腦或者移動(dòng)端的相關(guān)資料,這里提供了三種方法,需要的朋友可以參考下
    2016-09-09
  • JS扁平化輸出數(shù)組的2種方法解析

    JS扁平化輸出數(shù)組的2種方法解析

    這篇文章主要介紹了JS扁平化輸出數(shù)組的2種方法解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-09-09

最新評(píng)論