日期:2021/11/20 分类:JavaScript 题目:什么是闭包?闭包的优缺点以及实现原理和应用场景分别是什么?
闭包是在函数中提出的概念,简单来说就是一个函数定义中引用了函数外定义的变量,并且该函数可以在其定义环境外被执行。当内部函数以某一种方式被任何一个外部函数作用域访问时,一个闭包就产生了。
实际上闭包可以看做一种更加广义的函数概念。因为其已经不再是传统意义上定义的函数。
闭包的条件:
-
外部函数中定义了内部函数。
-
外部函数是具有返回值,且返回值为内部函数。
-
内部函数还引用了外部函数的变量。
闭包的缺点:
-
作用域没有那么直观。
-
因为变量不会被垃圾回收所以有一定的内存占用问题。
闭包的作用:
-
可以使用同级的作用域。
-
读取其他元素的内部变量。
-
延长作用域。
-
避免污染全局变量
闭包的原理:
我们可以将函数的执行分成两个阶段,即预编译阶段和执行阶段;
-
在预编译阶段,如果发现内部函数使用了外部函数的变量,它就会在内存中 创建一个闭包对象并保存相对应的值,如果已经存在闭包,则只需要增加对应属性值即可。
-
在执行完成后,函数执行上下文会被校徽,函数对闭包对象的引用也会被销毁,但其内部函数还持有该闭包的引用,所以内部函数还可以继续使用外部函数的变量
闭包主要是利用作用域链的特性,一个函数内部定义的函数会将包含该函数的活动对象添加到自己本身的作用域链中,函数执行完毕,其执行作用域链销毁,但因内部函数的作用域链仍然引用这个活动对象,所以其活动对象不会被销毁,直到内部函数被销毁后这些活动对象才会被销毁。
闭包的实现的demo:
// 1. 通过返回的内部函数来操作函数中的局部变量
function fun () {
var v = 100; // 局部变量
// 通过返回一个对象的方式访问局部变量v 来完成闭包
return {
set: function (x) {
v = x;
},
get: function () {
return v
}
}
}
var result = fun();
result.set(200)
console.log(result.get()); // 200
// 2. 定义一个局部变量,计算该函数一共调用几次
var generate_count = function () {
var container = 0;
return function () {
container++
console.log(`这是第${container}次调用`);
}
}
var result = generate_count();
result(); // 这是第1次调用
result(); // 这是第2次调用
result(); // 这是第3次调用
// 3.修改 Math.pow() 函数,让求一个数的平方或者立方时,不需要每次传递第二个参数
/*
Math.pow(4, 2) // 求4的平方
Math.pow(4, 3) // 求4的立方
*/
// 写一个函数生成器
function makePower (power) {
return (number) => {
return Math.pow(number, power)
}
}
// 平方
let power2 = makePower(2)
// 立方
let power3 = makePower(3)
// 求4的平方
console.log(power2(4)) // 16
// 求4的立方
console.log(power3(4)) // 62