对es6常用知识点的梳理

解构赋值

对es6解构赋值知识点的梳理。

数组的解构赋值

数组的解构赋值,元素是按次序排列,变量的取值是由它的位置决定;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Before:
let a = 1,
let b = 2,
let c = 3
// Now:
let [a,b,c] = [1,2,3]

let [a,b] = [1]
a // > 1
b // > undefined

let [a,,c] = [1,2,3]
a // > 1
c // > 3

let [,,c] = [1,2,3]
c // > 3

// 用数组的解构赋值来交换两个变量的值
let a = 1;
let b = 2;
[a,b] = [b,a]
a // > 2
b // > 1

对于数组的解构,如果等号右边不是数组,那么进行解构将会报错;

1
2
3
4
5
let [a,b] = 1;
let [a] = true;
let [a] = NaN;
let [a,b] = {};
// > 以上都将报错

默认值

在解构的时候指定默认值,当解构的数组成员严格等于undefined,默认值才会生效;默认值也可以引用解构赋值的其它变量,前提是被引用的变量必须已经声明。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
let [a,b = 2] = [1]
a // > 1
b // > 2

let [a,b = 2] = [1,null]
a // > 1
b // > null 这里的默认值不会生效,因为null不严格等于undefined

let [a = 1,b = a] = [] //引用变量a作为b的默认值
a // > 1
b // > 1

let [a = b, b = 1] = []
// > 报错 ReferenceError: b is not defined; 因为当a引用b作为默认值的时候,b还未被声明

对象的解构赋值

对象的解构与数组有一个重要的不同,对象的属性没有次序,变量必须与属性同名,才能取到正确的值。

1
2
3
4
5
6
7
let obj = {name: "jack",age: 22};
let {name, age} = obj;
name // > 'jack'
age // > 22

let {log} = console;
log('解构赋值') // > '解构赋值'

实际上,对象的解构赋值是下面形式的简写,被赋值的其实是后边的变量:
(对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者)

1
2
3
4
5
6
7
let {name: name,age: age} = {name: "jack",age: 22};
name // > 'jack'

let {name: who,age: howOld} = {name: "jack",age: 22}
who // > 'jack'
howOld // > 22
// 上述代码中,name是匹配的模式,who才是变量,真正被赋值的是变量who,而不是name

默认值

对象的解构赋值,只有当对象的属性值严格等于undifined的时候,默认值才会生效。

1
2
3
4
5
6
7
8
9
10
11
12
let {a = 3} = {}
a // > 3

let {a, b = 2} ={a: 1}
a // > 1
b // > 2

let {a: aaa = 222} = {}
aaa // > 222

let {a: aaa = 222} = {a: 111}
aaa // > 111

字符串的解构赋值

字符串也可以解构赋值。这是因为此时,字符串被转换成了一个类似数组的对象。

1
2
3
4
5
6
const [a,b,c,d,e] = 'hello';
a // > 'h'
b // > 'e'
c // > 'l'
d // > 'l'
e // > 'o'

类数组的对象都有一个length属性,我们可以对这个属性进行解构赋值

1
2
let {length} = 'hello'
length // > 5

函数参数的解构赋值

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
function fn([x,y]){
return x + y
}
fn([1,2]) // > 3

function fn([x = 1,y = 2]){
return x + y
}
fn([]) // > 3

[[1,2],[3,4]].map(([x,y])=>x + y) // >[3,7]

function fn({x = 1,y = 2}){
return x + y
}
fn({}) // > 3

function fn(){
return [1,2,3]
}
let [a,b,c] = fn()
a // > 1
b // > 2
c // > 3

function fn(){
return {a: 1,b: 2,c: 3}
}
let {a,b,c} = fn()
a // > 1
b // > 2
c // > 3

es6对几种数据类型的扩展

数值的扩展

  • Number.isFinite()

    用来检查一个数值是否为有限的,即不是Infinity。如果参数类型不是数值,Number.isFinite一律返回false。

    1
    2
    3
    4
    5
    6
    7
    8
    Number.isFinite(15); // > true
    Number.isFinite(0.8); // > true
    Number.isFinite(NaN); // > false
    Number.isFinite(Infinity); // > false
    Number.isFinite(-Infinity); // > false
    Number.isFinite('foo'); // > false
    Number.isFinite('15'); // > false
    Number.isFinite(true); // > false
  • Number.isNaN()

    用来检查一个值是否为NaN。如果参数类型不是NaN,Number.isNaN一律返回false。

    1
    2
    3
    4
    5
    6
    7
    Number.isNaN(NaN) // > true
    Number.isNaN(15) // > false
    Number.isNaN('15') // > false
    Number.isNaN(true) // > false
    Number.isNaN(9/NaN) // > true
    Number.isNaN('true' / 0) // > true
    Number.isNaN('true' / 'true') // > true
  • Number.parseInt(),Number.parseFloat()

    es6将全局方法parseInt()和parseFloat()移植到Number对象上,行为保持不变。

    1
    2
    Number.parseInt('12.34') // > 12
    Number.parseFloat('123.45#') // > 123.45
  • Number.isInteger()

    用来判断一个数值是否为整数。如果参数不是数值,Number.isInteger返回false。

    1
    2
    3
    4
    5
    6
    7
    8
    Number.isInteger(10) // > true
    Number.isInteger(0) // > true
    Number.isInteger(10.0) // > true
    Number.isInteger(10.1) // > false
    Number.isInteger() // > false
    Number.isInteger(null) // > false
    Number.isInteger('10') // > false
    Number.isInteger(true) // > false

值得注意的是,由于js的精度问题,在下面这种情况下,Number.isInteger()可能会误判。

1
Number.isInteger(3.0000000000000002) // > true

类似情况还有,当一个数值的绝对值小于Number.MIN_VALUE(5E-324)^1,这时,Number.isInteger也会误判。

1
2
Number.isInteger(5E-324) // false
Number.isInteger(5E-325) // true

Math对象的扩展

  • Math.trunc()

    用于去除一个数的小数部分,返回整数部分。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Math.trunc(4.1) // 4
    Math.trunc(4.9) // 4
    Math.trunc(-4.1) // -4
    Math.trunc(-4.9) // -4
    Math.trunc(-0.1234) // -0

    // 实现方式(对于没有部署这个方法的环境,可以模拟这个方法)
    Math.trunc = Math.trunc || function (x){
    return x < 0 ? Math.ceil(x) : Math.floor(x);
    }
  • Math.sign()

    用来判断一个数到底是正数、负数、还是零。对于非数值,会先将其转换为数值。如果参数是非数值,会自动转为数值。对于那些无法转为数值的值,会返回NaN。

    它的返回值:

    参数为正数,返回+1;
    参数为正数,返回+1;
    参数为 0,返回0;
    参数为-0,返回-0;
    其他值,返回NaN。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    Math.sign(-5) // -1
    Math.sign(5) // +1
    Math.sign(0) // +0
    Math.sign(-0) // -0
    Math.sign(NaN) // NaN

    Math.sign('') // 0
    Math.sign(true) // +1
    Math.sign(false) // 0
    Math.sign(null) // 0
    Math.sign('9') // +1
    Math.sign('foo') // NaN
    Math.sign() // NaN
    Math.sign(undefined) // NaN

字符串的新增方法

  • includes(),startsWith(),endsWith()

    includes():返回布尔值,表示是否找到了参数字符串。
    startsWith():返回布尔值,表示参数字符串是否在原字符串的头部。
    endsWith():返回布尔值,表示参数字符串是否在原字符串的尾部。

    1
    2
    3
    4
    let s = 'Hello world!';
    s.startsWith('Hello') // true
    s.endsWith('!') // true
    s.includes('o') // true

这三个方法都支持第二个参数,表示开始搜索的位置。

1
2
3
4
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
  • repeat()

    返回一个新字符串,表示将原字符串重复n次。参数如果是小数,会被取整。

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

    字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
    padStart()和padEnd()一共接受两个参数,第一个参数是字符串补全生效的最大长度,第二个参数是用来补全的字符串。

    1
    2
    3
    4
    5
    'x'.padStart(5, 'ab') // 'ababx'
    'x'.padStart(4, 'ab') // 'abax'

    'x'.padEnd(5, 'ab') // 'xabab'
    'x'.padEnd(4, 'ab') // 'xaba'
  • trimStart(),trimEnd()

    行为与trim()一致,trimStart()消除字符串头部的空格,trimEnd()消除尾部的空格。它们返回的都是新字符串,不会修改原始字符串。

    1
    2
    3
    4
    let s = '  abc  ';
    s.trim() // "abc"
    s.trimStart() // "abc "
    s.trimEnd() // " abc"

浏览器还部署了额外的两个方法,trimLeft()是trimStart()的别名,trimRight()是trimEnd()的别名。


数组的扩展

  • 扩展运算符

    将一个数组转为用逗号分隔的参数序列。

    1
    2
    let arr = [1,2,3,4]
    console.log(...arr) // > 1,2,3,4

复制数组

1
2
3
4
5
6
7
8
// es5
const arr = [1,2,3]
const arr2 = arr.concant()
arr2 // > [1,2,3]
// es6扩展运算符
const arr = [1,2,3]
const arr2 = [...arr]
arr2 // > [1,2,3]

合并数组

1
2
3
4
5
6
7
8
9
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
let arr = [...'我爱你中国']
arr // > ['我','爱','你','中','国']

Module语法

es6模块的设计思想是尽量的静态化,使得编译时就能确定模块的依赖关系,以及输入和输出的变量。CommonJS 和 AMD 模块,都只能在运行时确定这些东西。

import和export的几种用法

以下几种写法,导出模块的文件统一命名成output.js;导入文件命名成entry.js。
写法1:

1
2
3
4
5
6
// output.js
export const name = 'clearLove';
// entry.js
import {name} from './output';
// 或者写成
import {name as newName} from './output'; //as关键字,将输入的变量重命名

写法2:

1
2
3
4
5
6
7
8
9
10
// output.js
const name = 'clearLove';
const fn = function(x,y){
return x + y
}
export {name,fn}
// entry.js
import {name,fn} from './output';
// 或者写成
import {name as newName,fn as newFn} from './output'; //as关键字,将输入的变量重命名

写法3:

1
2
3
4
5
6
7
// output.js
const name = 'clearLove';
export {
name as newName, //as关键字,将输出的变量重命名
}
// entry.js
import {newName} from './output';

写法4:

1
2
3
4
5
6
7
8
9
// output.js
export const name = 'clearLove';
export const fn = function(x,y){
return x + y ;
}
// entry.js
import * as output from './output';
console.log(output.name)
output.fn()

从以上几种方法可以看出,使用import命令的时候,用户需要知道所要加载的变量名或函数名,否则无法加载;为了给用户提供方便,让他们不用一一查看模块里的变量名或函数名就能加载模块,就要用到export default命令,为模块指定默认输出。以下方法为示例:

1
2
3
4
5
6
7
8
9
10
11
12
// output.js
export default function(x,y){
return x + y ;
}
// 或者写成
function fn(x,y){
return x + y ;
}
export default fn;
// entry.js
import fnfnfn from './output';
fnfnfn();

export与import 的复合写法

1
2
3
4
5
6
// entry.js
export { name, fn } from './output';

// 可以简单理解为
import { name, fn } from './output';
export { name, fn };

模块的接口改名和整体输出

1
2
3
4
5
6
// entry.js
// 接口改名
export { fn as fnfnfn } from './output';

// 整体输出
export * from './output';

具名接口改为默认接口

1
2
3
4
5
6
// entry.js
export { name as default } from './output';

// 等同于
import { name } from './output';
export default name;

还有一种写法:

1
2
3
4
5
6
// entry.js
export * as all from "./output";

// 等同于
import * as all from "./output";
export {all};
0%