函数创建与定义的过程
- 函数定义阶段
- 在堆内存中开辟一段空间
- 把函数体内的代码一摸一样的的存储在这段空间内
- 把空间赋值给栈内存的变量中
- 函数调用阶段
- 按照变量名内的存储地址找到堆内存中对应的存储空间
- 在调用栈中开辟一段新的函数执行空间
- 在执行空间中进行形参赋值
- 在执行空间中进行预解析
- 在执行空间中完整执行一遍函数内的代码
- 开辟的函数执行空间销毁
不会销毁的函数执行空间
- 当函数内返回一个复杂数据类型
- 并且函数外部有变量接受这个复杂数据类型
- 函数执行完毕的函数执行空间不会被销毁
function fn() {
const obj = {
a: 1,
b: 2
}
return obj
}
const res = fn()
console.log(res)
res = 100
认识闭包
- 需要一个不会被销毁的函数执行空间
- 需要 直接 或 间接的返回一个函数
- 内部函数使用着外部函数的私有变量
- 优点:
- 可以在函数外面访问到函数内部的变量
- 延长了变量的生命周期
- 缺点
- 闭包函数(不会销毁的空间), 大量使用会造成内存溢出
function outer () {
let a = 100
let b = 200
function inner () {
return a
}
return inner
}
let res = outer()
let outerA = res()
console.log(outerA)
沙箱模式
- 利用了 函数内 "间接" 返回一个函数
- 外部函数 返回一个对象, 对象内书写多个函数
function outer () {
let a = 100
let b = 200
const obj = {
getA: function () {
return a
},
getB: function () {
return b
},
setA: function (val) {
a = val
}
}
return obj
}
const res1 = outer()
console.log(res1.getA())
console.log(res1.getB())
res1.setA(999)
console.log(res1.getA())
const res2 = outer()
console.log(res2.getA())
沙箱模式小案例
<button class="sub">-</button>
<input class="inp" type="text" value="1">
<button class="add">+</button>
<br>
<button class="sub1">-</button>
<input class="inp1" type="text" value="1">
<button class="add1">+</button>
function outer() {
let a = 1
return {
getA() {
return a
},
setA(val) {
a = val
}
}
}
const subBtn = document.querySelector('.sub')
const addBtn = document.querySelector('.add')
const inp = document.querySelector('.inp')
let res = outer()
subBtn.onclick = function () {
let count = res.getA()
res.setA(count - 1)
inp.value = res.getA()
}
addBtn.onclick = function () {
let count = res.getA()
res.setA(count + 1)
inp.value = res.getA()
}
const subBtn1 = document.querySelector('.sub1')
const addBtn1 = document.querySelector('.add1')
const inp1 = document.querySelector('.inp1')
let res1 = outer()
subBtn1.onclick = function () {
let count = res1.getA()
res1.setA(count - 1)
inp1.value = res1.getA()
}
addBtn1.onclick = function () {
let count = res1.getA()
res1.setA(count + 1)
inp1.value = res1.getA()
}
沙箱模式的语法糖
- 尽可能的简化沙箱模式的语法
- 利用的是 getter 和 setter 来进行操作数据
- 语法糖:
- 再不影响功能的情况下, 提供一点更适合操作的语法
- 一碗水, 喝了能让我们补充水分, 水里加点糖, 喝完能让我们补充水分, 并且更好喝了
function outer() {
let a = 100
let b = 200
return {
get a() { return a },
get b() { return b },
set a(val) { a = val }
}
}
let res = outer()
console.log(res.a)
console.log(res.b)
res.a = 999
console.log(res.a)
闭包的面试题
function fun(n, o) {
console.log(o)
const obj = {
fun: function (m) {
return fun(m, n)
}
}
return obj
}
var a = fun(0)
a.fun(1)
a.fun(2)
a.fun(3)