资讯专栏INFORMATION COLUMN

js下探究 let, var 之于闭包

BLUE / 3101人阅读

摘要:问题在说闭包,一定会牵涉到作用域。这也是闭包的属性的,能够记录下内部函数引用外部的值。因为都是全局变量,所以循环也就是不断值覆盖,闭包并不会记录在循环时的值,只会记录闭包变量。闭包时记录的除了闭包变量还有块级作用域变量最后来看看这个输出什么

js 是非常灵活的语言,写起来真是*

不过现在有了typescript,写起来舒服多了。

问题

在说js闭包,一定会牵涉到作用域。而一般在区别 var 跟 let 时就会举 for 循环的例子,但是这里只说 作用域,而不说闭包,那么其实还是看不懂,至于觉得很无厘头。

在阮一峰的 let 和 const 命令一节,举了这么一个例子。

var a = [];
for (var i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 10

var a = [];
for (let i = 0; i < 10; i++) {
  a[i] = function () {
    console.log(i);
  };
}
a[6](); // 6    

然后我就不清楚了,为什么使用var全局变量后, 就输出10, 变成块级作用域let后就正常输出了。

动手

不知道到底怎么回事,只好调试去看变量到底是什么样?在两个例子中都稍微增加了点东西

var a = [];
var b;
var c;
for (var i = 0; i < 10; i++) {
    b = i;
    c = i;
    a[i] = function () {
        console.log(i);
        console.log(c);
    };
}

这里,循环里面有3个变量,内部函数中引用两个。然后我们循环次后,看看a[0], a[1]

我们发现a[0], a[1]首先是个函数对象,在scopes 中有 Closure 这个东西,这就是闭包了。
这里闭包中只有 i跟c,并没有b, 因为b没有在内部函数中被使用,因此没有被scopes 记录下来。
而且请注意,i跟c的值都是当前变量i的值。 这也是闭包的属性的,能够记录下内部函数引用外部的值。因为 i, c, b 都是全局变量,所以循环也就是不断值覆盖,闭包并不会记录在循环时的值,只会记录 闭包变量。

注: 我这里是循环了3次,所以 闭包变量都是3,如果循环完了则是另外的值,你能正确说出它们的值么?

接着我们来看let 的改编

var a = [];
let b;
let c;
for (let i = 0; i < 10; i++) {
    b = i;
    c = i;
    a[i] = function oo() {
        console.log(i);
        console.log(c);
    };
}
a[6](); // 6

同样,这里依旧i,b,c三个变量,内部函数中引用两个。然后我们循环次后,看看a[0], a[1]

在上图,我们可以看到scopes 增加了个新东西 Block, 这是函数记录了 块作用域。
看着这个图,我们就可以这么理解: let声明的变量i 不是全局变量,每次循环都是作用域关闭然后重新再重建,但是在内部函数又引用了 这个块级作用域变量, 所以内部函数会记录这个值。

而变量c 虽然也是 let声明,为什么不是被记录到 Block 呢,这是因为 变量c 虽然是let声明,但是是在for循环外面, 对于这个文件来说,变量c就是全局变量,所以被记录到 closure

over

看完以上分析,不知道有没有加深你对let,const 的理解, let声明的变量是块级作用域,const声明的是全局变量,但也要看用在哪儿。 闭包时记录的 除了闭包变量还有块级作用域变量

最后来看看这个输出什么:

var a = [];
let b;
let c;
for (let i = 0; i < 10; i++) {
    b = i;
    c = i;
    var n = i;
    let m = i;
    a[i] = function oo() {
        console.log(i);
        console.log(c);
        console.log(n);
        console.log(m);
    };
}
a[6](); 



文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/108062.html

相关文章

  • JS进击之路:闭包

    摘要:常见问题说到闭包相关的问题,最典型的就是变量和指向这两类问题。如果有错误或不严谨的地方,欢迎批评指正,如果喜欢,欢迎点赞。 引言 闭包这个词对很多前端开发人员来说既熟悉又陌生,熟悉是因为很多人都用过闭包,但是用的时候不知道闭包,陌生是因为并不理解闭包,接下来这篇文章将会从多方面介绍闭包 定义 闭包是怎么定义的呢?当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数在当前词法作...

    tolerious 评论0 收藏0
  • Node.js内存管理和V8垃圾回收机制

    摘要:垃圾回收内存管理实践先通过一个来看看在中进行垃圾回收的过程是怎样的内存泄漏识别在环境里提供了方法用来查看当前进程内存使用情况,单位为字节中保存的进程占用的内存部分,包括代码本身栈堆。 showImg(https://segmentfault.com/img/remote/1460000019894672?w=640&h=426);作者 | 五月君Node.js 技术栈 | https:...

    JowayYoung 评论0 收藏0
  • javascript知识点

    摘要:模块化是随着前端技术的发展,前端代码爆炸式增长后,工程化所采取的必然措施。目前模块化的思想分为和。特别指出,事件不等同于异步,回调也不等同于异步。将会讨论安全的类型检测惰性载入函数冻结对象定时器等话题。 Vue.js 前后端同构方案之准备篇——代码优化 目前 Vue.js 的火爆不亚于当初的 React,本人对写代码有洁癖,代码也是艺术。此篇是准备篇,工欲善其事,必先利其器。我们先在代...

    Karrdy 评论0 收藏0
  • Swift中的ARC相关

    摘要:再次提醒一下中的只针对引用类型对象。对于我们中的大多数来说,我们其实并不清楚内存中发生的了什么。那就是循环引用,类似于操作系统中的死锁。除了声明外,还有一个不常用的关键字,于类似该声明也是表面非持有关系,当时两种存在区别。 关于内存管理 当我们选择这条职业道路的时候,不可避免的我们都要内存管理打交道。无论是C中的malloc、free还是C++中的new、delete。它如此重要又如此...

    刘明 评论0 收藏0
  • 夯实基础-作用域与闭包

    摘要:作用域分类作用域共有两种主要的工作模型。换句话说,作用域链是基于调用栈的,而不是代码中的作用域嵌套。词法作用域词法作用域中,又可分为全局作用域,函数作用域和块级作用域。 一篇巩固基础的文章,也可能是一系列的文章,梳理知识的遗漏点,同时也探究很多理所当然的事情背后的原理。 为什么探究基础?因为你不去面试你就不知道基础有多重要,或者是说当你的工作经历没有亮点的时候,基础就是检验你好坏的一项...

    daydream 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<