Js ES6 特性

🍹 ES6新增块级作用域、箭头函数、模板字面量、解构赋值、类和模块等特性,简化代码编写、提高代码可读性和可维护性。

1 拷贝

  • 拷贝
    • 深拷贝与浅拷贝的概念只存在于引用数据类型。
    • 浅拷贝:B复制了A,当修改A时,B也跟着变了。
    • 深拷贝:B复制了A,当修改A时,B没有随着变。

1-1 浅拷贝

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>浅拷贝</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
var obj1 = {
name: "张三",
age: 20,
speak: function () {
console.log("我是" + this.name);
}
};

var obj2 = obj1;
// 修改obj2的属性和方法时,obj1相应的属性和方法也会改变
obj2.name = "李四";
console.log(obj1);
console.log(obj2);
</script>
</body>

</html>

1-2 深拷贝

  • 深拷贝
    • Array:slice()、concat()、Array.from()、操作符(只实现一维数组的深拷贝)。
    • Object
      • Object.assign()、操作符(只能实现一维对象的深拷贝)。
      • JSON.parse(JSON.stringify(obj)):实现多维对象深拷贝。
      • 但是容易忽略undefined,任意函数,以及Symbol值。

(1) 数组

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>数组</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
// slice()方法
var arr1 = [1, 2, 3, 4];
var arr2 = arr1.slice();
arr2[0] = 3;
console.log(arr1);
console.log(arr2);

// concat()方法
var arr3 = [1, 2, 3, 4];
var arr4 = arr1.concat();
arr4[0] = 5;
console.log(arr3);
console.log(arr4);

// Array.from()方法
var arr5 = [1, 2, 3, 4];
var arr6 = Array.from(arr1);
arr6[0] = 7;
console.log(arr5);
console.log(arr6);

// …操作符
var arr7 = [1, 2, 3, 4];
var arr8 = [...arr1];
arr8[0] = 9;
console.log(arr7);
console.log(arr8);
</script>
</body>

</html>

(2) 对象

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>对象</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
// Object.assign()方法:一维对象的深拷贝
var obj1 = {
name: "张三",
age: 20,
speak: function () {
console.log("我是" + this.name);
}
};
var obj2 = Object.assign({}, obj1);
// 修改obj2的属性和方法时,obj1相应的属性和方法不会改变
obj2.name = "李四";
console.log(obj1);
console.log(obj2);

// …操作符
var obj3 = {
name: "张三",
age: 20,
speak: function () {
console.log("我是" + this.name);
}
};
var obj4 = {
...obj3
};
// 当修改obj2的属性和方法时,obj1相应的属性和方法不会改变
obj4.name = "李四";
console.log(obj3);
console.log(obj4);

// JSON.parse(JSON.stringify(obj)):多维对象的深拷贝
// JSON.stringify()序列化过程中,undefined、任意函数以及symbol值会被忽略
//
var obj5 = {
name: "张三",
age: 20,
birthday: {
year: 1997,
month: 12,
day: 5
},
speak: function () {
console.log("我是" + this.name);
}
};
var obj6 = JSON.parse(JSON.stringify(obj5));
// 修改obj2的属性和方法时,obj1相应的属性和方法不会改变
obj6.name = "李四";
console.log(obj5);
console.log(obj6);
</script>
</body>

</html>

(3) 通用

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>通用</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
var obj1 = {
name: "张三",
age: 20,
birthday: {
year: 1997,
month: 12,
day: 5,
},
speak: function () {
console.log("我是" + this.name);
},
};

var obj2 = deepClone(obj1);

// 当修改obj2的属性和方法的时候,obj1相应的属性和方法不会改变
obj2.name = "李四";
console.log(obj1);
console.log(obj2);

/**
* 深拷贝通用方法
* @param obj 需要拷贝的对象
* @param has
* @returns {any|RegExp|Date}
*/
function deepClone(obj, has = new WeakMap()) {
// 类型检查
if (obj == null) return obj;
if (obj instanceof Date) return obj;
if (obj instanceof RegExp) return obj;
if (!(typeof obj == "object")) return obj;

// 构造对象
const newObj = new obj.constructor();

// 防止自引用导致的死循环
if (has.get(obj)) return has.get(obj);
has.set(obj, newObj);

// 循环遍历属性及方法
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = deepClone(obj[key]);
}
}

// 返回对象
return newObj;
}
</script>
</body>

</html>

2 生成器

  • 生成器
    • 生成器函数是ES6提供的一种异步编程解决方案,语法行为与传统函数完全不同。
    • 返回的结果是迭代器对象,调用迭代器对象的next方法可以得到yield语句后的值。
    • yield类似函数的暂停标记,也可认为是函数的分隔符,每调用一次next执行一段代码。
    • next方法可以传递实参,作为yield语句的返回值,*的位置则没有限制。

2-1 函数使用

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>函数使用</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
function* gen() {
// 代码1开始执行
console.log("代码1执行了");
yield "代码1...";
// 代码2开始执行
console.log("代码2执行了");
yield "代码2...";
// 代码3开始执行
console.log("代码3执行了");
return "真奇怪...";
}

let iterator = gen();
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log("***************");

// 遍历
for (let v of gen()) {
console.log(v);
}
</script>
</body>

</html>

2-2 函数参数

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>函数参数</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
function* gen(arg) {
console.log(arg);
let one = yield 111;
console.log(one);
let two = yield 222;
console.log(two);
let three = yield 333;
console.log(three);
}

// 执行获取迭代器对象
let iterator = gen("AAA");
console.log(iterator.next());

// next方法可以传入实参
console.log(iterator.next("BBB"));
console.log(iterator.next("CCC"));
console.log(iterator.next("DDD"));
</script>
</body>

</html>

2-3 函数实例

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
46
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>函数实例</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
// 1s后控制台输出111,2s后输出222,3s后输出333
function one() {
setTimeout(() => {
console.log(111);
iterator.next();
}, 1000)
}

function two() {
setTimeout(() => {
console.log(222);
iterator.next();
}, 2000)
}

function three() {
setTimeout(() => {
console.log(333);
iterator.next();
}, 3000)
}

function* gen() {
yield one();
yield two();
yield three();
}

// 调用生成器函数
let iterator = gen();
iterator.next();
</script>
</body>

</html>

2-4 案例演示

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
46
47
48
49
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>函数演示</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
// 模拟获取用户数据、订单数据、商品数据
function getUsers() {
setTimeout(() => {
let data = "用户数据";
iterator.next(data);
}, 1000);
}

function getOrders() {
setTimeout(() => {
let data = "订单数据";
iterator.next(data);
}, 1000);
}

function getGoods() {
setTimeout(() => {
let data = "商品数据";
iterator.next(data);
}, 1000);
}

function* gen() {
let users = yield getUsers();
console.log(users);
let orders = yield getOrders();
console.log(orders);
let goods = yield getGoods();
console.log(goods);
}

// 调用生成器函数
let iterator = gen();
iterator.next();
</script>
</body>

</html>

3 模块化

  • 模块化
    • 将一个大的程序文件,拆分成许多小文件,然后将其组合起来。
    • 模块功能构成的命令
      • export:用于规定模块的对外接口。
      • import:用于输入其他模块提供的功能。

3-1 模块化的暴露

  • 模块化的暴露
    • 方式:分别暴露、统一暴露、默认暴露。
    • 分别暴露适用于导出多个内容,方便选择性导入。
    • 统一暴露适用于导出一个主要的模块内容,方便简化导入。
    • 默认暴露适合于导出单个主要内容的模块,简化导入操作。

(1) 分别暴露m1.js

1
2
3
4
5
// 方式一:分别暴露
export let school = "厦门大学";
export function study() {
console.log("我们要学习!");
}

(2) 统一暴露m2.js

1
2
3
4
5
6
7
// 方式二:统一暴露
let school = "厦门大学";

function findJob() {
console.log("我们要工作!");
}
export { school, findJob };

(3) 默认暴露m3.js

1
2
3
4
5
6
7
// 方式三:默认暴露
export default {
school: "厦门大学",
change: function () {
console.log("我们要改变!");
}
}

3-2 模块化的导入

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>模块化的导入</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
// 引入m1.js模块内容
import * as m1 from "./js/m1.js";
// 引入m2.js模块内容
import * as m2 from "./js/m2.js";
// 引入m3.js模块内容
import * as m3 from "./js/m3.js";

// 使用VSCode的Live Server插件启动服务查看
m1.study();
m2.findJob();
m3.default.change();
</script>
</body>

</html>

3-3 解构赋值形式

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>解构赋值形式</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
// 引入m1.js模块内容
import { school, study } from "./js/m1.js";
// 引入m2.js模块内容
import { school as s, findJob } from "./js/m2.js";
// 引入m3.js模块内容,默认暴露还可以直接import m3 from "./js/m3.js"
import { default as m3 } from "./js/m3.js";

console.log(school);
study();

console.log(s);
findJob();

console.log(m3);
m3.change();
</script>
</body>

</html>

4 Class类

  • Class类
    • 通过class关键字定义类,ES6的class可看作语法糖。
    • super(调用父级构造方法)。
    • extends(继承父类)、static(定义静态方法和属性)。
    • class(声明类)、constructor(定义构造函数初始化)。
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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Class类</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
// 父类
class Phone {
// 构造方法
constructor(brand, color, price) {
this.brand = brand;
this.color = color;
this.price = price;
}

// 对象方法
call() {
console.log("我可以打电话!");
}
}

// 子类
class SmartPhone extends Phone {
constructor(brand, color, price, screen, pixel) {
super(brand, color, price);
this.screen = screen;
this.pixel = pixel;
}

// 子类方法
photo() {
console.log("我可以拍照片!");
}

playGame() {
console.log("我可以玩游戏!");
}

// 方法重写
call() {
console.log("我可以看视频!");
}

// 静态方法
static run() {
console.log("我可以写程序!");
}

static connect() {
console.log("我可以建连接!");
}
}

// 实例化对象
const Nokia = new Phone("诺基亚", "灰色", 230);
const iPhone6s = new SmartPhone("苹果", "白色", 6088, "4.7inch", "500w");
// 调用子类方法
iPhone6s.playGame();
// 调用重写方法
iPhone6s.call();
// 调用静态方法
SmartPhone.run();
</script>
</body>

</html>

5 Promise

  • Promise
    • ES6引入的异步编程新解决方案,语法上是个构造函数。
    • 可用来封装异步操作,并可以获取其成功或失败的结果。

5-1 基本使用

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>基本使用</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
// 实例化promise对象
const p = new Promise(function (resolve, reject) {
setTimeout(function () {
// 成功调用resolve()处理
let data = "数据读取成功";
resolve(data);

// 失败调用reject()处理
let err = "数据读取失败";
reject(err);

}, 1000);
});

// 调用promise对象的then方法
p.then(function (value) {
console.log(value);
}, function (reason) {
console.error(reason);
});
</script>
</body>

</html>

5-2 案例演示

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>案例演示</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
// 接口地址:https://api.oioweb.cn/api/common/Get60sWorldInsight
const p = new Promise((resolve, reject) => {
// 创建对象
const xhr = new XMLHttpRequest();
// 初始化
xhr.open("GET", "https://api.oioweb.cn/api/common/Get60sWorldInsight");
// 发送
xhr.send();
// 绑定事件, 处理响应结果
xhr.onreadystatechange = function () {
if (xhr.readyState === 4) {
// 判断响应状态码200-299
if (xhr.status >= 200 && xhr.status < 300) {
// 表示成功
resolve(xhr.response);
} else {
// 如果失败
reject(xhr.status);
}
}
}
});

// 指定回调
p.then(function (value) {
console.log(value);
}, function (reason) {
console.error(reason);
});
</script>
</body>

</html>

5-3 Promise-then

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Promise-then</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
// 创建promise对象
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve("用户数据");
}, 1000)
});

// 链式调用+箭头函数
p.then(value => {
console.log(value);
return value;
}).then(value => {
console.log(value);
});
</script>
</body>

</html>

5-4 Promise-catch

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Promise-catch</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
const p = new Promise((resolve, reject) => {
setTimeout(() => {
// 设置p对象的状态为失败, 并设置失败的值
reject("出错啦!");
}, 1000);
});

p.catch(function (reason) {
console.error(reason);
});
</script>
</body>

</html>

6 数据结构

  • 数据结构
    • Set
      • 集合,类似于数组,但成员的值是唯一的,实现了iterator接口。
      • 可以使用扩展运算符和for…of进行遍历,集合的属性和方法如下。
        • size:返回集合的元素个数。
        • add():增加一个新元素,返回当前集合。
        • delete():删除元素,返回boolean值。
        • has():检测集合中是否包含某个元素,返回boolean值。
        • clear():清空集合,返回undefined。
    • Map
      • 类似于对象,也是键值对的集合,键的范围不限于字符串。
      • 实现了iterator接口,可使用扩展运算符和for…of进行遍历。
        • size:返回Map的元素个数。
        • add():增加一个新元素,返回当前Map。
        • get():返回键名对象的键值。
        • has():检测Map中是否包含某个元素,返回boolean值。
        • clear():清空集合,返回undefined。

6-1 Set

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Set</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
// 创建一个空集合
let s1 = new Set();
// 创建一个非空集合
let s2 = new Set([1, 2, 3, 1, 2, 3]);
// 返回集合的元素个数
console.log(s2.size);
// 删除元素
console.log(s2.delete(1));
// 检测是否存在某个值
console.log(s2.has(2));
// 清空集合
console.log(s2.clear());
// 添加新元素
console.log(s2.add(4));
</script>
</body>

</html>

6-2 Map

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
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>Map</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script>
// 创建一个空Map
let m1 = new Map();
// 创建一个非空Map
let m2 = new Map([
["name", "张三"],
["gender", "男"]
]);
// 添加映射值
console.log(m2.set("age", 6));
// 获取映射元素的个数
console.log(m2.size);
// 获取映射值
console.log(m2.get("age"));
// 检测是否有该映射
console.log(m2.has("age"));
// 清除
console.log(m2.clear());
</script>
</body>

</html>

7 数值扩展

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
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>数值扩展</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
// 二进制
let b = 0b11111111
// 八进制
let o = 0o777;
// 十进制
let d = 100;
// 十六进制
let x = 0xff;
console.log(b);
console.log(o);
console.log(d);
console.log(x);
console.log("*****")

// Number.EPSILON:Js最小精度
function equal(a, b) {
if (Math.abs(a - b) < Number.EPSILON) {
return true;
} else {
return false;
}
}
console.log(equal(0.1 + 0.2, 0.3));
console.log(0.1 + 0.2 === 0.3);
console.log("*****")

// Number.isFinite:检测一个数值是否为有限数
console.log(Number.isFinite(100));
console.log(Number.isFinite(100 / 0));
console.log(Number.isFinite(Infinity));
console.log(Number.isFinite(-Infinity));
console.log("*****")

// Number.isNaN:检测一个数值是否为NaN
console.log(Number.isNaN(123));
console.log("*****")

// Number.parseInt:将一个字符串转换为整数
console.log(Number.parseInt("12345abc"));
console.log("*****")

// Number.parseFloat:将一个字符串转换为浮点数
console.log(Number.parseFloat("3.141神奇"));
console.log("*****")

// Number.isInteger:判断一个数是否为整数
console.log(Number.isInteger(5));
console.log(Number.isInteger(2.5));
console.log("*****")

// Math.trunc:将数字的小数部分抹掉
console.log(Math.trunc(32100.5));
console.log("*****")

// Math.sign:判断一个数到底为正数、负数、还是零
console.log(Math.sign(100));
console.log(Math.sign(null));
console.log(Math.sign(-200));
</script>
</body>

</html>

8 对象扩展

  • 对象扩展
    • Object.is:比较两个值是否严格相等,与===行为基本一致。
    • Object.assign:对象的合并,将源对象的所有可枚举属性,复制到目标对象。
    • __proto__、setPrototypeOf、getPrototypeOf,则可以直接设置对象的原型。
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
46
47
<!DOCTYPE html>
<html>

<head>
<meta charset="UTF-8" />
<title>对象扩展</title>
</head>

<body style="text-align: center">
<!-- JavaScript由上到下执行 -->
<script type="module">
// Object.is
console.log(Object.is(120, 120));
console.log(Object.is(NaN, NaN));
console.log(NaN === NaN);

// 设置原型对象
const school = {
name: "厦门大学"
};
const cities = {
xiaoqu: ["思明校区", "漳州校区", "翔安校区", "马来西亚分校"]
};
Object.setPrototypeOf(school, cities);
console.log(Object.getPrototypeOf(school));
console.log(school);

// Object.assign
const config1 = {
host: "localhost",
port: 3306,
name: "张三",
pass: "root",
test1: "test1"
};
const config2 = {
host: "127.0.0.1",
port: 3309,
name: "李四",
pass: "root",
test2: "test2"
}
console.log(Object.assign(config1, config2));
</script>
</body>

</html>

Js ES6 特性
https://stitch-top.github.io/2024/09/26/web/web01-javascript/javascript07-js-es6-te-xing/
作者
Dr.626
发布于
2024年9月26日 22:45:00
许可协议