闭包原理
js使用的是词法作用域,词法作用域的意味着函数执行使用的是定义函数时生效的变量作用域。即函数执行时,里面的参数访问跟执行函数时的作用域无关。如下代码2所示最后输出的是local scope。
闭包定义:js函数对象的内部状态不仅要包含函数代码,还要包含对函数定义所在作用域的引用(即变量)。
我的理解是类似对象和类,在一个function定义的变量里面,它不仅包含内部函数-嵌套函数(function中的function),还包含其内部定义变量的引用,执行时仍然使用自身内部变量的引用,这些变量可看作这个function变量的私有变量。
代码对比理解闭包
代码1
let scope = "global scope"
function checkscope(){
let scope = "local scope"
function f(){return scope}
return f()
}
checkscope()
代码2
let scope = "global scope"
function checkscope(){
let scope = "local scope"
function f(){return scope}
return f
}
let s = checkscope()()
上述两段代码,区别在于代码2返回的是函数,代码1返回的是函数执行的结果—执行的位置,一个在函数体内部,一个在函数体外部。两者的输出都是
local space
可见js的执行作用域只与定义函数时的作用域有关。
案例
let uniqueInteger = function(){
let counter = 0; //只进行分配一次
return function(){return counter++}
}()
console.log(uniqueInteger()) //=>0
console.log(uniqueInteger()) //=>1
在这段代码里counter为私有变量,只进行分配一次,所以这里初始化只进行一次
其实这里就类似于定义了一个对象,想像成别的语言里面的类和对象啥的应该就能更好的理解闭包一点。
function uniqueInteger1(){
var counter = 0;
return function(){return counter++}
}
console.log(uniqueInteger1()()) //=>0
console.log(uniqueInteger1()()) //=>0
闭包难点
function constfuncs(){
let funcs = []
for(var i=0;i<10;i++){
funcs[i]=()=>i
}
return funcs
}
let funcs = constfuncs()
for(let i=0;i<10;i++){
console.log(funcs[i]())
}
//=>10,10,10,10,10,10,10,10,10,10
function constfuncs(){
let funcs = []
for(let i=0;i<10;i++){
funcs[i]=()=>i
}
return funcs
}
let funcs = constfuncs()
for(let i=0;i<10;i++){
console.log(funcs[i]())
}
//=>0,1,2,3,4,5,6,7,8,9
这两个代码的区别在于函数体里面循环体定义i的时候用的是var还是let,var的作用域为整个函数体,而let作用的是整个函数体。因此,当return funcs这条语句执行时,若为var定义的i为10。而用let定义的i,因为i的作用域被卡死在循环体内,所以不同的循环体里i都有一个与其他循环体不同的作用域内部的i,即每个循环体都有自己的作用域。
我不知道我解释清楚这个没有,但是我的理解就是,每个循环体都有自己的独立作用域,如果是用let定义的i,那么每个循环体里面都有一个i,而用var定义,则10个循环体共用一个i,所以最后输出的全是10。
js权威指南上说,“与闭包关联的作用域是’活的’。”我还没理解这句话意思。。。
var 与let的变量提升
console.log(getPi)
console.log("pi",Pi)
console.log(p)
getPi()
function getPi(){
return 3.14
}
var Pi =3.14
let p = 'p'