携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第16天,点击查看活动详情
在此之前,我们已经了解了执行上下文的概念,包括全局执行上下文与函数执行上下文,下面,闭包。
····一个例子:
var n = 10
function fn(){
var n =20
function f() {
n++;
console.log(n)
}
f()
return f
}
var x = fn()
x()
x()
console.log(n)
分析:变量x为执行函数fn后返回的结果,也就是f。
x( )相当于执行的是函数f( )。
所以结果为:
····闭包:
在 JS 忍者秘籍(P90)中对闭包的定义:闭包允许函数访问并操作函数外部的变量。红宝书上对于闭包的定义:闭包是指有权访问另外一个函数作用域中的变量的函数。 MDN 对闭包的定义为:闭包是指那些能够访问自由变量的函数。这里的自由变量是外部函数作用域中的变量。
总之大概意思是,闭包是指一个函数有权访问另一个函数作用域的函数。
闭包形成的原因:
内部的函数存在外部作用域的引用,就会导致闭包。
拿上一个例子来说,在f函数中存在引用并不属于它自己作用域内的变量n,这就产生了闭包。
····闭包变量的存储位置:堆内存。
闭包不存在于栈内存中是因为栈会把处于栈顶的变量自动回收。闭包的特性就是虽然上一个执行上下文已经被销毁,却仍然存在。所以不可以被自动回收,所以要存放在堆内存中。
拿上一个例子来说,即使fn被执行完之后就被销毁了,但是 JavaScript 依然会让fn.AO 活在内存中,f 函数依然可以通过 f 函数的作用域链找到它,正是因为 JavaScript 做到了这一点,从而实现了闭包这个概念。(这句话我觉得理解了很重要)
····闭包的作用:
保护函数私有变量不受外界干扰。形成不会被销毁的栈内存。
将一些函数的值保存下来,实现方法和属性的私有化。
····闭包的使用场景:
1.return一个函数(return f和f()构成闭包)
var n = 10
function fn(){
var n =20
function f() {
n++;
console.log(n)
}
return f
}
var x = fn()//20
x() // 21
2.函数作为参数
var a = '林一一'
function foo(){
var a = 'foo'
function fo(){
console.log(a)
}
return fo //return fo,fo()就是闭包
}
function f(p){
var a = 'f'
p()
}
f(foo())
foo()的返回值为fo,所以f(foo())等同于f(fo),因为执行fo函数console.log的结果为a的取值,所以f(foo())的值为foo
3.自执行函数
var a = "吃饭"
(function p(){
console.log(a)
})()
产生了闭包p()
4.循环赋值:
for(var i = 0; i<10; i++){
(function(j){
setTimeout(function(){
console.log(j)
}, 1000)
})(i)
}
因为存在闭包的原因导致输出1-10,闭包形成了10个互不干扰的私有作用域。将外层的自执行函数去掉后就不存在外部作用域的引用了,输出的结果就是连续的10。为什么?
因为js是单线程的。遇到异步代码会把异步代码放进栈中,等同步代码执行完再去执行微观任务。
即等i++执行完等于10之后,再去执行定时器。
5.使用回调函数就是在使用闭包。
window.name = '123'
setTimeout(function timeHandler(){
console.log(window.name);
}, 100)
6.防抖节流。
7.函数柯里化
····一些题目:
var data = [];
for (var i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
};
}
data[0]();
data[1]();
data[2]();
var data = [];
for (var i = 0; i < 3; i++) {
(function(j){
setTimeout( data[j] = function () {
console.log(j);
}, 0)
})(i)
}
data[0]();
data[1]();
data[2]();
var data = [];
for (let i = 0; i < 3; i++) {
data[i] = function () {
console.log(i);
};
}
data[0]();
data[1]();
data[2]()
var result = [];
var a = 3;
var total = 0;
function foo(a) {
for (var i = 0; i < 3; i++) {
result[i] = function () {
total += i * a;
console.log(total);
}
}
}
foo(1);
result[0]();
result[1]();
result[2]();
后几个练习题我想留着自己以后练习,就不写答案了。