资讯专栏INFORMATION COLUMN

[面试专题]从for循环看let和var的区别

Jrain / 1220人阅读

摘要:从循环看和的区别的允许你声明一个作用域被限制在块级中的变量语句或者表达式。在中,绑定不受变量提升的约束,这意味着声明不会被提升到当前执行上下文的顶部。这个变量处于从块开始到初始化处理的暂存死区之中。

从for循环看let和var的区别
MDN的let:

let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,var声明的变量只能是全局或者整个函数块的。在 ECMAScript 2015 中,let 绑定不受变量提升的约束,这意味着 let 声明不会被提升到当前执行上下文的顶部。在块中的变量初始化之前,引用它将会导致 ReferenceError(而使用 var 声明变量则恰恰相反,该变量的值是 undefined )。这个变量处于从块开始到 let 初始化处理的”暂存死区“之中。
循环定义中的let作用域:循环体中是可以引用在for声明时用let定义的变量,尽管let不是出现在大括号之间.

var list = document.getElementById("list");

for (let i = 1; i <= 5; i++) {
  var item = document.createElement("LI");
  item.appendChild(document.createTextNode("Item " + i));
  let j = i;
  item.onclick = function (ev) {
    console.log("Item " + j + " is clicked.");
  };
  list.appendChild(item);
}

在每次循环的时候用 let j 保留的 i 的值,所以在 i 变化的时候,j 并不会变化。而console.log 的是 j,即使此处i声明换成var,结果依然一样.
MDN此处的写法是多余的,去掉let j = i依然可以实现上述效果,只是方便理解let.事实上去掉let j = i,等效于:

for (let i = 1; i <= 5; i++) {
  //let i = i;即将i的作用域放在了改块级作用域中
  var item = document.createElement("LI");
  item.appendChild(document.createTextNode("Item " + i));
  item.onclick = function (ev) {
    console.log("Item " + i + " is clicked.");
  };
  list.appendChild(item);
}
console.log(i)// Uncaught ReferenceError: i is not defined

上边代码中最后的ReferenceError表明,i虽然在for循环{}的外层,但是实际上是被绑定在该块级作用域内的.这里和var是不一样的,var声明的i在外层,因此成为全局变量.

变量提升(hoist)
let x = "global";
(function() {
    console.log(x); // Uncaught ReferenceError: x is not defined
    let x = "part";
    console.log(x)
}());

众所周知,let变量没有hoist,按这个理解,函数内第一行log(x)应当是global才对,但是却报错了.去掉let x = "part"就没有问题,这说明后边的声明影响到了第一行的log(x).

fn();
function fn(){
  var x = 1;
  console.log(x,y)
  var y = 2
}

执行过程:

找到所有用 function 声明的变量,在环境中「创建」这些变量。

将这些变量「初始化」并「赋值」为 function(){//具体内容}

执行代码,即fn()

函数体内找到所有用var声明的变量,在环境中「创建」这些变量

将这些变量「初始化」为 undefined。

开始执行代码,x = 1 将 x 变量「赋值」为 1

打印x = 1 ,而y还未赋值,因此为undefined
如果var改为let:

找到所有用 function 声明的变量,在环境中「创建」这些变量。

将这些变量「初始化」并「赋值」为 function(){//具体内容}

执行代码,即fn()

函数体内找到所有用let声明的变量,在环境中「创建」这些变量

开始执行代码,x = 1 将 x 变量「赋值」为 1

打印 x = 1 ,而y还未「初始化」,因此Uncaught ReferenceError.这就是所谓暂时性死区.

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

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

相关文章

  • [面试专题]for循环letvar区别

    摘要:从循环看和的区别的允许你声明一个作用域被限制在块级中的变量语句或者表达式。在中,绑定不受变量提升的约束,这意味着声明不会被提升到当前执行上下文的顶部。这个变量处于从块开始到初始化处理的暂存死区之中。 从for循环看let和var的区别 MDN的let: let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,var声明的变量只能是全局或者整个函数块的。...

    Aomine 评论0 收藏0
  • [面试专题]for循环letvar区别

    摘要:从循环看和的区别的允许你声明一个作用域被限制在块级中的变量语句或者表达式。在中,绑定不受变量提升的约束,这意味着声明不会被提升到当前执行上下文的顶部。这个变量处于从块开始到初始化处理的暂存死区之中。 从for循环看let和var的区别 MDN的let: let允许你声明一个作用域被限制在块级中的变量、语句或者表达式。与var关键字不同的是,var声明的变量只能是全局或者整个函数块的。...

    tommego 评论0 收藏0
  • 56 道高频 JavaScript 与 ES6+ 面试题及答案

    摘要:线程的划分尺度小于进程,使得多线程程序的并发性高。线程在执行过程中与进程还是有区别的。每个独立的线程有一个程序运行的入口顺序执行序列和程序的出口。从逻辑角度来看,多线程的意义在于一个应用程序中,有多个执行部分可以同时执行。 showImg(https://segmentfault.com/img/bVbv2GE?w=900&h=400); 前言 本文讲解 56 道 JavaScript...

    zengdongbao 评论0 收藏0
  • 8道经典JavaScript面试题解析,你真掌握JavaScript了吗?

    摘要:浏览器的主要组成包括有调用堆栈,事件循环,任务队列和。好了,现在有了前面这些知识,我们可以看一下这道题的讲解过程实现步骤调用会将函数放入调用堆栈。由于调用堆栈是空的,事件循环将选择回调并将其推入调用堆栈进行处理。进程再次重复,堆栈不会溢出。 JavaScript是前端开发中非常重要的一门语言,浏览器是他主要运行的地方。JavaScript是一个非常有意思的语言,但是他有很多一些概念,大...

    taowen 评论0 收藏0
  • JavaScript专题之乱序

    摘要:源码地址为了简化篇幅,我们对这个数组进行分析,数组长度为,此时采用的是插入排序。插入排序的源码是其原理在于将第一个元素视为有序序列,遍历数组,将之后的元素依次插入这个构建的有序序列中。 JavaScript 专题系列第十九篇,讲解数组乱序,重点探究 Math.random() 为什么不能真正的乱序? 乱序 乱序的意思就是将数组打乱。 嗯,没有了,直接看代码吧。 Math.random ...

    I_Am 评论0 收藏0

发表评论

0条评论

Jrain

|高级讲师

TA的文章

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