js高级特性–闭包
前置知识
变量声明
-
基本数据类型
var a = 12 var b = a b = 13
-
引用数据类型
var a = {n: 12} var b = a b.n = 13 console.log(a) // { n: 13 }
-
函数的声明和调用
-
函数声明
... const A = function(a) { ... } ...
函数声明步骤: 1、声明作用域[[scope]] 2、声明形参 3、存储代码块
-
函数调用
-
> 函数调用步骤: 1、形成私有的执行上下文 2、初始化作用域链 3、形参赋值 4、代码执行
js作用域(es5)
js中作用域分为全局作用域和局部作用域(函数作用域)
-
全局作用域
任何地方都能被访问
var num = 100 function f1() { console.log(num); } f1() // 100
-
函数作用域
在固定的代码片段中才能被访问
function f2() { var num = 200 } f2() console.log(num); //demo.html:13 Uncaught ReferenceError: num is not defined
-
注意 定义的变量不使用var关键词 则为全局作用域
function f2() { num = 200 // 定义的变量为全局作用域 } f2() console.log(num); // 200
-
作用域链
变量寻找过程: 作用域f1 —》 作用域f2 —》 全局作用域 (当前作用域找不到值就会向上一级作用域找,直至找到为止,形成作用域链)
var a = 1 // 变量a为全局作用域
function f1() {
var b = 2 // 变量b为f1作用域
function f2() {
var c = 3 // 变量c为f2作用域
console.log(a);
}
f2()
}
f1() // 输出1
// 执行函数f2 打印变量a 在f2作用域中没有变量a 向上找f1作用域 f1作用域没有变量a 向上找全局作用域 存在变量a 正确打印
思考
作用域链机制可以让函数作用域内访问全局作用域的变量
-
反之如何实现在全局作用域内访问函数作用域中的变量
function f1() { var a = 1 var b = 2 function f2 (){ console.log(a+b); } return f2 } var f3 = f1() f3() // f2函数嵌套在f1函数内部,所以f1内部的所有变量对于f2都是可访问的(作用域链机制),当f2作为返回值,我们就可以在全局作用域中访问函数作用域中的变量了。
闭包概念
-
思考中的f3函数就是闭包,闭包就是可以访问其他函数内部变量的函数
-
因为在js中只有函数内部的子函数才能访问局部变量,所以闭包可以理解为函数内部的函数
-
闭包本质就是函数内部与函数外部连接的桥梁
闭包的用途
-
可以访问函数作用域中的变量(上文思考中)
-
让变量的值始终保存在内存中
-
没有闭包的情况下
function f1() { var a = 1 a++ console.log(a); } f1() // 输出为2 f1() // 输出为2 因为每次调用后变量会被垃圾回收机制回收 // f2函数中的a是自己的函数作用域 所以f2执行完就回收变量a
-
存在闭包的情况下
function f1() { var a = 2 return function () { a++ console.log(a); } } var f2 = f1() f2() // 输出为3 f2() // 输出为4 // f2 函数中的a访问的是f1中的作用域 所以f2执行完并不会回收变量a
-
练习
-
练习1
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); // 输出为 The Window
var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()()); // 输出为 My Object
-
练习2
let a = 0 b = 0 function A(a) { A = function(b) { console.log(a + b++) } console.log(a++) } A(1) // 输出为1 A(2) // 输出为4
运行过程