日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

js - 执行上下文和作用域以及闭包

發布時間:2023/12/18 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 js - 执行上下文和作用域以及闭包 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

首先,咱們通常被"執行上下文","執行上下文環境","上下文環境","執行上下文棧"這些名詞搞混。那我們一一來揭秘這些名字的含義。

這一塊一直比較晦澀難懂,還是需要仔細去斟酌斟酌。

什么是執行上下文(也叫做“執行上下文環境”,“上下文環境”)?

咱們還是先看代碼。

console.log(a) // undefined var a = 100fn('bella') // 'bella' 20 function fn(name) {age = 20console.log(name, age)var age }console.log(b); // 這里報錯 // Uncaught ReferenceError: b is not defined

第一個console輸出 undefined,說明瀏覽器在執行console.log(a)的時候,已經知道a的存在的,但是不知道a的值。

第二個fn("bella")輸出 "bella" 20,說明瀏覽器在執行的時候已經知道fn函數了,并且執行了

第三個console報錯,b is noe defined。說明沒有找到b

那么可以看出來,瀏覽器在執行之前做了一些準備工作。

那做了些什么準備工作:

  • 全局上下文環境: 變量定義,函數聲明
  • 函數上下文環境(函數內部):變量定義,函數聲明,this,arguments

下面這個例子很多地方都用來講解執行上下文和上下文棧。

1 // 這是一個壓棧出棧的過程--執行上下文棧 2 let a = 10; // 1、進入全局上下文環境 3 let fn; 4 let bar = function(x) { 5 let b = 5 6 fn(x + b) // 3、進入fn函數上下文環境 7 }; 8 fn = function(y) { 9 let c = 5 10 console.log(y + c) 11 } 12 13 bar(10) // 2、 進入bar函數上下文

?這里引出了執行上下文棧的概念,上下文棧就是壓棧和出棧的過程。

1.在代碼執行之前,首先創建全局上下文環境

// 全局上下文環境 a: undefinedfn: undefinedbar: undefined,
this: window

2.然后執行代碼,在代碼執行到12之前,全局上下文中的變量在執行中被賦值

// 全局上下文環境a: 10fn: functionbar: function,
this: window

然后執行13行代碼,調用bar函數,會創建一個新的執行上下文環境。并將這個bar上下文環境壓棧,并設置為活動狀態

// bar函數上下文環境 b: undefinedx: 10arguments: [10]
this: window

3.然后執行到第6行代碼,調用fn的時候,會創建一個新的執行上下文。并將這個fn上下文環境壓棧,并設置為活動狀態。

// fn函數上下文環境 c: undefined y: 15 arguments: [15]
this: window

4.fn執行完畢后,調用fn函數生成的fn上下文環境出棧,銷毀。然后bar出棧銷毀。然后全局上下文出棧銷毀

?

?

理解完了執行上下文,再看看this

相信都知道這句話,誰調用函數,this就指向誰。那么我們理解下this:

var a = {name: 'A',fn: function() {console.log(this.name)}}a.fn() // this === a a.fn.call({name: 'B'}) // this === {name: 'B'}var fn1 = a.fnfn1() // this === window

this: this的值只有在執行的時候才能確認,定義的時候不能確認。因為this是執行上下文的一部分,而執行上下文需要再代碼執行之前確定。

this執行會有不同,主要集中在這幾個場景中:
  • 作為構造函數執行,構造函數中
  • 作為對象屬性執行,上述代碼中a.fn()
  • 作為普通函數執行,上述代碼中fn1()
  • 用于call apply bind,上述代碼中a.fn.call()
  • 作用域


    ES6之前沒有塊級作用域,除了全局作用域,函數會創建自己的作用域。 作用域在函數定義的時候已經確定了,不是在函數調用確定(區別于執行上下文環境,this是執行上下文環境中的) 作用域只是一個“地盤”,其中沒有變量。變量是通過作用域對應的執行上下文環境中的變量對象來實現的。所以作用域是靜態的,而執行上下文是動態的。 有閉包存在的時候,一個作用域存在兩個上下文環境也是有的。 也就是說,作用域只是用于劃分你在這個作用域里面定義的變量的有效范圍,出了這個范圍就無效

    作用域鏈

    函數在定義的時候就確定了函數體內部自由變量的作用域 自由變量:比如a,在fn作用域使用,但是并沒有在fn作用域定義。這就是自由變量 let a = 100 function fn() {let b = 20function bar() {console.log(a + b) // a是自由變量}return bar }let x = fn(), b = 200 x() 那么自由變量是如何得到的?這就引出了作用域鏈 bar要取得a的值,就要在bar函數的作用域中取值,如果沒有,就往上找,找到fn作用域內,也沒有定義a,繼續往上找,就找到全局作用域,找到就結束了。這就是作用域鏈 講完這些,我們再通過一個例子來理解閉包 1 function F1() { 2 var a = 100 3 return function () { 4 console.log(a) 5 } 6 } 7 var f1 = F1() 8 var a = 200 9 f1()

    ?

    自由變量將從作用域鏈中去尋找,但是 依據的是函數定義時的作用域鏈,而不是函數執行時,以上這個例子就是閉包。 怎么理解依據的是函數定義時的作用域鏈,而不是函數執行時這句話? 調用第9行之后 如果按照執行時,就輸出的時200 但是作用域都是在定義時就生成了,所以f1回去再定義function的作用域去找,因此輸出100. 理解閉包之后,我們就看看閉包的主要場景:
    • 函數作為返回值,上面的例子就是
    • 函數作為參數傳遞

    ?

    轉載于:https://www.cnblogs.com/thonrt/p/10333581.html

    總結

    以上是生活随笔為你收集整理的js - 执行上下文和作用域以及闭包的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。