<script type="text/javascript">/* //沒塊作用域if(true) {var c = 3}console.log(c)*/var a =10,b =20functionfn(x){var a =100,c =300;console.log('fn()', a, b, c, x)functionbar(x){var a =1000,d =400console.log('bar()', a, b, c, d, x)}bar(100)bar(200)}fn(10)</script>
作用域與執行上下文
區別1
全局作用域之外,每個函數都會創建自己的作用域,作用域在函數定義時就已經確定了。而不是在函數調用時
全局執行上下文環境是在全局作用域確定之后, js代碼馬上執行之前創建
函數執行上下文是在調用函數時, 函數體代碼執行之前創建
區別2
作用域是靜態的, 只要函數定義好了就一直存在, 且不會再變化
執行上下文是動態的, 調用函數時創建, 函數調用結束時就會自動釋放
聯系
執行上下文(對象)是從屬于所在的作用域
全局上下文環境==>全局作用域
函數上下文環境==>對應的函數使用域
<script type="text/javascript">var a =10,b =20functionfn(x){var a =100,c =300;console.log('fn()', a, b, c, x)functionbar(x){var a =1000,d =400console.log('bar()', a, b, c, d, x)}bar(100)bar(200)}fn(10)</script>
作用域鏈
理解
多個上下級關系的作用域形成的鏈, 它的方向是從下向上的(從內到外)
查找變量時就是沿著作用域鏈來查找的
查找一個變量的查找規則
在當前作用域下的執行上下文中查找對應的屬性, 如果有直接返回, 否則進入2
在上一級作用域的執行上下文中查找對應的屬性, 如果有直接返回, 否則進入3
再次執行2的相同操作, 直到全局作用域, 如果還找不到就拋出找不到的異常
<script type="text/javascript">var a =1functionfn1(){var b =2functionfn2(){var c =3console.log(c)console.log(b)console.log(a)console.log(d)}fn2()}fn1()</script>
閉包
如何產生閉包?
當一個嵌套的內部(子)函數引用了嵌套的外部(父)函數的變量(函數)時, 就產生了閉包
閉包到底是什么?
使用chrome調試查看
理解一: 閉包是嵌套的內部函數(絕大部分人)
理解二: 包含被引用變量(函數)的對象(極少數人)
注意: 閉包存在于嵌套的內部函數中
產生閉包的條件?
函數嵌套
內部函數引用了外部函數的數據(變量/函數)
<script type="text/javascript">functionfn1(){var a =2var b ='abc'functionfn2(){//執行函數定義就會產生閉包(不用調用內部函數)console.log(a)}// fn2()}fn1()functionfun1(){var a =3varfun2=function(){console.log(a)}}fun1()</script>
常見的閉包
將函數作為另一個函數的返回值
將函數作為實參傳遞給另一個函數調用
<script type="text/javascript">// 1. 將函數作為另一個函數的返回值functionfn1(){var a =2functionfn2(){a++console.log(a)}return fn2}var f =fn1()f()// 3f()// 4// 2. 將函數作為實參傳遞給另一個函數調用functionshowDelay(msg, time){setTimeout(function(){alert(msg)}, time)}showDelay('atguigu',2000)</script>
閉包的作用
使用函數內部的變量在函數執行完后, 仍然存活在內存中(延長了局部變量的生命周期)
讓函數外部可以操作(讀寫)到函數內部的數據(變量/函數)
問題:
函數執行完后, 函數內部聲明的局部變量是否還存在? 一般是不存在, 存在于閉中的變量才可能存在
在函數外部能直接訪問函數內部的局部變量嗎? 不能, 但我們可以通過閉包讓外部操作它
<script type="text/javascript">functionfn1(){var a =2functionfn2(){a++console.log(a)// return a}functionfn3(){a--console.log(a)}return fn3}var f =fn1()f()// 1f()// 0</script>
閉包的生命周期
產生: 在嵌套內部函數定義執行完時就產生了(不是在調用)
死亡: 在嵌套的內部函數成為垃圾對象時
<script type="text/javascript">functionfn1(){//此時閉包就已經產生了(函數提升, 內部函數對象已經創建了)var a =2functionfn2(){a++console.log(a)}return fn2}var f =fn1()f()// 3f()// 4f =null//閉包死亡(包含閉包的函數對象成為垃圾對象)</script>