ES6常用语法
ES6 的变量声明: let 和 const
ES6 中新增了 let 和 const 来定义变量:
var
:ES5 和 ES6 中,定义全局变量(是 variable 的简写)。let
:定义局部变量,替代 var。const
:定义常量(定义后,不可修改)。
var:全局变量
看下面的代码:
1 | { |
上方代码是可以输出结果的,输出结果为 1。因为 var 是全局声明的,所以,即使是在区块里声明,但仍然在全局起作用。
再来看下面这段代码:
1 | var a = 1; |
上方代码的输出结果为 2 ,因为 var 是全局声明的。
总结:
用 var 定义的全部变量,有时候会污染整个 js 的作用域。
let:定义局部变量
1 | var a = 2; |
上方代码的输出结果为 2。用 let 声明的变量,只在局部(块级作用域内)起作用。
let 是防止数据污染,我们来看下面这个 for 循环的例子,很经典。
1、用 var 声明变量:()
1 | for (var i = 0; i < 10; i++) { |
上方代码可以正常打印结果,且最后一行的打印结果是 10。说明循环体外定义的变量 i,是在全局起作用的。
2、用 let 声明变量:
1 | for (let i = 0; i < 10; i++) { |
上方代码的最后一行无法打印结果,也就是说打印会报错。因为用 let 定义的变量 i,只在{ }
这个块级作用域里生效。
总结:我们要习惯用 let 声明,减少 var 声明带来的污染全局空间。
为了进一步说明 let 不会带来污染,需要说明的是:当我们定义了let a = 1
时,如果我们在同一个作用域内继续定义let a = 2
,是会报错的。
const:定义常量
在程序开发中,有些变量是希望声明后,在业务层就不再发生变化,此时可以用 const 来定义。
举例:
1 | const name = "smyhvae"; //定义常量 |
用 const 声明的变量,只在局部(块级作用域内)起作用。
let 和 const 的作用【重要】
let 和 const 的作用如下:
禁止重复声明
支持块级作用域
控制修改
相反, 用var
声明的变量:可以重复声明、没有块级作用域、不能限制。
暂时性死区问题说明:其实 let 和 const 是有变量提升的,但是没有初始化提升:
1 | var name = "zs"; |
块级作用域
解决问题:
1 | for (var i = 0; i < 5; i++) { |
for 循环举例【经典案例】
代码 1、我们先来看看如下代码:(用 var 定义变量 i)
1 |
|
上方代码中的运行效果如下:
你可能会感到诧异,为何点击任何一个按钮,弹出的内容都是 4 呢?这是因为,我们用 var 定义的变量 i,是在全局作用域声明的。整个代码中,自始至终只有一个变量。当我们还没点击按钮之前,变量 i 已经循环到 4 了。
也就是说,上面的 for 循环,相当于如下代码:
1 | var i = 0; |
代码 2、上面的代码中,如果我们改为用 let 定义变量 i:
1 |
|
上方代码中的运行效果如下:
上面这个运行结果,才是我们预期的效果。我们用 let 定义变量 i,在循环的过程中,每执行一次循环体,就会诞生一个新的 i。循环体执行 4 次,就会有四个 i。
let 与 const 都是只在声明所在的块级作用域内有效。
let 声明的变量可以改变,值和类型都可以改变,没有限制。而 const 声明的是常亮,值和类型都不能改变。
对于引用类型的变量,const 命令只是保证变量名指向的地址不变,并不保证该地址的数据不变。如果想让定义的对象或数组的内部数据也不能够修改和改变,可以使用 object.freeze(names)进行冻结,这样为对象添加新属性就不起作用。
Example:
1 | { |
本质
const 实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于简单类型的数据(数值、字符串、布尔值),值就保存在变量指向的那个内存地址,因此等同于常量。但对于复合类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const 只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
1 | const foo = {}; |
上面代码中,常量 foo 储存的是一个地址,这个地址指向一个对象。不可变的只是这个地址,即不能把 foo 指向另一个地址,但对象本身是可变的,所以依然可以为其添加新属性。
下面是另一个例子。
1 | const a = []; |
上面代码中,常量 a 是一个数组,这个数组本身是可写的,但是如果将另一个数组赋值给 a,就会报错。
如果真的想将对象冻结,应该使用 Object.freeze
方法。
1 | const foo = Object.freeze({}); |
上面代码中,常量 foo 指向一个冻结的对象,所以添加新属性不起作用,严格模式时还会报错。
除了将对象本身冻结,对象的属性也应该冻结。下面是一个将对象彻底冻结的函数。
1 | var constantize = obj => { |
解构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构
Example:
1 | //ES5 |
数组嵌套解构
1 | let [a, [[b], c]] = [1, [[2], 3]]; |
数组解构设置默认值
1 | let [x, y = "b"] = ["a"]; // x='a', y='b' |
对象解构赋值
1 | let { a, b } = { a: "aaa", b: "bbb" }; |
undefined
和null
的区别
如果我们在赋值时,采用的是 undefined
或者null
,那会有什么区别呢?
1 | { |
上方代码分析:
undefined:相当于什么都没有,此时 b 采用默认值。
null:相当于有值,但值为 null。
对象解构设置默认值
1 | let { x, y = "x" } = { x: "x", y: "y" }; |
圆括号的使用
如果变量 foo 在解构之前就已经定义了,此时你再去解构,就会出现问题。下面是错误的代码,编译会报错:
1 | let foo = 'haha'; |
要解决报错,只要在解构的语句外边,加一个圆括号即可:
1 | let foo = "haha"; |
字符串解构
字符串也可以解构,这是因为,此时字符串被转换成了一个类似数组的对象。举例如下:
1 | const [a, b, c, d] = "smyhvae"; |
输出结果:
字符串的扩展
ES6 中的字符串扩展,用得少,而且逻辑相对简单。如下:
includes(str)
:判断是否包含指定的字符串startsWith(str)
:判断是否以指定字符串开头endsWith(str)
:判断是否以指定字符串结尾repeat(count)
:重复指定次数
举例如下:
1 | let str = "abcdefg"; |
打印结果:
模板字符串
我们以前让字符串进行拼接的时候,是这样做的:(传统写法的字符串拼接)
1 | var name = "smyhvae"; |
这种写法,比较繁琐,而且容易出错。
现在有了 ES6 语法,字符串拼接可以这样写:
1 | var name = "smyhvae"; |
注意,上方代码中,倒数第二行用的符号是单引号,最后一行用的符号是反引号(在 tab 键的上方)。
Number 的扩展
- 二进制与八进制数值表示法: 二进制用
0b
, 八进制用0o
。
举例:
1 | console.log(0b1010); //10 |
Number.isFinite(i)
:判断是否为有限大的数。比如Infinity
这种无穷大的数,返回的就是 false。Number.isNaN(i)
:判断是否为 NaN。Number.isInteger(i)
:判断是否为整数。Number.parseInt(str)
:将字符串转换为对应的数值。Math.trunc(i)
:去除小数部分。
举例:
1 | //Number.isFinite(i) : 判断是否是有限大的数 |
数组的新增方法
数组的相关文档,可参考:Array 对象
扩展运算符
1 | console.log(...[1, 2, 3]) |
includes(value,index)
该方法的第二个参数表示搜索的起始位置,默认为 0。如果第二个参数为负数,则表示倒数的位置,如果这时它大于数组长度(比如第二个参数为-4,但数组长度为 3),则会重置为从 0 开始。
1 | [1, 2, 3] |
filter 方法
filter 用来过滤数组中不满足条件的元素, 把满足条件的元素放到新的数组里, 并且不会改变原数组
1 | let array = [1, 2, 3, 4, 5]; |
every 方法:
every 会遍历数组, 判读是否满足给定的条街, 如果每一项都是 true, 就会返回 true, 只要有一个是 false, 就会返回 false
1 | let array = [1, 2, 3, 4, 5]; |
some 方法
some 会遍历数组, 判读是否满足给定的条件, 只要有一项 true, 就会返回 true, 否则返回 false
1 | let array = [1, 2, 3, 4, 5]; |
reduce 方法
接收一个函数作为累加器, 数组中每个值(从左到右)开始缩减, 最终为一个值,也就是计算总合
1 | let array = [1, 2, 3, 4, 5]; |
example:
输出字符串中每个字符出现的次数
1 | var arr = "abcdaabc"; |
数组去重
1 | let person = [ |
for … of 循环
ES6 中,如果我们要遍历一个数组,可以这样做:
1 | let arr1 = [1, 2, 3, 4, 5]; |
输出结果:
for…of 的循环可以避免我们开拓内存空间,增加代码运行效率,所以建议大家在以后的工作中使用 for…of 循环。
注意,上面的数组中,for ... of
获取的是数组里的值;for ... in
获取的是 index 索引值。
对象的新增方法
对象的相关文档,可参考:Object 对象
Object.is
1 | Object.is(v1, v2); |
判断两个数据是否完全相等。底层是通过字符串来判断的
我们先来看下面这两行代码的打印结果:
1 | console.log(0 == -0); |
打印结果:
1 | true |
上方代码中,第一行代码的打印结果为 true,这个很好理解。第二行代码的打印结果为 false,因为 NaN 和任何值都不相等。
但是,如果换成下面这种方式来比较:
1 | console.log(Object.is(0, -0)); |
打印结果却是:
1 | false |
代码解释:还是刚刚说的那样,Object.is(v1, v2)
比较的是字符串是否相等。
Object.assign
Object.assign 用于对象的合并,方法的第一个参数是目标对象,后面的参数都是源对象。
1 | const target = { a: 1 }; |
Object.keys 和 Object.values
Object.keys 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。
Object.values 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。
1 | var obj = { a: "aaa", b: "bbb" }; |
Object.entries 和 Object.fromEntries
Object.entries 方法返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。
Object.fromEntries 方法是 Object.entries 的逆操作,用于将一个键值对数组转为对象。
1 | var obj = { a: "aaa", b: "bbb" }; |
Promise 对象
Promise 对象的相关文档,可参考:Promise 对象
Promise 是异步编程的一种解决方案,比传统的解决方案——回调函数和事件——更合理和更强大。
Promise 对象代表一个异步操作,有三种状态:pending(进行中)、fulfilled(已成功)和 rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态
基本用法:
1 | const promise = new Promise(function (resolve, reject) { |
Promise.prototype.then()
then 方法参数是 resolved 状态的回调函数。
1 | axios.get("/xxx").then(function (result) { |
Promise.prototype.catch()
catch 方法的参数是 reject 状态的回调函数。
1 | axios.get("/xxx").catch(function (err) { |
Promise.prototype.finally()
finally 方法的参数是 reject 状态的回调函数。
1 | axios.get("/xxx").finally(() => { |
Promise.all()
Promise.all 方法接受一个数组作为参数,p1、p2、p3 必须为 Promise 实例
1 | Promise.all([p1, p2, p3]); |
Promise.race()
Promise.race 方法同样是将多个 Promise 实例,包装成一个新的 Promise 实例
1 | const p = Promise.race([p1, p2, p3]); |
Promise.resolve()
Promise.resolve(result)会返回一个新的 Promise 实例,该实例的状态为 fulfilled。
1 | const p = Promise.resolve("成功了"); |
Promise.reject()
Promise.reject(err)会返回一个新的 Promise 实例,该实例的状态为 rejected。
1 | const p = Promise.reject("出错了"); |