JS - 闭包

379 阅读2分钟
在这个特别的日子里,容忍我叨叨一下:

   年前最后一篇,提前祝大家新年快乐,恭喜发财,发大大大财!
   做自己,相信一切美好,总在不期而遇。

什么是闭包:

what !!?

哈哈哈哈... 每次这个时候,我都会觉得自己是个憨憨,除了知道定义其他一无所知,悲伤一脸!

近期也是闲来无聊,看了一些资料,在这里结合案例和大家一起来分析分析:

案例一:


function test1(){
	function test2() {
		var b = 2
   		console.log(a)  // 1
  		a = 'Hello World'
   		console.log(a) // Hello World
   	}
   	var a = 1
   	return test2
}
var c = 3
var test3 = test1()
test3()

案例一:结合预编译分析

  • 预编译阶段,作用域指向:

  • 预编译结束流程: A: test1 预编译结束,test1 断开 test1-AO 的连接

B:test3 预编译结束 —— test2 预编译结束:

tips:

  • test3 执行后,test2 断开 test2-AO 的连接,test2-AO 被销毁
  • test1 return test2 并赋值给了 test3, 此时 test2 一直保留保留着与 test1-AO 的连接,并死死拽着不放,因此 test1-AO 不会被销毁

C:由上图可以看出,test1-AO 一直在作用域链上,未被销毁,因此可以在 test2 中去访问 test1-AO 中的变量 a 的值,且为1

D:当我们改变 test1 中 a 的值为:Hello World,也就直接修改了 test1-AO 中变量 a 的值

案例二:

function outer() {
	var num = 1
   	function inner() {
    		num++
    		console.log(num)
 	}
   	return inner
}
var addNum = outer()
addNum() // 2
addNum() // 3
addNum() // 4

案例二分析:

  • 预编译过程:

  • 预编译结束 - 作用域情况:

    A:inner、outer 函数编译结束时作用域情况:

B:执行多个 addNum() 的数值变化过程

案例三:

function test() {
	var str = 'Hello World'
   	var option = {
    	set: function(val) {
       		var num = 1
        	str = val
        },
        get: fucntion() {
        	var data = 2
        	console.log(str)
        }
    }
    return option
}
let obj = test
obj.set('世界,你好!')
obj.get() // 世界,你好!

案例三分析:

  • 预编译过程:

  • 预编译结束- 销毁过程 A、test 执行结束:test 断开与 test-AO 之间的连接

B、option 对象被 test 函数 return 出来, option 中的 set、get 方法使用了 test-AO 中的变量 str, 因此option.get() 、option.set() 一直抓着 test-AO

C、赋值变化过程

  • 执行完 test 之后,test 断开与 test-AO 之间的连接
  • 执行完 obj.set('世界,你好!'), test-AO 中变量 str 被赋值为:世界,你好!
  • obj.get(),获取 test-AO 中变化后 str 的值:世界,你好!

补充 return 、window

return 是赋值给了一个全局变量,然后在全局中执行

window.xxx:直接是全局变量,在全局中执行

示例:

return 的方式:

function test(){
 	var a = 1
 	function plus1() {
  		a++
  		console.log(a)
 	}
 	return plus1
}
var plus = test()
plus()  // 2
plus()  // 3 
plus()  // 4 

window.xxx 的方式

function test() {
	var a = 1
 	function plus1() {
   		a++
   		console.log(a)
 	}
 	window.plus1 = plus1()
}
var plus = test()
plus()  // 2
plus()  // 3 
plus()  // 4 

总结:

  • 当内部函数被返回到外部并保存时,一定会产生闭包
  • 闭包会产生原来作用域链不释放
  • 过渡的闭包会导致内存泄漏、加载过慢