参考文档:
https://juejin.im/post/6844903811622912014#heading-25
1、ES6新特性
1.1 ESCMAScript 2015(ES6)有哪些新特性?
:::success
块作用域
- 类
- 箭头函数
- 模板字符串
- 解构赋值
- 对象结构
- Promise
- 模块
- Symbol
- 代理(proxy)Set
- 函数默认参数
- rest 和展开
:::
1.2 var、let和const的的区别是什么?
var声明的变量会挂在在window上,相当于全局变量,而let和const声明的变量不会:
var a = 100; console.log(a, window.a); //100 100
let b = 10; console.log(b, window.b); //10 undefined
const c= 1; console.log(c, window.c); //1 undefined
var声明的变量存在变量提升,let和const不存在变量提升:
console.log(a); // undefined ===> a已声明还没赋值,默认得到undefined值
var a = 100;
console.log(b); // 报错:b is not defined ===> 找不到b这个变量
let b = 10;
console.log(c); // 报错:c is not defined ===> 找不到c这个变量
const c = 10;
:::success
在上面的代码中变量a用var声明, 会发生变量提升, 即脚本开始运行时, 变量a已经存在了, 但是没有值, 所以会输出undefined。变量b和c用let和const声明, 不会发生变量提升。这表明在声明之前变量b和c是不存在的, 这时如果用到它,就会抛出一个错误。
:::
3. let和const声明形成块级作用域
if(true){
var a = 100;
let b = 10;
const c = 1;
}
console.log(a);
console.log(b); //b is not defined
console.log(c); //c is not defined
同一作用域下let和const不能声明同名变量,而var可以:
var a = 100;
console.log(a);
var a = 10 console.log(a);
let a = 1000; //'a' has already been declared
let a = 'aa';
暂存死区: :::success 只要块级作用域内存在let命令, 它所声明的变量就绑定在这个区域, 不在受外部的影响。 :::
var a = 100;
if(true){
a =10;
let a =1;
}
:::success 上面的代码中, 存在全局变量a, 但是块级作用域内let又声明了一个局部变量a, 导致后者绑定这个块级作用域, 所以let声明变量前, 对变量a赋值就会报错。
ES6明确规定, 如果区块中存在let和const命令,这个区块对这些命令的变量, 从一开始就形成了封闭作用域。凡是在声明变量之前使用该变量,就会报错。
总之,在代码块内, 使用let命令声明变量之前, 改变量都是不可使用的。这在语法上被称为“暂时性死区(TDZ)” :::const与let区别:
一旦申明必须赋值,不能使用null占位;
2. 声明后不能在修改
3. 如果声明的是引用类型数据,可以修改其属性。const a = 100;
const list = [];
list[0] = 10;
console.log(list);// [10]
const obj = {a:100};
obj.name = 'apple';
obj.a = 10000;
console.log(obj); // {a:10000,name:'apple'}
3. 箭头函数是什么?
JS中 => 是箭头函数,是ES6标准中新增的一种新的函数。箭头函数表达式的语法比函数表达式更简单。并且没有自己的this,argumnets,super或new.target.箭头函数适用于那些本来需要使用匿名函数的地方,并且它不能用作构造函数(箭头函数没有prototype属性)。
const data = {
result: 0,
nums: [1, 2, 3, 4, 5],
computeResult() {
// 这里的“this”指的是“data”对象
const addAll = () => {
return this.nums.reduce((total, cur) => total + cur, 0)
};
this.result = addAll();
console.log(data.result);
}
data.computeResult()
箭头函数没有自己 的this值。如果在全局作用域声明箭头函数,则this值为window。
4. 什么是Set对象,与WeakSet的区别是什么?
4.1 Set基本用法: :::success ES6提供了新的数据结构Set.它类似数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成Set数据结构。 :::const s = new Set();
[11,22,33,44,33,22].forEach(x=> s.add(x));
console.log(s); //Set(4) {11, 22, 33, 44}
console.log([...s]); //[11, 22, 33, 44]
console.log(Array.from(s)); //[11, 22, 33, 44]
Set函数可以接收一个数组(可用于数组去重)
const arr = new Set([00,11,22,33,66,88,33,22,00]);
console.log(arr);
console.log([...arr]);
console.log(arr.size); //6 arr的长度
console.log(arr.delete(11)); //true 是否删除成功
arr.clear()
console.log(arr); //清空数组
Set 结构的实例有四个遍历方法,可以用于遍历成员:
- keys()
- values()
- entries()
- forEach()
Set结构转化为数组:
console.log([...s]);
//[11, 22, 33, 44]
console.log(Array.from(s)); //[11, 22, 33, 44]
也可以把Set结构转化为数组类型,可以使用map和filter方法。
Set可以实现并集、交集和差集:
let a = new Set([11,22,33,44]);
let b = new Set([33,66,22,55]);
//并集
let union = new Set([...a,...b]);
//交集
let intersect = new Set([...a].filter(x => b.has(x)));
//差集
let difference = new Set([...a].filter(x => !b.has(x)));
注意:
let s1 = new Set();
s1.add([1]);
s1.add([1]);
console.log(s1.size);
//2
/**
* 这两个数组[1]并不是同一个值,他们分贝定义的数组,在内存中分别对应着不同的存储地址,
* 因此并不是相同的值。所以能存储到Set结构中。
*/ let s2 = new Set();
s2.add(1);
s2.add(1);
console.log(s2.size); //1
WeakSet
WeakSet和Set一样也是不重复值的集合。但是和Set的区别:
(1) WeakSet的成员只能是对象,而不能是其他类型
const ws = new WeakSet();
ws.add(1) // TypeError: Invalid value used in weak set ws.add(Symbol())
// TypeError: invalid value used in weak set
(2)WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用。
const a = [[11,22],[33,44]];
const ws = new WeakSet(a);
console.log(ws);
const b = [11,22];
const ws2 = new WeakSet(b) //报错
WeakSet 结构有以下三个方法:
- WeakSet.prototype.add(value):向 WeakSet 实例添加一个新成员。
- WeakSet.prototype.delete(value):清除 WeakSet 实例的指定成员。
WeakSet.prototype.has(value):返回一个布尔值,表示某个值是否在 WeakSet 实例之中。
5. 类(class)
class就是类,和ES5中的构造函数十分类型,但是class的写法能让对象原型的功能更加清晰,更加符合面向对象的语言特点。
class Person{
constructor(name, age)
{
this.name = name;
this.age = age;
this.color = ['red'];
}
getName(){
console.log(this.name);
}
}
class Child extends Person{
constructor(name, age)
{
super(name, age)
}
}
const Jack = new Child('Jack',20);
const Iric = new Child('Iric',23);
Jack.color.push('pink');
Iric.color.push('orange');
Jack.getName();
Iric.getName();
console.log(Jack);
console.log(Iric);
区别:class的内部所有定义的方法,都是不可枚举的。而原型上面定义的方法都是可以枚举的。
class所有的方法和属性都定义在类的prototype属性上。6. 模块化(Module)
E6模块不是对象,而是通过export命令显示指定输入的代码,在通过import命令输出。
模块功能主要由两个命令构成: export和import。export命令用于规定模块的对外接口;
- import命令用于输入其他模块提供的功能。
6.1 导出(export)
ES6允许在一个模块中使用export来导出多个变量来或函数。 ```javascript export let name = ‘lisa’; let name = ‘Jack’; let age = 20; export {name, age}; export function getData(){ //do something }
通常情况下, export输出的变量就是本来的名字,但是可以使用as关键字重命名。
```javascript
export { v1 as streamV1, v2 as streamV2, v3 as streamLatestVersion };
- export和export Default均可以导出常量、函数、文件和模块等;
- 在一个文件或者模块中,export和import可以有多个,但是export Default只有一个。
- 通过export导出,在导入的时候需要加{ }, 由export default则不需要加{}.
6.2 导入(import)
如果想为输入的变量重新取一个名字,import命令要使用as关键字,将输入的变量重命名。import { firstName, lastName, year } from './profile.js';
import { lastName as surname } from './profile.js';
举例:import { foo } from 'my_module';
import { bar } from 'my_module';
// 等同于 import { foo, bar } from 'my_module';
逐一指定要加载的方法:// circle.js
export function area(radius) {
return Math.PI * radius * radius;
}
export function circumference(radius) {
return 2 * Math.PI * radius;
}
整体加载的写法如下:// main.js
import { area, circumference } from './circle';
console.log('圆面积:' + area(4));
console.log('圆周长:' + circumference(14));
7. 函数参数的默认值
在ES6中,支持定义函数的时候为其设置默认值:
一个容易忽略的地方是,参数默认值不是传值的,而是每次都重新计算默认值表达式的值。也就是说,参数默认值是惰性求值的。function foo(height = 50, color = 'red') {
// ...
}
不使用默认值:
function foo(height, color) {
var height = height || 50; var color = color || 'red'; //...
}
8. 模板字符串
ES6支持模板字符串,使得字符串的拼接跟腱简洁、直观。//不使用模板字符串:
var name = 'Your name is ' + first + ' ' + last + '.'
//使用模板字符串:
var name = `Your name is ${first} ${last}.`
9. 解构赋值
9.1 数组的结构赋值
从数组中获取值并赋值到变量中,变量的顺序与数组中顺序对应。数组的元素是按次序排列的,变量的取值由它的位置决定。const [a,b,c,d] = [11,22,33,44];
console.log(a,b,c,d); //11 22 33 44
const [a1,b1,c1] = [77,,99];
console.log(a1,b1,c1); //77 undefined 99
//默认值
let [m = 10, n=20] = [null,,];
console.log(m,n); //null 20
let [m = 10, n=20] = [undefined,,];
console.log(m,n); //10 20
//交换2个变量的值
var a = 10;
var b = 20;
[a, b] = [b,a];
console.log(a,b); //20 10
9.2 对象的解构赋值
对象的属性没有次序,变量必须与属性名同名,才能取到正确的值。const student = { name:'Ming', age:'18', city:'Shanghai' };
const {name,age,city} = student;
console.log(name); // "Ming"
console.log(age); // "18"
console.log(city); // "Shanghai"
10. 延展操作符(spread operator)
延展操作符…可以在函数调用、数组构造时,将数组或者string在语法层面展开,还可以在构造对象时,将对象表达式按key-value的方式展开。
函数调用:
myFunction (…iterableObj)
数组构造或字符串:
[…iterableObj,’haha’,…’hello’,78]
对象(浅拷贝):
let objClone = {…obj}11. Promise
Promise是异步编程的一种解决方案,比传统的解决方案callback更加的优雅。
Promise构造函数是同步执行的,then()方法是异步执行的。
不使用promise:
使用ES6:setTimeout(
function() {
console.log('Hello');
// 1秒后输出"Hello"
setTimeout(function() {
console.log('Hi'); // 2秒后输出"Hi"
},
1000);
}, 1000);
12. reducevar waitSecond = new Promise(function(resolve, reject){
setTimeout(resolve,1000)
});
waitSecond.then(function(){
console.log('hello');
return waitSecond;
}).then(function(){
console.log('nihao');
})
18 filterbookList: [
{
id: 1,
name: "HTML5",
date: "2020-10-23",
price: 25,
count: 10,
},
{
id: 2,
name: "CSS3",
date: "2020-10-23",
price: 25,
count: 10
},
{
id: 3,
name: "React",
date: "2020-10-23",
price: 25,
count: 10,
},
],
totalPrice() {
let total_price = this.bookList.reduce((prev, cur) => {
return prev + cur.count*cur.price
},
0);
return total_price;
},
filter的回调函数有一个要求: 必须返回一个boolean值, 当返回true时,函数内部会自动将这次回调的n加入到新的数组中,返回false,就会过滤掉这个值。二、ES7新特性
2.1 Array.prototype.inlcudes()
includes() 函数用来判断一个数组是否包含一个指定的值,如果包含则返回true,否则返回false.
includes函数与indexOf函数相似,下面两个表达式是等价的:const arr = ['vue','react','CSS3'];
if(arr.indexOf('vue') !== -1){
console.log('vue存在');
}
if(arr.includes('vue')){
console.log('vue存在');
}
2.2 求幂运算符(**)
Math.pow(3, 2) === 3 ** 2 // 9三、ES8新特性
3.1 async/await
答:ES2018引入异步迭代器,这就像常规迭代器,除了next()方法返回一个Promise.因此await可以和for…of循环一起使用,以串行的方式运行异步操作。例如:async function add(array){
for await (let i of array){
console.log(i);
}
}
add([11,22,33])
3.2 Object.values()
Object.values()是一个与Object.keys()类似的新函数,但返回的是Object自身属性的所有值,不包括继承的值。const obj = {a:11, b:22, c:33};
console.log(Object.keys(obj));
//[ 'a', 'b', 'c' ]
console.log(Object.values(obj)); //[ 11, 22, 33 ]
3.3 Object.entries()
Object.entries()函数返回一个给定对象自身可枚举的属性的键值对的数组。const obj = {a:11, b:22, c:33};
console.log(Object.keys(obj));
//[ 'a', 'b', 'c' ]
console.log(Object.values(obj));
//[ 11, 22, 33 ]
console.log(Object.entries(obj)); [ [ 'a', 11 ], [ 'b', 22 ], [ 'c', 33 ] ]
3.4 Object.fromEntries()
将键值对列表转化为一个对象。const obj = {a:11, b:22, c:33};
console.log(Object.keys(obj));
//[ 'a', 'b', 'c' ]
console.log(Object.values(obj)); //[ 11, 22, 33 ]
console.log(Object.entries(obj));
[ [ 'a', 11 ], [ 'b', 22 ], [ 'c', 33 ] ]
const aa = Object.entries(obj);
console.log(Object.fromEntries(aa)); //{ a: 11, b: 22, c: 33 }
3.5 Object.getOwnPropertyDescriptors()
Object.getOwnPropertyDescriptors()函数用来获取一个对象的所有自身属性的描述,如果没有任何属性,则返回空对象。
四、ES9新特性const obj2 = {
name: 'Jine',
get age() {
return '18'
}
};
console.log(Object.getOwnPropertyDescriptors(obj2));
1.Promise.finally()
一个Promise调用链要么成功到达最后一个.then(),要么失败触发.catch()。在某些情况下,你想要无论失败还是成功都运行一段代码,例如清楚、删除对话框等等。
.finally()允许你指定最终的逻辑:function doSomething(){
doSomething1()
.then(doSomething2)
.then(doSomething3)
.catch(err => {
console.log(err);
})
.finally(() => {
//finish here
})
}