04------JS函數高級之作用域(鏈)、閉包

作用域和作用域鏈

1.作用域
理解:

  • 就是一塊地盤,一個代碼所在的區域
  • 它是靜態的(相對於上下文對象),在編寫代碼的時候就已經確定

分類:

  • 全局作用域
  • 局部作用域
  • 塊作用域(ES6)

作用:

  • 隔離變量,不同作用域下同名變量不會有衝突

在這裏插入圖片描述
2.作用域和執行上下文

1).區別1

  • 全局作用域之外,每個函數都會創建自己的作用域,作用域在函數定義時就已經確定,而不是在函數調用時
  • 全局執行上下文環境是在全局作用域確定之後,js代碼馬上執行之前創建
  • 函數執行上下文是在調用函數時,函數體代碼執行之前創建

2).區別2

  • 作用域是靜態的,只要函數定義好了就會一直存在,且不會再變化
  • 執行上下文環境是動態的,調用函數時創建,函數調用結束時上下文環境會被動態釋放

3).聯繫

  • 執行上下文環境(對象)是從屬於所在的作用域
  • 全局上下文環境---->全局作用域
  • 函數上下文環境---->對應的函數使用域
    在這裏插入圖片描述
    3.作用域鏈

1).理解

  • 多個上下級關係的作用域形成的鏈,它的方向是從下向上的(從內到外)
  • 查找變量時就是沿着作用域鏈來查找的

2).查找一個變量的規則

  • 在當前作用域下的執行上下文中查找對應的屬性,如果有直接返回,否則進入2
  • 在上一級作用域的執行上下文查找對應的屬性,如果有直接返回,否則進入3
  • 再次執行2的相同操作,直到全局作用域,如果還找不到就拋出找不到的異常

圖解:
在這裏插入圖片描述
面試題:
1).

<script type="text/javascript">
var x = 10;
function fn() {
	console.log(x) // 10
}
function show(f) {
	var x = 20
	f()
}
show(fn)
</script>

2).

<script type="text/javascript">
var fn = function () {
	console.log(fn) //輸出fn函數
}
fn()
var obj = {
	fn2: function () {
		console.log(fn2) //報錯 fn2未定義
	}
}
obj.fn2()
</script>

閉包

1.閉包的理解

1).如何產生閉包?

  • 當一個嵌套的內部(子)函數引用了嵌套的外部(父)函數的變量(函數)時,就產生了閉包

2).閉包到底是什麼?

  • 理解一:閉包是嵌套的內部函數
  • 理解二:包含被引用變量(函數)的對象
  • 注意:閉包存在於嵌套的內部函數中

3).產生閉包的條件?

  • 函數嵌套
  • 內部函數引用了外部函數的數據(變量/函數)

2.常見的閉包

  • 將函數作爲另一個函數的返回值
function fn1() {
	var a = 2
	function fn2() {
		a++
		console.log(a)
	}
	return fn2
}
var f = fn1()
f() // 3
f() // 4
  • 將函數作爲實參傳遞給另一個函數調用
function showDelay(msg, time) {
	setTimeout(function () {
		alert(msg)
	}, time)
}
showDelay('hello', 1000)

3.閉包的作用

  • 延長了局部變量的生命週期
  • 在外部能夠間接的操作內部的變量

4.閉包的生命週期

  • 產生:在嵌套內部函數定義執行完時就產生了(不是在調用)
  • 死亡:在嵌套的內部函數成爲垃圾對象時
<script type="text/javascript">
	function fn1() {
		var a = 2
		function fn2() {
			a++
			console.log(a)
		}
		return fn2
	}
	// 問題1:此時閉包產生了嗎? 已產生
	var f = fn1()
	// 問題2:此時閉包釋放了嗎? 沒有
	f() 
	f() 
	// 問題3:此時閉包釋放回收了嗎? 沒有
	// 問題4:如何讓閉包釋放回收呢? f = null
</script>

5.閉包的應用
自定義JS模塊

  • 具有特定功能的js文件
  • 將所有的數據和功能都封裝在一個函數內部(私有的)
  • 只向外部暴露一個包含n個方法的對象或函數
  • 模塊的使用者,只需要通過模塊暴露的對象調用方法來實現對應的功能

6.閉包的缺點以及解決
缺點

  • 函數執行完後,函數內的局部變量沒有釋放,佔用內存時間會變長
  • 容易造成內存泄露

解決

  • 能不用閉包就不用
  • 及時釋放

內存溢出與內存泄露

1.內存溢出

  • 一種程序運行出現的錯誤
  • 當程序運行需要的內存超過了剩餘的內存時,就會拋出內存溢出的錯誤

2.內存泄露

  • 佔用的內存沒有及時釋放
  • 內存泄露積累多了就容易導致內存溢出
  • 常見的內存泄露:
    • 意外的全局變量
    • 沒有及時清理的計時器或回調函數
    • 閉包
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章