JS 解惑 - 闭包(closure)

发布于 2023-08-13 11:15:01 字数 3274 浏览 45 评论 0

对于 JS 的闭包(Closure)的概念,以及闭包的作用域具有全局性。我针对我自己的实战感受,这里简单谈谈。

概念

闭包(Closure),是指有权访问另一个函数作用域中的变量的函数。

创建闭包,常见的一种方式就是在一个函数内部创建另一个函数。

概念引自: JavaScript 高级程序设计(第三版)7.2 闭包 一节, 178 页

示例

举个例子来解释下这个概念:

var name = 'window';
function outerFun(){
    var name = 'night';
    console.log('1',this.name);
    var innerFun = function(){
        console.log('2',name);
        console.log('3',this.name);
    };
    return innerFun;
};

outerFun()();

结果:

1 window
2 night
3 window

分析

示例代码在执行的时候,可以进行如下分解:

var name = 'window';
var fun1 = outerFun();
var fun2 = fun1();//fun2 是 fun1 的闭包
fun2();//最终调用

再来继续加工下:

window.name = 'window';
window.fun1 = window.outerFun();
window.fun2 = window.fun1();//fun2 是 fun1 的闭包
window.fun2();//最终调用

为什么能这么变形呢?因为在最外层,其实所有变量都是 window 对象的!

经过上面的分解,我们知道最终调用 fun2() 的时候,其实 fun2 函数,已经相当于是 window 环境了。

所以,我们知道任何闭包,都是最终都相当于在 window 环境下执行的,这也就是为什么闭包的作用域具有全局性了。

深究

接下来再来看单独拆分下每个函数:

fun1 的函数:

var name = 'window';
function fun1(){
    var name = 'night';
    console.log('1',this.name);
}

为什么 fun1 中的结果是:window 而不是 night?

知识点:

  1. 我们知道,任何一个函数在执行的时候,首先会为其创建一个上下文环境,接着初始化 2 个变量: thisarguments ,fun1 中的 this(调用它的对象,也叫活动对象),即:window
  2. 全局作用域局部作用域 的最大区别就是,局部作用域在函数内部定义,并且在非闭包的情况下,函数运行完毕就释放掉了。

所以:

console.log('1',this.name); 其实就是在 window 中寻找 name 属性,这个肯定是 window 了,因为在函数之前,我们定了 var name = window.name

至于 fun1 中的 name 其实在函数中,根本就没有被使用,而如果我们不明确指定 this.name ,即:

var name = 'window';
function fun1(){
    var name = 'night';
    console.log('1',name);
}

那么结果肯定是:night,再如果 fun1 内部未定义 name,那么最终还是会通过原型链(或者叫上下文)找到全局的 name。

fun2 的函数:

function fun2(){
   console.log('2',name);
   console.log('3',this.name);
}

fun2 所处的活动对象其实有 3 个:

  1. 自身函数
  2. fun1 函数
  3. window 函数

console.log('2',name); 会优先从内部寻找 name 变量,没找到!那么就从为其提供闭包的父函数 fun1 中找,找到了,即:night

console.log('3',this.name); 这里明确指定了 this.name 那么,系统就会从原型链开始寻找 this.name ,由于 this 指向的是 window ,那么结果自然就是:window

扩展

其实闭包函数,在我们的日常工作中经常用到。

定义对象过程中经常会涉及到

//通过字面量定义一个对象 obj
var obj = {
    name : 'night',
    bindEvent : function(){
        var _self = this;
        $('#btn').click(function(){
            console.log('hello ' + _self.name);
        });
    }
};

方法中包含 setTimeout

//3s 后显示:hello night
function delayDisplay(){
    var name = 'night';
    setTimeout(function(){
        console.log('hello ' + name);
    },3000);
};

其实,还有很多这方面的例子,但是不管怎么样,你要记住一个概念:函数中的函数。而且闭包有一个优势:就是能访问创建闭包对象的变量。


fun2 的 this 不应该指向的是 fun1 吗?怎么 this 直接指向最外面的 window


这说明你还没完全理解闭包,要理解 this 到底指向谁,主要是看是谁执行的当前函数,那么函数中 this 就指向谁。这个题目中,fun1 的目的是 return fun2 函数,但是真正执行 fun2 的是 window。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

没企图

暂无简介

文章
评论
26 人气
更多

推荐作者

櫻之舞

文章 0 评论 0

弥枳

文章 0 评论 0

m2429

文章 0 评论 0

野却迷人

文章 0 评论 0

我怀念的。

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文