学习ES6新特性

1. ES6

1.1.1 let变量声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 1.不允许重复声明
// let a = 1;
// let a = 2;

// 2.块级作用域 ES5三种作用域:全局 函数 eval
// if else for while
// {
// let a = 5;
// }
// console.log(a);

// 3.不存在变量提升(即不允许使用未声明的变量)
// console.log(a);
// let a = 7;

// 4.不影响作用域链(即块级作用域里的函数等还可以使用变量)
// {
// let a = 7;
// function fn() {
// console.log(a);
// }
// fn();
// }

1.1.2 let经典案例(和var对比)

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
// 获取元素对象
let items = document.querySelectorAll('.item');

// 给每个item绑定点击事件,点击时切换背景颜色

// 以前用var写必须要用this

// for (var i = 0; i < items.length; i++) {
// items[i].onclick = function () {
// this.style.backgroundColor = 'pink';
// }
// }

// 如果写成items[i]会出问题,以上代码等价如下
// var不存在块级作用域,块与块之间相互污染,所有的i都为window.i为3
// {
// var i=0;
// items[i].onclick = function () {
// this.style.backgroundColor = 'pink';
// }
// };

// {
// var i=1;
// items[i].onclick = function () {
// this.style.backgroundColor = 'pink';
// }
// };

// {
// var i=2;
// items[i].onclick = function () {
// this.style.backgroundColor = 'pink';
// }
// };

//用let声明i像以下这样写是可行的
for (let i = 0; i < items.length; i++) {
items[i].onclick = function () {
items[i].style.backgroundColor = 'pink';
}
}

//等价于
//块与块之间不相互干扰
// {
// let i=0;
// items[i].onclick = function () {
// this.style.backgroundColor = 'pink';
// }
// };

// {
// let i=1;
// items[i].onclick = function () {
// this.style.backgroundColor = 'pink';
// }
// };

// {
// let i=2;
// items[i].onclick = function () {
// this.style.backgroundColor = 'pink';
// }
// };

1.2 const常量声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//声明常量
const PI = 3.14;

//1.常量必须在声明时赋值
// const A;

//2.常量通常用大写表示,但用小写也不会报错
// const school='UESTC';

//3.常量的值不能修改
// PI=6;

// 4.对对象和数组元素的改变不算做对常量的改变,因为该常量存储的是地址
const ARR = ['1', '2', '3']
ARR.push('4');

1.3 变量的解构赋值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 数组解构赋值
let arr = ['monica', 'andrew', 'rosa'];

// 按顺序赋值,注意要是方括号[]
let [first, second, third] = arr;
console.log(first, second, third);

// 对象解构赋值
const monica = {
name: 'monica',
age: '19',
english: function () {
console.log('speak English');
}
}
// 要与对象中属性同名,一般解构方法,注意要写大括号{}
let {english} = monica;
english();

1.4 模板字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 1.声明字符串,使用反引号``  ES5声明字符串 单引号'' 双引号""
let str = `我也是字符串`;
console.log(str, typeof str);

// 2.可以在内容中出现换行符
let string = `<ul>
<li>哈哈</li>
<li>嘻嘻</li>
<li>嘿嘿</li>
</ul>`;

//3.变量拼接
let favorite = 'monica';
let output = `${favorite} is my favorite`;
console.log(output);

1.5 对象的简化写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<script>
let name = 'monica';
let change = function () {
console.log("改变了~");
}

const girl = {
//完整写法
// name: name,
// change: change,

//简化写法,属性和变量同名可以直接如下简写
name,
change,
//声明函数的简写
improve() {
console.log('提升了')
}
}
</script>

1.6.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
43
44
45
<script>
//声明
let fn = (a, b) => {
return a + b;
}
console.log(fn(3, 9));

//1.this是静态的,始终指向函数声明时所在作用域this的值
let getName = function () {
console.log(this.name);
};

let getName2 = () => {
console.log(this.name);
};
//实质上等同于
//let fn=function(a,b){
let _this=this;
console.log(_this.name);
};

window.name = 'monica';
const girl = {
name: '莫妮卡'
}

getName();
getName2();
getName.call(girl);
getName2.call(girl);

//2.不能作为构造函数实例化对象

//3.不能使用arguments对象

//4.箭头函数的简写
//(1)省略小括号,只有一个形参时
let add = n => {
return n + n;
}
console.log(add(9));
//(2)省略花括号,函数体只有一行语句时,且要省略return,语句的执行结果就是返回值
let pow = n => n * n;
console.log(pow(8));
</script>

1.6.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
<script>
//需求1:点击div 2s 后变成粉色
let box = document.querySelector('.box');
box.addEventListener('click', function () {
setTimeout(() => {
//写成匿名函数的this指向不对(指向window)
// console.log(this);
this.style.backgroundColor = 'pink';
}, 2000)
})

//需求2:获取数组中偶数元素
const arr = [1, 3, 4, 6, 10, 25, 36]
// const result = arr.filter(function (num) {
// if (num % 2 === 0) {
// return true;
// } else {
// return false;
// }
// })
const result = arr.filter(num => num % 2 === 0)
console.log(result);

//总结:箭头函数适合应用于与this无关的场景,如定时器,数组的方法回调
//箭头函数不适合应用于与this有关的场景:如事件回调,对象的方法
</script>

1.7 函数参数的默认值设置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<script>
//1.形参初始值,具有默认值的参数,一般位置靠后
//如果没有传参则使用默认值
let add = function (a, b, c = 10) {
return a + b + c;
}
// console.log(add(1,2,3));
console.log(add(1, 2));

//2.与解构赋值结合
function connect({ hostName = '127.0.0.1', userName, password, port }) {
console.log(hostName);
console.log(userName);
console.log(password);
console.log(port);
}
connect({
// hostName: 'localhost',
userName: 'root',
password: '123',
port: '80'
})
</script>

1.8 rest参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
// ES5获取实参方式,不是数组
// function date(){
// console.log(arguments);
// }
// date('monica','andrew','rosa')

// rest参数,得到数组,操作更灵活
// function date(...args){
// console.log(args);
// }
// date('monica','andrew','rosa')

// rest 参数放到最后
function fn(a, b, ...args) {
console.log(a);
console.log(b);
console.log(args);
}
// 1 , 2 之后的全赋值给 args
fn(1, 2, 3, 4, 5, 6);
</script>

1.9.1 扩展运算符介绍

将数组转换为逗号分隔的参数序列

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script>
let students=['monica','andrew','rosa'];
//只有一个参数
// function study(){
// console.log(arguments);
// }
// study(students);

//使用扩展运算符,有3个参数
function study(){
console.log(arguments);
}
study(...students);

</script>

1.9.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
<body>
<div></div>
<div></div>
<div></div>

<script>
//1.数组的合并
const boys = ['andrew', 'tom'];
const girls = ['monica', 'rosa'];
// const students=boys.concat(girls);
const students = [...boys, ...girls]
console.log(students);

//2.数组的克隆
const a = [1, 2, 3];
const b = [...a];
console.log(b);

//3.将伪数组转为真正的数组
const divs = document.querySelectorAll('div');
const divArr=[...divs]
console.log(divs);
console.log(divArr);
</script>
</body>

1.10.1 Symbol的介绍与创建

文字表述:Symbol - ECMAScript 6入门 (ruanyifeng.com)

symbol的值是唯一的,用来解决命名冲突

不能参与运算,不能枚举,不能遍历,但可以使用Reflect.ownKeys来获取对象的所有键名。或者使用Object.getOwnPropertySymbols()方法,可以获取指定对象的所有 Symbol 属性名,该方法返回一个数组,成员是当前对象的所有用作属性名的 Symbol 值。

1
2
3
4
5
6
7
8
9
10
11
12
13
<script>
let s = Symbol();
console.log(s, typeof s);
//Symbol()可以接受一个字符串作为参数,表示对 Symbol 实例的描述。这主要是为了在控制台显示,或者转为字符串时,比较容易区分
let s2 = Symbol('monica');
let s3 = Symbol('monica');
console.log(s2===s3);

//Symbol.for()创建的值可重复使用
let s4=Symbol.for('monica');
let s5=Symbol.for('monica');
console.log(s4===s5);
</script>

JavaScript的7中数据类型:USONB

U undefined

S string symbol

O object

N null number

B boolean

1.10.2 对象添加Symbol类型属性

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
<script>
let game = {
up: '5',
down: '6',
play: function () {
console.log("play")
}
}
//如何在不看game内部结构的情况下安全地向game中添加两个方法 up down
let methods = {
up: Symbol(),
down: Symbol()
}

//用[]可以访问动态属性,即内部可以是表达式或变量
game[methods.up] = function () {
console.log("up");
};
game[methods.down] = function () {
console.log("down");
}
console.log(game);

let game2={
[Symbol('up')]:function(){
console.log("up");
},
[Symbol('down')]:function(){
console.log("down");
}
}

console.log(game2);

</script>

1.10.3 Symbol的内置属性

迭代 symbols

Symbol.iterator

一个返回一个对象默认迭代器的方法。被 for...of 使用。

Symbol.asyncIterator 实验性

一个返回对象默认的异步迭代器的方法。被 for await of 使用。

正则表达式 symbols

Symbol.match

一个用于对字符串进行匹配的方法,也用于确定一个对象是否可以作为正则表达式使用。被 String.prototype.match() 使用。

Symbol.replace

一个替换匹配字符串的子串的方法。被 String.prototype.replace() 使用。

Symbol.search

一个返回一个字符串中与正则表达式相匹配的索引的方法。被 String.prototype.search() 使用。

Symbol.split

一个在匹配正则表达式的索引处拆分一个字符串的方法.。被 String.prototype.split() 使用。

其他 symbols

Symbol.hasInstance

一个确定一个构造器对象识别的对象是否为它的实例的方法。被 instanceof 使用。当其他对象使用instanceof运算符,判断是否为该对象的实例时,会调用这个方法。比如,foo instanceof Foo在语言内部,实际调用的是Foo[Symbol.hasInstance](foo)

Symbol.isConcatSpreadable

一个布尔值,表明一个对象是否应该 flattened 为它的数组元素。被 Array.prototype.concat() 使用。

Symbol.unscopables

拥有和继承属性名的一个对象的值被排除在与环境绑定的相关对象外。

Symbol.species

一个用于创建派生对象的构造器函数。

Symbol.toPrimitive

一个将对象转化为基本数据类型的方法。

Symbol.toStringTag

用于对象的默认描述的字符串值。被 Object.prototype.toString() 使用。

1.11.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
<script>
let arr = ['monica', 'andrew', 'rosa', 'tom'];

// 使用for...in遍历数组,输出的是键名
for (let i in arr) {
console.log(i);
}
// 使用for...of遍历数组,输出的是键值,
// 对象进行for...of循环时,会调用Symbol.iterator方法,返回该对象的默认遍历器
for (let i of arr) {
console.log(i);
}
console.log(arr);
// 对象的Symbol.iterator属性指向对象的默认遍历器方法
// 执行这个属性,会返回一个遍历器对象。该对象的根本特征就是具有next方法。
// 每次调用next方法,都会返回一个代表当前成员的信息对象,具有value和done两个属性
let iterator = arr[Symbol.iterator]();
// 调用遍历器的next方法
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
</script>

1.11.2 迭代器应用_自定义遍历数据

对于原生部署 Iterator 接口的数据结构,不用自己写遍历器生成函数,for...of循环会自动遍历它们。除此之外,其他数据结构(主要是对象)的 Iterator 接口,都需要自己在Symbol.iterator属性上面部署,这样才会被for...of循环遍历。

对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,需要开发者手动指定。本质上,遍历器是一种线性处理,对于任何非线性的数据结构,部署遍历器接口,就等于部署一种线性转换。不过,严格地说,对象部署遍历器接口并不是很必要,因为这时对象实际上被当作 Map 结构使用,ES5 没有 Map 结构,而 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
25
26
27
28
29
30
31
32
<script>
const school = {
name: 'UEXTC',
students: [
'monica',
'andrew',
'rosa',
'tom'
],
[Symbol.iterator]() {
//声明索引变量
let index = 0;
// return一个指针对象,指针对象里有一个next方法
// next方法返回value和done属性值
return {
next: () => {
if (index < this.students.length) {
let result= { value: this.students[index], done: false };
index++;
return result;
} else {
return { value: 'undefined', done: true }
}
}
}
}
}
// 自定义遍历对象school
for (index of school) {
console.log(index);
}
</script>

1.12.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
<script>
//生成器是一个特殊的函数
//特殊的声明方式
function* generate() {
// yield——函数代码的分隔符
// console.log('1');
yield '一只没有耳朵';

// console.log('2');
yield '一只没有尾巴';

// console.log('3');
yield '真奇怪';

}
let iterator = generate();
console.log(generate());

// 特殊的执行方式
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());
console.log(iterator.next());

// 遍历
for(let i of generate()){
console.log(i);
}
</script>

1.12.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
<script>
//声明生成器函数
function* gen(args) {
console.log(args);
// yield暂停执行,next继续执行
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也可以传递参数,并作为上一个yield整体返回的结果
console.log(iterator.next('BBB'));
console.log(iterator.next('CCC'));
console.log(iterator.next('DDD'));

</script>

1.12.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
<script>
//需求:1s后控制台输出111,再过2s后输出222,再过3s后输出333
//回调地狱,很难维护
// setTimeout(() => {
// console.log('111');
// setTimeout(() => {
// console.log('222');
// setTimeout(() => {
// console.log('333');
// }, 3000);
// }, 2000);
// }, 1000);

function one() {
setTimeout(() => {
console.log('111');
iterator.next();
}, 1000);
// 使用setTimeout是必要的,它使主线程到达yield后完全暂停才执行子线程操作
// iterator.next()相当于告诉子线程完成后需干什么
// 当然,JavaScript是单线程异步执行
}
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>

1.12.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
<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>

1.13.1 Promise的基本使用

Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果

Promise对象是一个构造函数,用来生成Promise实例

Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolvereject。它们是两个函数,由 JavaScript 引擎提供,不用自己部署。

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为 resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为 rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

Promise实例生成以后,可以用then方法分别指定resolved状态和rejected状态的回调函数。then方法可以接受两个回调函数作为参数。第一个回调函数是Promise对象的状态变为resolved时调用,第二个回调函数是Promise对象的状态变为rejected时调用。这两个函数都是可选的,不一定要提供。它们都接受Promise对象传出的值作为参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const p=new Promise(function(resolve,reject){
setTimeout(() => {
// let data='数据库中的用户数据';
// // 只要调用就把p状态转为成功(resolved)
// resolve(data);

let err='数据读取失败';
reject(err);
}, 1000);
});
// 当p状态为成功时(resolved),调用第一个函数,否则调用第二个
p.then(function(value){
console.log(value);
},function(reason){
console.error(reason);
})

1.13.2 Promise封装文件读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
  // 1.引入fs模块
const { error } = require('console');
const fs = require('fs');

// 2.使用方法读取文件
// fs.readFile('../resources/test.txt', (err, data) => {
// if (err) throw err;
// console.log(data.toString());
// })

// 3.使用Promise封装
const p=new Promise((resolve, reject) => {
fs.readFile('../resources/test.txt',(err,data)=>{
if(err) reject(err);
resolve(data);
})
})
p.then(function(value){
console.log(value.toString());
},function(reason){
console.error('读取失败');
})

1.13.3 Promise封装ajax请求

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
<script>
const p = new Promise((resolve, reject) => {
// 1.创建对象
const xhr = new XMLHttpRequest();
// 2.初始化
xhr.open('GET', 'https://api.apiopen.top/getJoke');
// 3.发送
xhr.send();
// 4.绑定事件,处理响应结果
xhr.onreadystatechange = function () {
// 判断状态码
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>

1.13.4 Promise.prototype.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
<script>
// 创建promise对象
const p = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('用户数据');
// reject('出错啦!')
}, 1000);
})
// 调用then方法,返回一个promise对象,对象状态由对象的回调函数执行结果决定
let result = p.then(value => {
console.log(value);
// return '成功';
return new Promise((resolve, reject) => {
// resolve('ok');
// reject('error!')
throw '出错啦!'
})
}, reason => {
console.warn(reason);
})
// 1.函数返回 非promise类型属性 对象状态成功,返回的值为对象的成功值

// 2.函数返回 promise对象,resolve时成功,reject时失败

// 3.抛出错误,失败

console.log(result);
</script>

1.13.5 Promise实现多个文件内容读取

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
//要求读取三个文件内容,并将它们拼接在一起输出
// 1.引入fs模块
const fs = require('fs');

// 2.回调实现
// fs.readFile('../resources/file1.txt', (err, data1) => {
// fs.readFile('../resources/file2.txt', (err, data2) => {
// fs.readFile('../resources/file3.txt', (err, data3) => {
// let result = data1 + '\n' + data2 + '\n' + data3
// console.log(result);
// })
// })
// })

// 3.promise实现,链式调用
const p = new Promise((resolve, reject) => {
fs.readFile('../resources/file1.txt', (err, data) => {
resolve(data);
})
})
p.then(value => {
return new Promise((resolve, reject) => {
fs.readFile('../resources/file2.txt', (err, data) => {
resolve([value,data]);
})
})
}).then(value => {
return new Promise((resolve, reject) => {
fs.readFile('../resources/file3.txt', (err, data) => {
value.push(data);
resolve(value);
})
})
}).then(value=>{
console.log(value.join('\n'));
})

1.13.6 Promise对象catch方法

1
2
3
4
5
6
7
8
9
<script>
const p = new Promise((resolve, reject) => {
reject('出错啦!')
})
// 语法糖,更方便程序员使用
p.catch(reason => {
console.warn(reason);
})
</script>

1.14.1 集合介绍及API

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
<script>
// 声明set
let s = new Set();
let s2 = new Set(['monica', 'andrew', 'rosa', 'tom']);

// 元素个数
console.log(s2.size);

// 添加新元素
// s2.add('bob');

// 删除元素
// s2.delete('tom');

// 检测
// console.log(s2.has('jack'));

// 清空
// s2.clear();

// 遍历
for(let i of s2){
console.log(i);
}
console.log(s2);
</script>

1.14.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
<script>
let arr = [1, 2, 3, 5, 3, 2, 4, 6, 4]
// 数组去重
let result = [...new Set(arr)]
console.log(result)

// 交集
let arr1 = [1, 3, 4, 5, 7, 8, 4, 5]
let s = new Set(arr)
let s1 = new Set(arr1)
// let intersection=[...s].filter(item=>{
// if(s1.has(item)){
// return true
// }else{
// return false
// }
// })

// 简化后
let intersection = [...[...s].filter(item => s1.has(item))]
console.log(intersection);

// 并集
let union = [...new Set(arr.concat(arr1))];
console.log(union);

// 差集(与交集的判断逻辑相反,过滤出不在s1中的元素)
let diff = [...[...s].filter(item => !s1.has(item))]
console.log(diff);

</script>

1.15 map简介及API

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
<script>
// 声明map
let m = new Map();

// 添加元素
m.set('name', 'monica');
m.set('change', function () {
console.log('改变');
});
let key = {
name: 'monica'
}
m.set(key, ['tom', 'jack', 'andrew']);

// 删除元素
// m.delete('name');

// 获取
console.log(m.get('change'));
// 清空
// m.clear();
console.log(m);
// 遍历
for(let i of m){
console.log(i);
}
</script>

1.16.1 class介绍与初体验

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
<script>
// ES5写法
// 定义一个构造函数
// function Phone(brand, price) {
// this.brand = brand;
// this.price = price;
// }
// // 向构造函数的prototype中添加方法
// Phone.prototype.call = function () {
// console.log('打电话');
// }
// let p=new Phone('huawei',5999);
// p.call();
// console.log(p);

//class写法,相当于语法糖,大部分能用ES5实现,但更好体现面向对象
class Phone {
constructor(brand, price) {
this.brand = brand;
this.price = price;
};
call(){
console.log('打电话');
}
}
let p2=new Phone('sanxing',2999);
p2.call();
console.log((p2));
</script>

1.16.2 class静态成员

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<script>
// 函数对象的属性与方法只在函数对象上,而不在实例对象上
// 类似于类的静态成员,只能通过类访问,而实例无法访问
class Phone {
static name = 'monica';
static call() {
console.log('打电话');
};
constructor() {
};
}
let p = new Phone();
console.log(p.name);
// p.call();
console.log(Phone.name);
Phone.call();
</script>

1.16.2 ES5构造函数继承

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
<script>
// 构造函数继承
//手机
function Phone(brand, price) {
this.brand = brand;
this.price = price;
}
Phone.prototype.call = function () {
console.log('我可以打电话!');
}

// 智能手机
function SmartPhone(brand, price, color, size) {
// 改变this指向并传参,立即执行Phone(brand,price)
// apply(this,[a,b]) 以数组形式传参
Phone.call(this, brand, price);
this.color = color;
this.size = size;
}
// *********设置子级构造函数的原型***********
SmartPhone.prototype = new Phone;
SmartPhone.prototype.constructor = SmartPhone;

SmartPhone.prototype.photo = function () {
console.log('拍照');
}
SmartPhone.prototype.playGame = function () {
console.log('玩游戏');
}
let sp = new SmartPhone('huawei', 5999, 'black', '4.7inch');
console.log(sp);
sp.call();
sp.photo();
sp.playGame();
</script>

1.16.3 class的类继承

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
<script>
// 父类
class Phone {
constructor(brand, price) {
this.brand = brand;
this.price = price;
};
call() {
console.log('打电话');
};
}

// 子类
class SmartPhone extends Phone {
constructor(brand, price, color, size) {
super(brand, price);
this.color = color;
this.size = size;
};
photo() {
console.log('拍照');
};
playGame() {
console.log('玩游戏');
}
}
let sp = new SmartPhone('xiaomi', 4999, 'white', '4.9inch');
console.log(sp);
sp.call();
sp.photo();
sp.playGame();
</script>

1.16.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
<script>
// 父类
class Phone {
constructor(brand, price) {
this.brand = brand;
this.price = price;
};
call() {
console.log('打电话');
};
}

// 子类
class SmartPhone extends Phone {
constructor(brand, price, color, size) {
super(brand, price);
this.color = color;
this.size = size;
};
// 重写父类方法
// 但不能在成员属性中调用super()
// 只能进行重写
call() {
console.log('我可以进行视频通话');
};
photo() {
console.log('拍照');
};
playGame() {
console.log('玩游戏');
}
}
let sp = new SmartPhone('xiaomi', 4999, 'white', '4.9inch');
console.log(sp);
sp.call();
sp.photo();
sp.playGame();
</script>

1.16.5 class中getter和setter设置

(一般与动态属性相关)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script>
class Phone {
get price() {
console.log('price被读取了');
// 必须要返回一个值,后续调用price属性(与get后同名)即可触发
return '123';
};
set price(newValue) {
console.log('price被修改了');
// 可判断给属性赋值的逻辑,如newValue是否合法
// 必须要传入至少一个参数
}
};
let s = new Phone();
console.log(s.price);
</script>

1.17 ES6的数值扩展

  • Number.EPSILON :ES6 在 Number 对象上,新增一个极小的常量,表示 1 与 大于 1 的最小浮点数之差。

  • Math.trunc () :去除一个数的小数部分,返回整数部分。

  • Math.sign () :用来判断一个数是正数(1)、负数(-1)还是零(0)。

  • Number.isFinite :检测是否为有限数。

  • Number.isNaN :检测一个数值是不是NaN。

  • Number.parseInt

  • Number.parseInt('12348哈哈哈哈哈')	//12348
    
    1
    2
    3
    4
    5

    - Number.parseFloat

    - ```js
    Number.parseFloat('3.1415926嘻嘻嘻嘻嘻嘻') //3.1415926
  • Number.isInteger: 判断一个数是否为整数。

1.18 ES6的对象方法扩展

Object.is()

ES5 比较两个值是否相等,只有两个运算符:相等运算符(==)和严格相等运算符(===)。它们都有缺点,前者会自动转换数据类型,后者的NaN不等于自身,以及+0等于-0。JavaScript 缺乏一种运算,在所有环境中,只要两个值是一样的,它们就应该相等。

ES6 提出“Same-value equality”(同值相等)算法,用来解决这个问题。Object.is就是部署这个算法的新方法。它用来比较两个值是否严格相等,与严格比较运算符(===)的行为基本一致。

1
2
3
4
5
+0 === -0 //true
NaN === NaN // false

Object.is(+0, -0) // false
Object.is(NaN, NaN) // true

Object.assign()(浅拷贝)

Object.assign()方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。

1
2
3
4
5
6
7
const target = { a: 1 };

const source1 = { b: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

Object.assign()方法的第一个参数是目标对象,后面的参数都是源对象。

注意,如果目标对象与源对象有同名属性,或多个源对象有同名属性,则后面的属性会覆盖前面的属性。

1
2
3
4
5
6
7
const target = { a: 1, b: 1 };

const source1 = { b: 2, c: 2 };
const source2 = { c: 3 };

Object.assign(target, source1, source2);
target // {a:1, b:2, c:3}

Object.getPrototypeOf()

该方法与Object.setPrototypeOf方法配套,用于读取一个对象的原型对象。

1
Object.getPrototypeOf(obj);

下面是一个例子。

1
2
3
4
5
6
7
8
9
10
11
12
function Rectangle() {
// ...
}

const rec = new Rectangle();

Object.getPrototypeOf(rec) === Rectangle.prototype
// true

Object.setPrototypeOf(rec, Object.prototype);
Object.getPrototypeOf(rec) === Rectangle.prototype
// false

Object.setPrototypeOf()

Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的原型对象(prototype),返回参数对象本身。它是 ES6 正式推荐的设置原型对象的方法。

1
2
3
4
5
// 格式
Object.setPrototypeOf(object, prototype)

// 用法
const o = Object.setPrototypeOf({}, null);

该方法等同于下面的函数。

1
2
3
4
function setPrototypeOf(obj, proto) {
obj.__proto__ = proto;
return obj;
}

下面是一个例子。

1
2
3
4
5
6
7
8
9
10
let proto = {};
let obj = { x: 10 };
Object.setPrototypeOf(obj, proto);

proto.y = 20;
proto.z = 40;

obj.x // 10
obj.y // 20
obj.z // 40

上面代码将proto对象设为obj对象的原型,所以从obj对象可以读取proto对象的属性。

1.19.1 模块化介绍

防止命名冲突;代码复用;高维护性

1.19.2 模块化语法

export 命令用于规定模块的对外接口

import 命令用于输入其他模块提供的功能

1
2
3
4
<script type="module">
import * as m1 from './js/m1.js';
console.log(m1);
</script>
1
2
3
4
5
6
// 在需要向外暴露的数据或函数等前加上 export 命令
// 分别暴露
export let student='monica';
export function study(){
console.log('我爱学习');
}

1.19.3 模块暴露语法汇总

1
2
3
4
5
6
7
8
9
10
<script type="module">
import * as m1 from './js/m1.js';
import * as m2 from './js/m2.js'
import * as m3 from './js/m3.js'
console.log(m1);
console.log(m2);
console.log(m3);
// m3的属性和方法在default对象下
m3.default.improve();
</script>

分别暴露

1
2
3
4
5
6
// 在需要向外暴露的数据或函数等前加上 export 命令
// 分别暴露
export let student='monica';
export function study(){
console.log('我爱学习');
}

统一暴露

1
2
3
4
5
6
// 统一暴露
let school='UESTC';
function change(){
console.log('改变你');
};
export{school,change};

默认暴露

1
2
3
4
5
6
7
// 默认暴露
export default{
name:'tom',
improve(){
console.log('我想提升自己');
}
};

1.19.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
<script type="module">
// 1.通用的导入方式
import * as m1 from './js/m1.js';
import * as m2 from './js/m2.js'
import * as m3 from './js/m3.js'
console.log(m1);
console.log(m2);
console.log(m3);
// m3的属性和方法在default对象下
m3.default.improve();

// 2.解构赋值
import { student, study } from './js/m1.js';
// 有重名的话直接as 别名解决就好
import { student as UESTC, change } from './js/m2.js';
import { default as m3 } from './js/m3.js';
console.log(student, study);
console.log(UESTC, study);
console.log(m3);

// 3.简便形式(仅针对默认暴露)
import m3 from './js/m3.js';
console.log(m3);
</script>

1.19.5 第2种模块化方式

app.js(入口文件)

1
2
3
4
5
6
7
8
9
10
// 入口文件

// 引入模块
import * as m1 from './m1.js';
import * as m2 from './m2.js'
import * as m3 from './m3.js'

console.log(m1);
console.log(m2);
console.log(m3);
1
<script type="module" src="./js/app.js"></script>

学习ES6新特性
http://example.com/2024/09/24/学习ES6新特性/
作者
monica
发布于
2024年9月24日
许可协议