0
点赞
收藏
分享

微信扫一扫

js闭包简介


一、执行上下文和作用域链

执行上下文是JavaScript执行一段代码时的运行环境,比如调用一个函数,就会进入这个函数的执行上下文,然后确定该函数在执行期间用到的变量:this、变量、函数等。JavaScript代码在编译阶段,会为其创建上下文执行环境,而该执行环境所用到的 变量信息都存在执行上下文环境中的环境变量对象中

函数执行时,每个执行上文中都会有一个包含其中变量的对象。全局上下文中的叫变量对象,它会在代码执行期间始终存在。而函数局部上下文中的叫活动对象只在函数执行期间存在。

举例:

function compare (valuel, value2)
{
if (valuel<value2){
return-1;}
else if (valuel› value2){
return 1;
}
else {
return 0;
}
}
let result = conpare(5,10)

在定义compare ()两数时,就会为它创建作用域链,预装载全局变量对象,并保存在内部的[[Scope]]中。在调用这个的数时,会创建相应的执行上下文,然后通过复制函数的[[scope]]来创建其作用域链。接着会创建函数的活动对象 (用作变量对象)并将其推人作用域链的前端。在这个例子中,这意味着 compare函数执行上下文的作用域链中有两个变量对象:局部变量对象和全局变量对象。作用域链其实是一个包含指针的列表,每个指针分别指向一个变量对象,但是物理上并不会包含相应的对象(虚拟链表)。

js闭包简介_javascript

function createComparisonFunction(propertyName) {
return function(object1, object2) {
let value1 = object1[propertyName];
let value2 = object2[propertyName]
if (value1 < value2) { return -1; } else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
}
//创建比较函数
let compareNames = createComparisonFunction('name);
//调用函数
let result = compareNames({name:"Nicholas"},{name:"Matt"});
//解除对函数的引用,这样可以释放内存(垃圾回收机制)
compareName = null;

在 createComparisonFunction()返回匿名函数后,它的作用域链被初始化为包含createComparisonFunction() 的=活动对象全局变量对象。这样,匿名函数就可以访问到 createComparisonFunction()可以访问的所有变量。另一个有意思的副作用就是,createcomparisonFunction()的活动对象并不能在它执行完毕后销毀,因为匿名函数的作用域链中仍然有对它的引用。在createCorDarisonruncttonty执行完毕后,其执行上卞文的作用城链会销毁,但它的活动对象仍然会保留在内存中,直到匿名函数被销毁后才会被销毁:

js闭包简介_作用域链_02

二、常见的闭包类型

①定时器

function wait(message){
setTimeout(() => {
console.log(message);
}, 1000);
}

一个内部函数(箭头函数)传递给setTimeout,这个箭头函数有wait作用域得闭包,因此保持对messsage得引用。wait执行1000毫秒后,它得内部作用域并不会消失,依然保持对wait作用域得闭包,(箭头函数对wait函数得活动对象得作用域链依然保持);
②点击事件

function test(name,selector) {
$(selector).click(
function name() {
console.log('name:'+name);
}
)
}
test('leechoy','#test1');
test('simon','#test2')

三、循环和闭包

for (var index = 0; index < 5; index++) {
setTimeout(() => {
console.log(index);
}, 1000);
}

输入结果为 5 5 5 5 5
let块级作用域,块重返作用域
(for循环头部的let 声明还会有个特殊的行为。这个行为指出变量在循环过程中不止被声明一次,每次选代都会声明。随后的每个迭代都会使用上一个迭代结束时的值来初始化这个变量。)

for (let index = 0; index < 5; index++) {
setTimeout(() => {
console.log(index);
}, 1000);
}

输入结果为 0 1 2 3 4

for (var index = 0; index < 5; index++) {
(
function () {
setTimeout(() => {
console.log(index);
}, 1000);
}
)()
}

输入结果为 5 5 5 5 5

for (var index = 0; index < 5; index++) {
(
function (i) {
setTimeout(() => {
console.log(i);
}, 1000);
}
)(index)
}

for (var index = 0; index < 5; index++) {
(
function () {
var i= index;
setTimeout(() => {
console.log(i);
}, 1000);
}
)()
}

输入结果为 0 1 2 3 4


举报

相关推荐

0 条评论