一、作用域
[[scope]]的定义:
每一个javascript函数都是一个对象,对象中有些属性我们可以访问,但有些不可以,这些属性仅供js引擎存取。[[scope]]就是其中之一,[[scope]]指的就是我们所说的作用域,其中存储了运行期上下文的集合(即:作用域链)。
一切对象都有属性,函数也是对象,函数有属性,如和访问的name属性,不可访问的[[scope]]属性
运行期上下文的定义:
当函数执行时,会创建一个称为执行期上下文的内部对象。一个执行期上下文定义了一个函数执行时候的环境。函数每次执行时对应的执行上下文都是独一无二的。所以多次调用一个函数会导致创建多个执行上下文。当函数执行完毕,它所产生的执行上下文被销毁。
function test(){}
test() //-> AO{},即时的存储空间,执行完被销毁
test() //-> AO{}
复制代码
作用域链的定义:
[[scope]]中所存储的执行期上下文对象的集合,这个集合呈链式连接,我们把这种链式链接叫作用域链
function a() {
function b() {
var b = 234
}
var a = 123
b()
}
var global = 100
a()
复制代码
<1> a定义时产生的 — a刚出生时存的是它所在环境的执行期上下文
<2> a执行时产生一个AO,放在作用域链的顶端
<3> a执行完销毁自己的AO,回到被定义状态
b执行时同理 !!
b中的AO(a的) 和 a中的AO(a的) 是一样的,拿的是一个引用。
function a() {
function b() {
function c(){}
c()
}
b()
}
a()
复制代码
a定义 a.[[scope]] -> 0:GO
a执行 a.[[scope]] -> 0:AO(a)、1:GO
b定义 b.[[scope]] -> 0:AO(a)、1:GO
b执行 b.[[scope]] -> 0:AO(b)、1:AO(a)、2:GO
c定义 c.[[scope]] -> 0:AO(b)、1:AO(a)、2:GO
c执行 c.[[scope]] -> 0:AO(c)、1:AO(b)、2:AO(a)、3:GO
里面可以访问外面的,外面的看不见里面的
查找变量:从作用域链的顶端依次向下查找。在哪个函数里面查找变量,就上哪个函数的作用域链的顶端依次向下查找。
一、闭包
定义:
当内部函数被保存到外部时,将会生成闭包。
缺点:
闭包会导致原有作用域链不释放,造成内存泄漏(内存占用多了,所剩的少了,理解为泄漏)。
作用:
1.实现公有变量 eg:函数累加器(例3)
2.可以做缓存(存储结构) eg:(例5)
3.可以实现封装,属性私有化 eg:Person()
4.模块化开发,防止污染全局变量
例子:
function a() {
function b() {
var bbb = 234
console.log(aaa) //123
}
var aaa = 123
return b
}
var global = 100
var demo = a() //此处a执行完了,要销毁,但是return b,所以AO(a)还跟b连着,未被销毁。
demo()
复制代码
但凡内部的函数被保存到了外部,一定是闭包。因为内部函数保留了外部函数的劳动成果。
2.
function a() {
var num = 100
function b() {
num++
console.log(num)
}
return b
}
var demo = a()//a执行完销毁
demo() //101
demo() //102
复制代码
a销毁时b还未执行,
第一次执行,建立新的AO(b),b拿AO(a)的num,并把AO(a).num-> 101,执行后AO(b)销毁
第二次执行,建立新的AO(b),b拿AO(a)的num,并把AO(a).num-> 101,执行后AO(b)销毁
3.
function add() {
var count = 0
function demo() {
count++
console.log(count)
}
return demo
}
var counter = add()
counter() //1
counter() //2
counter() //3
复制代码
function test() {
var num = 100
function a() {
num++
console.log(num)
}
function b() {
num--
console.log(num)
}
return [a, b]
}
var myArr = test()
myArr[0]() //101
myArr[1]() //100
复制代码
function eater() {
var food = ""
var obj = {
eat: function () {
console.log(`eating ` + food)
food = ""
},
push: function (myFood) {
food = myFood
}
}
return obj
}
var eater1 = eater()
eater1.push("banana")
eater1.eat() //eating banana
复制代码