ES6常用新特性(一)

前言

ES6增加了不少新特性,灵活运用可以大幅提高工作效率,下面总结了一下比较常用的新特性。

  • let const
  • 解构赋值
  • 模板字符串
  • 数组拓展
  • 箭头函数
  • 对象拓展

let

1
2
3
4
5
6
7
8
9
10
11
12
13
function test(){
for(let i=1;i<3;i++){
console.log(i);// 1 2
}
console.log(i); // Uncaught ReferenceError: i is not defined
//如果是var则此处i=3

let a = 1;
let a = 2;
//报错Uncaught SyntaxError: Identifier 'a' has already been declared

}
test();
  • let拥有块级作用域(花括号内就是一个块)
  • es6强制开启严格模式
    严格模式下,没有变量提升,变量未声明,不能引用,报错Uncaught ReferenceError: a is not defined,而不是undefined
  • let声明后的变量不能重复声明

const

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
function last(){
const PI=3.14159265;
PI = 6;
console.log(PI); //Uncaught TypeError: Assignment to constant variable.


const PI;
PI = 6;
console.log(PI);//Uncaught SyntaxError: Missing initializer in const declaration


const x={
a:1
}
console.log(x); //{a: 1}

//x.b=2;
//console.log(x); //{a: 1, b: 2}

}
last();
  • const同样拥有块级作用域
  • const声明基础类型值时是常量,不能被赋值修改
  • const必须声明时赋值,否则报错Uncaught SyntaxError: Missing initializer in const declaration
  • const声明引用类型值时,可以被修改

解构赋值

  • 什么是解构赋值?
    ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构

数组解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
let [a, b, c] = [1, 2, 3];

//等价于
let a = 1;
let b = 2;
let c = 3;

let [a, b, c=3] = [1, 2];
console.log(a,b,c); //1,2,3

let [a, b, c] = [1, 2];
console.log(a,b,c); //1,2,undefined


{
let a,b,c;
[a,b,...c]=[1,2,3,4,5,6];
console.log(a,b,c);
//1,2,[3, 4, 5, 6]
}

适用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//变量交换
{
let a=1;
let b=2;
[a,b]=[b,a];
console.log(a,b); //2,1
}

//数组
{
function fn(){
return [1,2]
}
let a,b;
[a,b]=fn();
console.log(a,b); //1,2
//es5需要用数组下标获取对应值
//a = fn()[0];
//b = fn()[1];
}

//返回多个值时,可以选择性的接受某几个变量
{
function fn(){
return [1,2,3,4,5]
}
let a,b,c;
[a,,,b]=fn();
console.log(a,b); //1,4
}

//不确定数组返回长度时,想要的值只有前几个
{
function fn(){
return [1,2,3,4,5]
}
let a,b,c;
[a,,...b]=fn();
console.log(a,b); //1,[3, 4, 5]
}
//let a,b,c;
//[a,,...b,c]=fn();
//console.log(a,b,c);
//Uncaught SyntaxError: Rest element must be last element
//...b必须是最后一个元素

对象解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
let a,b;
({a,b}={a:1,b:2})
console.log(a,b); //1,2
}

{
let a={x:42,y:true};
let {x,y}=a;
console.log(x,y); //42,true
}

{
let {a=10,b=5}={a:3};
console.log(a,b); //3,5
}

适用场景

1
2
3
4
5
6
7
8
9
10
11
12
13
//获取对象的属性值
{
let metaData={
title:'abc',
test:[{
title:'test',
desc:'description'
}]
}
let {title:esTitle,test:[{title:cnTitle}]}=metaData;
console.log(esTitle,cnTitle);
//abc,test
}

字符串的拓展

includes(), startsWith(), endsWith()

  • includes():返回布尔值,表示是否找到了参数字符串。
  • startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
  • endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。
1
2
3
4
5
let s = 'Hello world!';

s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false

repeat()

repeat方法返回一个新字符串,表示将原字符串重复n次。

1
2
3
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""

模板字符串

模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。

1
2
3
4
5
6
{
let name="list";
let info="hello world";
let m=`i am ${name},${info}`;
console.log(m); //i am hello, world
}

  • 使用模板字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。

padStart(),padEnd()

ES2017引入了字符串补全长度的功能。

  • padStart()用于头部补全
  • padEnd()用于尾部补全。
1
2
3
4
5
{
//日期补全,个位数补全等等
console.log('1'.padStart(2,'0'));
console.log('1'.padEnd(2,'0'));
}

数值拓展

Number.isInteger()

Number.isInteger()用来判断一个数值是否为整数。

1
2
3
Number.isInteger(25) // true
Number.isInteger(25.0) // true
Number.isInteger(25.1) // false

  • 如果参数不是数值,Number.isInteger返回false

数组的拓展

扩展运算符

扩展运算符可以展开数组

1
2
3
4
5
6
7
8
9
//替代函数的apply方法
// ES5 的写法
Math.max.apply(null, [14, 3, 77])

// ES6 的写法
Math.max(...[14, 3, 77])

// 等同于
Math.max(14, 3, 77);

适用场景

  • 复制数组
1
2
3
4
5
6
7
8
9
10
11
12
13
//es5写法
const a1 = [1, 2];
const a2 = a1.concat();

a2[0] = 2;
a1 // [1, 2]

//es6写法
const a1 = [1, 2];
// 写法一
const a2 = [...a1];
// 写法二
const [...a2] = a1;
  • 合并数组
    注意:这两种方法都是浅拷贝
1
2
3
4
5
6
7
8
9
10
11
const arr1 = ['a', 'b'];
const arr2 = ['c'];
const arr3 = ['d', 'e'];

// ES5 的合并数组
arr1.concat(arr2, arr3);
// [ 'a', 'b', 'c', 'd', 'e' ]

// ES6 的合并数组
[...arr1, ...arr2, ...arr3]
// [ 'a', 'b', 'c', 'd', 'e' ]
  • 与解构赋值结合
    与解构赋值结合起来,用于生成数组。
1
2
3
4
// ES5
a = list[0], rest = list.slice(1)
// ES6
[a, ...rest] = list
  • 字符串
    将字符串转为真正的数组。
1
2
[...'hello']
// [ "h", "e", "l", "l", "o" ]

Array.of

Array.of方法用于将一组值,转换为数组。

1
2
3
4
5
6
7
{
let arr = Array.of(3,4,5,6,7);
console.log('arr=',arr); //arr=[3,4,5,6,7]

let empty=Array.of();
console.log('empty',empty); //empty=[]
}

Array.from

Array.from方法用于将两类对象转为真正的数组:类似数组的对象(array-like object)和可遍历(iterable)的对象(包括 ES6 新增的数据结构 Set 和 Map)。

1
2
3
4
5
6
7
8
9
10
{
let p=document.querySelectorAll('p');
let pArr=Array.from(p);
pArr.forEach(function(item){
console.log(item.textContent);
});

//Array.from还可以接受第二个参数,作用类似于数组的map方法,用来对每个元素进行处理,将处理后的值放入返回的数组。
console.log(Array.from([1,3,5],function(item){return item*2})); //[2,6,10]
}

entries(),keys() 和 values()

  • keys()是对键名的遍历
  • values()是对键值的遍历
  • entries()是对键值对的遍历。
1
2
3
4
5
6
7
8
9
10
11
{
for(let index of ['1','a','bc'].keys()){
console.log('keys',index); //0 1 2
}
for(let value of ['1','a','bc'].values()){
console.log('values',value); //1 a ac
}
for(let [index,value] of ['1','a','bc'].entries()){
console.log('entries',index,value); //0 1, 1 a, 2 bc
}
}

find() findIndex() 和includes()

  • find()找出第一个符合条件的数组成员
  • findIndex()返回第一个符合条件的数组成员的位置
  • includes()返回一个布尔值,表示某个数组是否包含给定的值
1
2
3
4
5
6
7
8
9
{
console.log([1,2,3,4,5,6].find(function(item){return item>3}));
//4
console.log([1,2,3,4,5,6].findIndex(function(item){return item>3}));
//3

console.log('number',[1,2,NaN].includes(1)); //true
console.log('number',[1,2,NaN].includes(NaN)); //true
}

函数的拓展

默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
{
//es5写法
function log(x, y) {
y = y || 'World';
console.log(x, y);
}

//es6写法
function test(x, y = 'world'){
console.log('默认值',x,y);
}
test('hello'); //默认值 hello world
test('hello','kill'); //默认值 hello kill
}

//作用域
//es6写法
{
let x='test';
function test2(x,y=x){
console.log('作用域',x,y);
}
test2('kill');
}
//等价于
//es5写法
{
var x='test';
function test2(x,y){
y = x;
console.log('作用域',x,y);
}
test2('kill');
}

rest参数

rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
function test3(...arg){
for(let v of arg){
console.log('rest',v);
}
}
test3(1,2,3,4,'a');
//rest 1
//rest 2
//rest 3
//rest 4
//rest a
}

{
console.log(...[1,2,4]); //1 2 4
console.log('a',...[1,2,4]); //a 1 2 4
}

rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

箭头函数

箭头函数有几个使用注意点。

  • 函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
  • 不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。
  • 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var f = v => v;
// 等同于
var f = function (v) {
return v;
};


//不需要参数时,可以用圆括号代替参数部分
var f = () => 5;
// 等同于
var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};


{
let arrow = v => v*2;
let arrow2 = () => 5;
console.log('arrow',arrow(3 //arrow 6
console.log(arrow2()); //5

}

简化回调函数

1
2
3
4
5
6
7
// 正常函数写法
[1,2,3].map(function (x) {
return x * x;
});

// 箭头函数写法
[1,2,3].map(x => x * x);

改变this指向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// ES6
function foo() {
setTimeout(() => {
console.log('id:', this.id);
}, 100);
}

// ES5
function foo() {
var _this = this;

setTimeout(function () {
console.log('id:', _this.id);
}, 100);
}

尾调用

某个函数的最后一步是调用另一个函数,就是尾调用

1
2
3
function f(x){
return g(x);
}

尾调用的好处:尾调用优化

  • 尾调用优化,就是使用尾递归,对于尾递归来说,由于只存在一个调用帧,所以永远不会发生“栈溢出”错误。
  • ES6规定,所有 ECMAScript 的实现,都必须部署“尾调用优化”。
1
2
3
4
5
6
7
8
9
{
function tail(x){
console.log('tail',x);
}
function fx(x){
return tail(x)
}
fx(123)
}

对象的拓展

简洁表示法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
{
// 简洁表示法
let o=1;
let k=2;
let es5={
o:o,
k:k
};
let es6={
o,
k
};
console.log(es5,es6);

let es5_method={
hello:function(){
console.log('hello');
}
};
let es6_method={
hello(){
console.log('hello');
}
};
console.log(es5_method.hello(),es6_method.hello());
}

属性表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
// 属性表达式
let a='x';
let es5_obj={
a:'c',
b:'c'
};

let es6_obj={
[a]:'c'
}
console.log(es5_obj,es6_obj);
//{a: "c", b: "c"} {x: "c"}

}

注意,属性名表达式与简洁表示法,不能同时使用,会报错。

1
2
3
4
5
6
7
8
// 报错
const foo = 'bar';
const bar = 'abc';
const baz = { [foo] };

// 正确
const foo = 'bar';
const baz = { [foo]: 'abc'};

Object.is(),Object.assign()

  • Object.is()用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。
  • Object.assign()可以实现对象的浅拷贝
1
2
3
4
5
6
7
8
9
10
11
12
{
// 新增API
console.log('字符串',Object.is('abc','abc'),'abc'==='abc'); //true true
console.log('数组',Object.is([],[]),[]===[]); //数组 false false

console.log('拷贝',Object.assign({a:'a'},{b:'b'})); //拷贝 {a: "a", b: "b"}

let test={k:123,o:456};
for(let [key,value] of Object.entries(test)){
console.log([key,value]); //["k", 123] ["o", 456]
}
}
1
2
3
4
5
6
7
8
{
// 扩展运算符
let {a,b,...c}={a:'test',b:'kill',c:'ddd',d:'ccc'};
c={
c:'ddd',
d:'ccc'
}
}

参考

阮一峰 ECMAScript 6 入门


感谢打赏,错误之处欢迎指正交流(`・ω・´) !~~



文章目录
  1. 1. 前言
  2. 2. let
  3. 3. const
  4. 4. 解构赋值
    1. 4.1. 数组解构赋值
    2. 4.2. 对象解构赋值
  5. 5. 字符串的拓展
    1. 5.1. includes(), startsWith(), endsWith()
    2. 5.2. repeat()
    3. 5.3. 模板字符串
    4. 5.4. padStart(),padEnd()
  6. 6. 数值拓展
    1. 6.1. Number.isInteger()
  7. 7. 数组的拓展
    1. 7.1. 扩展运算符
    2. 7.2. Array.of
    3. 7.3. Array.from
    4. 7.4. entries(),keys() 和 values()
    5. 7.5. find() findIndex() 和includes()
  8. 8. 函数的拓展
    1. 8.1. 默认值
    2. 8.2. rest参数
    3. 8.3. 箭头函数
    4. 8.4. 尾调用
  9. 9. 对象的拓展
    1. 9.1. 简洁表示法
    2. 9.2. 属性表达式
    3. 9.3. Object.is(),Object.assign()
  10. 10. 参考
|