ES6入门教程之let、const的使用方法


Posted in Javascript onApril 13, 2019

一、前提

解决ES5中只有全局作用域和函数作用域,没有块级作用域而带来的不合理的场景。

let

基本用法

用法和var 一样,只是let声明的变量只有在let命令所在的代码块有效

{
 let a = 10;
 var b = 1;
}

a // ReferenceError: a is not defined.
b // 1

可以看出var 声明的变量在代码块之外也是可以调用,而let声明的则调用报错。所以let 声明只在它声明的当前代码块中才能调用。

变量提升

在使用 var 的时候会出现 “变量提升”的现象,即变量可以在声明之前使用,值为undefined。let 改变了这种现状,但是必须先声明在使用,如果在声明之前使用则会出现报错。如下:

// var 的情况
console.log(foo); // 输出undefined
var foo = 2;

// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;

暂时性死区

只要块级作用域内部存在 let 或者 const 命令,它所声明的变量就“绑定”在这个区域,不会受外部影响。且暂时性死区的本质就是,只要一进入当前作用域,所要使用的变量就已经存在了,但是不可获取,只有等到声明变量的那一行代码出现,才可以获取和使用该变量。如下:

var tmp = 123;

if (true) {
 tmp = 'abc'; // ReferenceError
 let tmp;
}

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

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

if (true) {
 // TDZ开始
 tmp = 'abc'; // ReferenceError
 console.log(tmp); // ReferenceError

 let tmp; // TDZ结束
 console.log(tmp); // undefined

 tmp = 123;
 console.log(tmp); // 123
}

注意:

++使用let声明变量时,只要变量在还没有声明完成前使用,就会报错。上面这行就属于这个情况,在变量x的声明语句还没有执行完成前,就去取x的值,导致报错”x 未定义“。++

不允许重复声明

let 不允许在同一个作用域内声明同一个变量,如下:

// 报错
function func() {
 let a = 10;
 var a = 1;
}

// 报错
function func() {
 let a = 10;
 let a = 1;
}

或者如下:

function func(arg) {
 let arg;
}
func() // 报错

function func(arg) {
 {
 let arg;
 }
}
func() // 不报错

块级作用域

上面也提到过在es5中没有块级作用域的概念,只有函数作用域和全局作用域,那么就带来了一些问题,如下:

var tmp = new Date();

function f() {
 console.log(tmp);
 if (false) {
 var tmp = 'hello world';
 }
}

f(); // undefined


外层声明被内层声明所覆盖,内层使用的是外层的声明,内层变量提升导致 undefinded

第二种:计数循环全局泄露,如下:

var s = 'hello';

for (var i = 0; i < s.length; i++) {
 console.log(s[i]);
}

console.log(i); // 5

常见的面试题,最后输出不是预料中的 1 2 3 4 5 而全部是 5

ES6的块级作用域,实际上就是let 新增的,如下:

function f1() {
 let n = 5;
 if (true) {
 let n = 10;
 }
 console.log(n); // 5
}

内外层的 n 互不干扰

ES6中 允许作用域任意嵌套,并且互不干扰,如下:

内外层可以同名

{{{{
 let insane = 'Hello World';
 {let insane = 'Hello World'}
}}}};

或者

{{{{
 {let insane = 'Hello World'}
 console.log(insane); // 报错
}}}};

块级作用域的出现可以让以下立即执行函数的写法不必要,如下:

// IIFE 写法
(function () {
 var tmp = ...;
 ...
}());

// 块级作用域写法
{
 let tmp = ...;
 ...
}

块级作用域和函数声明

在ES5中,函数只能在顶层作用域和函数作用域中声明,不能在块级作用域中声明,但是浏览器为了兼容性,还是可以在块级作用域中声明,理论上在ES6中 块级作用域中声明的函数,在外部调用会报错,考虑环境的问题,应当避免在块级作用域中声明函数,如果需要也应当写成函数表达式的方式,而不是函数声明语句,如下:

// 函数声明语句
{
 let a = 'secret';
 function f() {
 return a;
 }
}

// 函数表达式
{
 let a = 'secret';
 let f = function () {
 return a;
 };
}

const

const声明的是一个常量 如下:

const PI = 3.1415;
PI // 3.1415

PI = 3;
// TypeError: Assignment to constant variable.

声明之后如果在赋值,将会报错,同时因为声明的是常量,即const声明后即要赋值不然也会报错
const 和 let 相同,声明也只在当前的块级作用域生效。同样也不会声明提升,也存在暂时死区,只能在声明之后使用,且和 let 一样不得重复声明,不能重新赋值。

重要:

const 所不能改变的并不是值,而是变量指向的那个内存地址所保存的值不能变动,对于简单类型(数值、字符串、布尔值),值就保存在变量所指向的内存地址中,因此等同于常量。而对于复合类型(数组、对象),变量指向的内存地址,保存的只是一个指向实际数据的指针,const 只能保证这个指针是固定的(即总指向一个固定的地址)。至于它指向的数据结构则是不能控制的 ,如下:

const foo = {};

// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123

// 将 foo 指向另一个对象,就会报错
foo = {}; // TypeError: "foo" is read-only

常量foo储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,
即不能把foo指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。

或者

const a = [];
a.push('Hello'); // 可执行
a.length = 0; // 可执行
a = ['Dave']; // 报错

常量a是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给a,就会报错

如果真的想将声明对象冻结,不能在改变 则应该使用object.freeze()

const foo = Object.freeze({});

// 常规模式时,下面一行不起作用;
// 严格模式时,该行会报错
foo.prop = 123;

对象也可以冻结

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

ES6 声明变量的六种方法

1. function
2. var
3. let
4. const
5. import
6. class

顶层对象的属性

在浏览器环境指的是window对象,在 Node 指的是global对象,ES5 之中,顶层对象的属性与全局变量是等价的。

window.a = 1;
a // 1

a = 2;
window.a // 2

global 对象

ES5 的顶层对象,本身也是一个问题,因为它在各种实现里面是不统一的。

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

同一段代码为了能够在各种环境,都能取到顶层对象,现在一般是使用this变量,但是有局限性。

  1. 全局环境中,this会返回顶层对象。但是,Node 模块和 ES6 模块中,this返回的是当前模块。
  2. 函数里面的this,如果函数不是作为对象的方法运行,而是单纯作为函数运行,this会指向顶层对象。但是,严格模式下,这时this会返回undefined。
  3. 不管是严格模式,还是普通模式,new Function('return this')() ,总是会返回全局对象。但是,如果浏览器用了 CSP(Content Security Policy,内容安全策略),那么eval、new Function这些方法都可能无法使用。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对三水点靠木的支持。

Javascript 相关文章推荐
javascript 避免闭包引发的问题
Mar 17 Javascript
js操作输入框中选择内容兼容IE及其他主流浏览器
Apr 22 Javascript
node.js中的require使用详解
Dec 15 Javascript
jQuery验证插件validation使用指南
Apr 21 Javascript
jQuery实现表格展开与折叠的方法
May 04 Javascript
javascript瀑布流布局实现方法详解
Feb 17 Javascript
JS封装通过className获取元素的函数示例
Dec 20 Javascript
Vue.js实现开发购物车功能的方法详解
Feb 22 Javascript
小程序如何使用分包加载的实现方法
May 22 Javascript
前端Vue项目详解--初始化及导航栏
Jun 24 Javascript
js如何实现元素曝光上报
Aug 07 Javascript
vue 实现图片懒加载功能
Dec 31 Vue.js
ES6入门教程之变量的解构赋值详解
Apr 13 #Javascript
微信小程序template模版的使用方法
Apr 13 #Javascript
vue基于viewer实现的图片查看器功能
Apr 12 #Javascript
js form表单input框限制20个字符,10个汉字代码实例
Apr 12 #Javascript
详解js创建对象的几种方法及继承
Apr 12 #Javascript
详解JQuery基础动画操作
Apr 12 #jQuery
React中阻止事件冒泡的问题详析
Apr 12 #Javascript
You might like
hessian 在PHP中的使用介绍
2010/12/13 PHP
php控制文件下载速度的方法
2015/03/24 PHP
利用PHP如何实现Socket服务器
2015/09/23 PHP
PHP版本升级到7.x后wordpress的一些修改及wordpress技巧
2015/12/25 PHP
遍历指定目录,并存储目录内所有文件属性信息的php代码
2016/10/28 PHP
laravel5表单唯一验证的实例代码
2019/09/30 PHP
PHP7创建销毁session的实例方法
2020/02/03 PHP
Ext对基本类型的扩展 ext,extjs,format
2010/12/25 Javascript
返回对象在当前级别中是第几个元素的实现代码
2011/01/20 Javascript
JavaScript实现仿新浪微博大厅和腾讯微博首页滚动特效源码
2015/09/15 Javascript
详解AngularJs HTTP响应拦截器实现登陆、权限校验
2017/04/11 Javascript
JavaScript订单操作小程序完整版
2017/06/23 Javascript
旺旺在线客服代码 旺旺客服代码生成器
2018/01/09 Javascript
JavaScript设计模式之构造器模式(生成器模式)定义与用法实例分析
2018/07/26 Javascript
js 实现 list转换成tree的方法示例(数组到树)
2019/08/18 Javascript
使用vue构建多页面应用的示例
2020/10/22 Javascript
[01:00:11]DOTA2-DPC中国联赛 正赛 CDEC vs DLG BO3 第一场 2月7日
2021/03/11 DOTA
python实现dijkstra最短路由算法
2019/01/17 Python
对Python中TKinter模块中的Label组件实例详解
2019/06/14 Python
在macOS上搭建python环境的实现方法
2019/08/13 Python
安装Pycharm2019以及配置anconda教程的方法步骤
2019/11/11 Python
python实现单目标、多目标、多尺度、自定义特征的KCF跟踪算法(实例代码)
2020/01/08 Python
python 用opencv实现图像修复和图像金字塔
2020/11/27 Python
css3 flex布局 justify-content:space-between 最后一行左对齐
2020/01/02 HTML / CSS
英国图书音像网站:Hive.co.uk(图书、电子书、DVD、蓝光、音乐CD等)
2017/10/16 全球购物
医学生个人求职信范文
2013/09/24 职场文书
外企办公室竞聘演讲稿
2013/12/29 职场文书
小学三八妇女节活动方案
2014/03/16 职场文书
个人反四风对照检查材料思想汇报
2014/09/23 职场文书
群众路线问题查摆对照检查材料
2014/10/04 职场文书
小学感恩节活动策划方案
2014/10/06 职场文书
高一化学教学反思
2016/02/22 职场文书
python本地文件服务器实例教程
2021/05/02 Python
LayUI+Shiro实现动态菜单并记住菜单收展的示例
2021/05/06 Javascript
Vue详细的入门笔记
2021/05/10 Vue.js
Android开发手册自定义Switch开关按钮控件
2022/06/10 Java/Android