给大家推荐一个实用面试题库

1、前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

1、let命令

基本用法

用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。

let只能出现在当前作用域的顶层。

for循环中,使用let声明循环变量i,当前的i只在本轮循环有效,每一次循环的i都是一个新的变量。

for循环还有一个特别之处,就是设置循环变量的那部分是一个父作用域,而循环体内部是一个单独的子作用域。

不存在变量提升现象

变量提升:变量可以在声明之前使用,使用var声明的变量会自动提升到函数作用域顶部。

==》具体争议转看下文“关于是否存在变量提升的争议问题”

暂时性死区

只要块级作用域内存在let命令,它所声明的变量就“绑定”(binding)这个区域,不再受外部的影响。

var tmp = 123;if (true) {tmp = 'abc'; // ReferenceError 受到let约束let tmp;
}
复制代码

ES6 明确规定,如果区块中存在letconst命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。

在代码块内,使用let命令声明变量之前,该变量都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,TDZ)

在没有引入lettypeof是绝对安全,不会出错的 typeof对于没有声明的变量会显示undefined不会报错,但是对于未声明的变量会报错ReferenceError

总之,暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。

不允许重复声明

注意区分重复冗余声明和嵌套声明

2、块级作用域

存在意义

ES5只有全局作用域和函数作用域

解决以下场景问题:

  1. 内层变量可能会覆盖外层变量。
  2. 用来计数的循环变量泄露为全局变量。

ES6的块级作用域

let为JavaScript新增了块级作用域。
ES6允许块级作用域的任意嵌套。
内层作用域可以定义外层作用域的同名变量。

块级作用域的出现,实际上使得获得广泛应用的**匿名立即执行函数表达式(匿名 IIFE)**不再必要了。

块级作用域与函数声明

ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。

ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
为了避免块级作用域内声明的函数的处理规则对老代码产生很大的影响,减轻不兼容问题,ES6允许浏览器有自己的行为方式,规则如下:

  • 允许在块级作用域内声明函数。
  • 函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
  • 同时,函数声明还会提升到所在的块级作用域的头部。

注意,上面三条规则只对 ES6 的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。

根据这三条规则,浏览器的 ES6 环境中,块级作用域内声明的函数,行为类似于var声明的变量。
考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。

// 块级作用域内部的函数声明语句,建议不要使用
{let a = 'secret';function f() {return a;}
}// 块级作用域内部,优先使用函数表达式
{let a = 'secret';let f = function () {return a;};
}
复制代码

ES6 的块级作用域必须有大括号,如果没有大括号,JavaScript 引擎就认为不存在块级作用域。

3、const命令

基本用法

const声明一个只读的常量。一旦声明,常量的值就不能改变。

const一旦声明变量,就必须立即初始化,不能留到以后赋值。

const的作用域与let命令相同:只在声明所在的块级作用域内有效。

const命令声明的常量也是不提升,同样存在暂时性死区,只能在声明的位置后面使用。

const声明的常量,也与let一样不可重复声明。

本质

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。

对于简单数据类型,值就是保存变量的内存地址【常量】;复合数据类型,变量指向的内存地址保存的只是一个指向实际数据的指针

const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。

因此使用const声明一个对象,对象的属性是可变的,但是不能改变对象为另一个对象(不能改变指针的指向)。

冻结对象,无法改变对象属性应该使用Object.freeze方法。

var constantize = (obj) => {Object.freeze(obj);Object.keys(obj).forEach( (key, i) => {if ( typeof obj[key] === 'object' ) {constantize( obj[key] );}});
};
复制代码

ES6声明变量的六种方法

ES5

  1. var
  2. function

ES6

  1. let
  2. const
  3. import
  4. class

4、顶层对象的属性

顶层对象,在浏览器环境指的是window对象,在 Node 指的是global对象。

ES5 之中,顶层对象的属性与全局变量是等价的。

顶层对象的属性与全局变量挂钩带来的问题:

  1. 首先是没法在编译时就报出变量未声明的错误,只有运行时才能知道(因为全局变量可能是顶层对象的属性创造的,而属性的创造是动态的);
  2. 其次,程序员很容易不知不觉地就创建了全局变量(比如打字出错);
  3. 最后,顶层对象的属性是到处可以读写的,这非常不利于模块化编程。
  4. 另一方面,window对象有实体含义,指的是浏览器的窗口对象,顶层对象是一个有实体含义的对象,也是不合适的。

从 ES6 开始,全局变量将逐步与顶层对象的属性脱钩。

  • var命令和function命令声明的全局变量,依旧是顶层对象的属性;
  • let命令、const命令、class命令声明的全局变量,不属于顶层对象的属性。

5、globalThis对象

JavaScript 语言存在一个顶层对象,它提供全局环境(即全局作用域),所有代码都是在这个环境中运行。

但是,顶层对象在各种实现里面是不统一的。

  • 浏览器里面,顶层对象是window,但 Node 和 Web Worker 没有window
  • 浏览器和 Web Worker 里面,self也指向顶层对象,但是 Node 没有self
  • Node 里面,顶层对象是global,但其他环境都不支持。

很难找到一种方法在所有情况下都取到顶层对象,因此ES2020引入了globalThis作为顶层对象。

关于是否存在变量提升的争议问题

在学习该部分知识时,依据的是ES6入门教程以及MDN中文文档的内容,没有过多参看其他官方文档,便断定letconst不存在变量提升。但经过大佬指点后拜读了mdn英文文档,文档中描述了letconstclass来说是存在变量提升的,以下做详细解释。

MDN英文文档说明存在以下三种认为是变量提升(Hositing)的行为:

【原文】Hoisting is not a term normatively defined in the ECMAScript specification. The spec does define a group of declarations as HoistableDeclaration, but this only includes function, function*, async function, and async function* declarations. Hoisting is often considered a feature of var declarations as well, although in a different way. In colloquial terms, any of the following behaviors may be regarded as hoisting:

【翻译】Hosting(变量提升)不是 ECMAScript 规范中规范定义的术语。该规范确实将一组声明定义为HoistableDeclaration,但这仅包括函数,函数*,异步函数和异步函数*声明。变量提升通常也被认为是var声明的一个特征,尽管方式不同。通俗地说,有下列行为之一,可视为变量提升:

  1. Being able to use a variable's value in its scope before the line it is declared. ("Value hoisting")

【翻译】能够在声明变量的行之前在其范围内使用变量的值。(“值变量提升”)

【实例】ECMAScript规范说明中写到作为HoistableDeclaration的四种function声明:functionfunction*async functionasync function*

  1. Being able to reference a variable in its scope before the line it is declared, without throwing a ReferenceError, but the value is always undefined. ("Declaration hoisting")

【翻译】能够在声明该变量的行之前在其作用域中引用该变量,而不会引发ReferenceError,但该值始终未定义。(“声明变量提升”)

【实例】var命令的变量提升

  1. The declaration of the variable causes behavior changes in its scope before the line in which it is declared.

【翻译】变量的声明会导致在声明它的行之前在其作用域中发生行为更改。

【实例】letconstclass声明命令(也统称为词汇声明lexical declarations)

看到这里有个问题:既然存在变量提升,为何ES6入门和MDN中文文档中都没有注明呢?

MDN英文文档也给出了解释:

因为暂时性死区的存在,严格禁止了在变量声明前进行使用,所以很多地方都认为letconstclass声明命令不存在变量提升。这种异议也合理的,因为变量提升并不是一个被定义到ECMAScript中的普遍认可的术语(universally-agreed term)。但是暂时性死区可能会导致其范围内发生其他可观察到的变化,这表明是存在着变量提升的。

实例如下:

【原文】If the const x = 2 declaration is not hoisted at all (as in, it only comes into effect when it's executed), then the console.log(x) statement should be able to read the x value from the upper scope. However, because the const declaration still "taints" the entire scope it's defined in, the console.log(x) statement reads the x from the const x = 2 declaration instead, which is not yet initialized, and throws a ReferenceError. Still, it may be more useful to characterize lexical declarations as non-hoisting, because from a utilitarian perspective, the hoisting of these declarations doesn't bring any meaningful features.

【翻译】如果说 const x = 2的声明完全没有被变量提升(那么它只在执行时生效),那么console.log(x)应该是能够从上层作用域中读取到x的值的。但此处因为const的声明依然“污染”到了它定义的整个作用域,所以console.log(x)语句实际上读取到的是const x = 2 声明的x,并抛出ReferenceError。尽管如此,将词汇声明(lexical declarations) 描述为非变量提升可能更有用,因为从功利的角度来看,这些变量提升不会带来任何有意义的特征。

【注意】以下这种情况不属于变量提升:

{var x = 1;
}
console.log(x); // 1
复制代码

因为这里没有“先访问后声明”,这里只是因为var声明没有在块范围内。

结论

综上所述,实际上letconst是存在变量提升的,但通常不会刻意去这样描述,因为从功利的角度来看,这些变量提升并不会带来任何有意义的特征。

给大家推荐一个实用面试题库

1、前端面试题库 (面试必备)            推荐:★★★★★

地址:前端面试题库

【面试题】【ES6】let和const命令 (面试必看)相关推荐

  1. ES6 let和const 命令

    ES6 let 和 const 命令 1. 变量声明 2. 变量提升问题 3. 暂时性死区(TDZ) 4. 块级作用域 4.1 为什么需要块级作用域? 4.2 ES6的块级作用域 4.3 块级作用域和 ...

  2. python开发工程师面试题-超实用面试必看,Python工程师面试题

    原标题:超实用面试必看,Python工程师面试题 面试是公司挑选职工的一种重要方法.它给公司和应招者提供了进行双向交流的机会,能使公司和应招者之间相互了解,从而双方都可更准确做出聘用与否.受聘与否的决 ...

  3. Java常见面试题 Java面试必看 (一)

    本篇博客是本人收集网上Java相关的资料整理所得,仅供参考. 一.Java基础 1.JDK 和 JRE区别 JDK(Java Development Kit)是针对Java开发员的产品,是整个Java ...

  4. Java常见面试题 Java面试必看 (二)

    Java常见面试题 Java面试必看 (一) 十一.Spring Boot/Spring Cloud 104.什么是 spring boot? Spring Boot 是由 Pivotal 团队提供的 ...

  5. 网络工程师面试题(面试必看)(3)

    作者简介:一名云计算网络运维人员.每天分享网络与运维的技术与干货.   座右铭:低头赶路,敬事如仪 个人主页:网络豆的主页​​​​​​ 前言 本系列将会提供网络工程师面试题,由多位专家整合出本系列面试 ...

  6. 最新iOS面试必看题视频教程(附大神简历要素)

    2019独角兽企业重金招聘Python工程师标准>>> 本文是由尚学堂iOS学院总结的ios开发者在求职时会遇到的一些面试题 ,并通过实际代码演练将课程详尽的讲解出来,希望对学习io ...

  7. 面试必看:java面试考点精讲视频教程

    面试必看:java面试考点精讲视频教程 Java作为目前比较火的计算机语言之一,连续几年蝉联最受程序员欢迎的计算机语言榜首,因此每年新入职Java程序员也数不胜数.很多java程序员在学成之后,会面临 ...

  8. 2019年黑马新版Java学习路线图(内含大纲+视频+工具+书籍+面试)面试必看!

    非常好的java学习路线,伴有配套资源. 面试必看! 黑马程序员:http://bbs.itheima.com/thread-386464-1-1.html

  9. ES6 let和const命令(3)

    const 用来声明常量.一旦声明,就不能改变. const在声明必须初始化,只声明不赋值会出错 const的作用域与let一样,只在声明的块级作用域有效. const命令声明的常量也不提升,同样存在 ...

最新文章

  1. tableau可视化数据分析60讲(十二)-过滤器详解
  2. Unix/Linux下文件基本操作[zt]
  3. Sparklens:Spark应用程序优化工具
  4. 第二十一期:干货盘点!推荐程序员使用的5款工具软件
  5. 你必须要知道的架构知识~第二章 代码是否面向对象,要看你的继承怎么用
  6. extundelete应用实战
  7. 通过opencv的函数进行图片修复:cv2.inpaint()
  8. C#LeetCode刷题之#31-下一个排列(Next Permutation)
  9. Linux 查看命令
  10. 计算机控制试压,试压泵计算机控制系统电脑控制试压泵自动记录功能
  11. mysql 优化器 cost评估_MySQL优化器cost计算
  12. c语言 滑窗法_滑窗算法
  13. python键值对是什么意思_python键值对
  14. 大规模手机定位采集系统设计
  15. Java合并流实现简单的文件合并示例
  16. 【从0到1搭建LoRa物联网】15、LoRa连接到The Things Network
  17. POJ1502 信息传递(单源最短路径)
  18. oracle 二进制算法,二进制搜索(查找)
  19. 一个谷粉和3年的Google Reader重度使用者的碎碎念
  20. 【SSH框架/国际物流商综平台】-01-分三期(仓储管理,货运全流程管理,决策分析)- 项目背景 界面原型 用例图 企业组织结构 功能模块图 系统框架 项目表单收集

热门文章

  1. r7 6800u核显相当于什么显卡
  2. java获取虾米数据_json获取属性值的方式
  3. 风袖第一阶段之每周上新
  4. 次世代游戏建模这7问
  5. 扬帆际海:如何成为一个合格的跨境电商运营?
  6. MMC,SD,TF各是什么
  7. 读书笔记||控制论、信息论、系统论
  8. 低配置系统安装 linux,在低配置机中安装Linux系统
  9. ⑦Java SE知识点回顾与小结(面向对象)
  10. 【VS】VS Code安装、配置、使用(windows10 64)