学习要点:
1.Set 数据集合
本节课我们来开始学习 ES6 新增的 Set 数据集合的用法;
严格来说,对象不算是一种数据结构
先来打印看看它是什么
let set = new Set();
console.log(set);
//创建一个 Set 集合
let set = new Set();
set.add(1);
set.add(2);//这两个合并成一个了
set.add(2);
set.add('2');
set.add('c');
console.log(set); //Set {1,2,'2','c'}
console.log(set.size); //长度 4
//通过构造参数初始化集合
let set = new Set([1, 2, 2, 3, 3, 4, 5]);
console.log(set); //Set {1, 2, 3, 4, 5}
let set = new Set([1, 2, 2, 3, 3, 4, 5]);
console.log(set.has(2)); //true
console.log(set.has('2')); //false
let set = new Set([1, 2, 2, 3, 3, 4, 5]);
console.log(set); //{ 1, 2, 3, 4, 5 }
console.log(set.delete(2)); //true
console.log(set); //{ 1, 3, 4, 5 }
console.log(set.clear());//undefined
console.log(set);//{}
let set = new Set([1, 2, 2, 3, 3, 4, 5]);
let array = [...set];
console.log(array);
let set = new Set([1, 2, 2, 3, 3, 4, 5]);
for (let i of set){
console.log(i);
}
let set = new Set([1, 2, 2, 3, 3, 4, 5]);
//forEach 变量
//在 Set 集合中 key 和 value 都是值
//s 表示 set 集合本身
set.forEach(function (key, value, s) {
console.log(value);
});
let ws = new WeakSet([1,2,3])
//强引用
let set = new Set(),
obj = {1:1};
set.add(obj);
console.log(set); //引用存在
//移出引用
obj = null;
console.log(set); //引用依然存在
//弱引用
let ws = new WeakSet(),
obj = {1:1};
ws.add(obj);
console.log(ws.has(obj)); //引用存在,因为弱引用它是无法查看内部的情况的,只能通过这个方式查看是否存在
//移出引用
obj = null;
console.log(ws.has(obj)); //随着销毁而释放
学习要点:
1.Map 数据集合
本节课我们来开始学习 ES6 新增的 Map 数据集合的用法;
let map = new Map();
console.log(map);
//创建 Map 集合
let map = new Map();
map.set('name', 'Mr.Lee'); //.set 添加,支持.set(...).set(...)
map.set('age', 100);
console.log(map);
console.log(map.get('name')); //.get 获取
//通过构造参数初始化集合
let map = new Map([
['name', 'Mr.Lee'],
['age', 100]
]);
console.log(map);
let map = new Map([
['name', 'Mr.Lee'],
['age', 100]
]);
console.log(map.has('name')); //true
console.log(map.size); //2
map.delete('name'); //删除
map.clear(); //清空
let map = new Map([
['name', 'Mr.Lee'],
['age', 100]
]);
map.forEach((value, key, m) => {
console.log(key + '-' + value);
console.log(m);
});
let wm = new WeakMap();
wm.set('1');
console.log(wm);
let wm = new WeakMap(),
obj = {};
wm.set(obj);
console.log(wm);
和weak set一样
学习要点:
1.迭代器和生成器
2.默认迭代接口
本节课我们来开始学习 ES6 新增的迭代器和生成器的用法。
//生成器
function *cit() {
yield 1;
yield 2;
yield 3;
}
PS:1,2,3 是我们要遍历的值;下面我们要创建迭代器;
//迭代器
let it = cit();
//每执行一次.next()将下移一行
console.log(it.next()); //1, false
console.log(it.next()); //2, false
console.log(it.next()); //3, false
console.log(it.next()); //undefined, true
PS:属性 value 得到值,没有返回 undefined,当没有值了,done 则返回 true;
function *cit(items) {
for (let i = 0 ; items.length; i++) {
yield items[i]
}
}
let it = cit([1,2,3,4,5]);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
console.log(it.next().value);
PS:如果作为匿名函数使用:let cit = function *(items);
let items = [1, 2, 3, 4, 5];
console.log(items.keys()); //key, Object [Array Iterator]
console.log(items.values()); //value, Object [Array Iterator]
console.log(items.entries());//key+value, Object [Array Iterator]
let items = [1, 2, 3, 4, 5];
//for..of 遍历得到 value 值
for (let i of items.values()) {
console.log(i);
}
let items = [1, 2, 3, 4, 5];
let values = items.values();
console.log(values.next());
PS:下节课,我们把其它几种数据类型的默认迭代都演示一遍;
学习要点:
1.Promise 介绍
2.实例测试
本节课我们来开始学习 ES6 新增的 Promise 异步通信方案的功能。
//创建一个 Promise 实例
let p = new Promise((resolve, reject) => {
//一顿异步通信操作后,返回成功或失败
//然后判断成功或失败去执行 resolve 或 reject
if (true) {
//console.log('异步通信执行成功!');
resolve('执行成功!');
} else {
//console.log('异步通信执行失败!');
reject('执行失败!');
}
});
//then 方法可执行 resolve 的回调函数
//catch 方法可执行 reject 的回调函数
// p.then((value) => {
// console.log(value);
// }).catch((reason) => {
// console.log(reason);
// });
//或者这种一体化语法也行
p.then((value) => {
console.log(value);
},(reason)=>{
console.log(reason);
});
PS:如果你有过很多层异步通信实战基础,上面提供的方法会突然感觉清晰很多;
PS:因为它把多层嵌套的回调函数给分离出来,通过 then 和 catch 来实现;
...
p.then((value) => {
console.log(value);
},(reason)=>{
console.log(reason);
});
//模拟异步 1
setTimeout(() => {
console.log('1.返回异步通信');
}, 3500);
//模拟异步 2
setTimeout(() => {
console.log('2.返回异步通信');
}, 800);
//模拟异步 3
setTimeout(() => {
console.log('3.返回异步通信');
}, 1500);
PS:这里不管你怎么调节,最终输出结果总是:2,3,1。需求顺序要:1,2,3;
let p1 = new Promise((resolve, reject) => {
//模拟异步 1
setTimeout(() => {
//console.log('1.异步通信');
resolve('1.返回异步通信');
}, 3500);
});
let p2 = new Promise((resolve, reject) => {
//模拟异步 2
setTimeout(() => {
//console.log('2.异步通信');
resolve('2.返回异步通信');
}, 800);
});
let p3 = new Promise((resolve, reject) => {
//模拟异步 3
setTimeout(() => {
//console.log('3.异步通信');
resolve('3.返回异步通信');
}, 1500);
});
//执行回调
p1.then((value) => {
console.log(value);
return p2;
}).then((value) => {
console.log(value);
return p3;
}).then((value) => {
console.log(value);
});
学习要点:
1.状态特点
2.更多方法
本节课我们来开始学习 ES6 新增的 Promise 异步通信方案的状态特点
(1) .Pending(进行中)
(2) .Fulfilled(已成功)
(3) .Rejected(已失败)
pending -> resolve 方法 -> fulfilled -> resolved
pending -> reject 方法 -> rejected -> resolved
PS:测试当前状态,在浏览器环境下比较直观直接:console.log(p1),在不同阶段执行;node环境下看得不明显,用浏览器测试
let p1 = new Promise((resolve, reject) => {
//模拟异步 1
setTimeout(() => {
//console.log('1.异步通信');
resolve('1.返回异步通信');
}, 3500);
});
let p2 = new Promise((resolve, reject) => {
//模拟异步 2
setTimeout(() => {
//console.log('2.异步通信');
resolve('2.返回异步通信');
}, 800);
});
let p3 = new Promise((resolve, reject) => {
//模拟异步 3
setTimeout(() => {
//console.log('3.异步通信');
resolve('3.返回异步通信');
}, 1500);
});
console.log(p1);
//执行回调
p1.then((value) => {
console.log(p1);
console.log(value);
return p2;
}).then((value) => {
console.log(value);
return p3;
}).then((value) => {
console.log(value);
});
但是那个看起来还是太长了,下面有好的解决方案
let p1 = new Promise((resolve, reject) => {
//模拟异步 1
setTimeout(() => {
//console.log('1.异步通信');
resolve('1.返回异步通信');
}, 3500);
});
let p2 = new Promise((resolve, reject) => {
//模拟异步 2
setTimeout(() => {
//console.log('2.异步通信');
resolve('2.返回异步通信');
}, 800);
});
let p3 = new Promise((resolve, reject) => {
//模拟异步 3
setTimeout(() => {
//console.log('3.异步通信');
resolve('3.返回异步通信');
}, 1500);
});
console.log(p1);
//执行回调
// p1.then((value) => {
// console.log(p1);
// console.log(value);
// return p2;
// }).then((value) => {
// console.log(value);
// return p3;
// }).then((value) => {
// console.log(value);
// });
//all方法,可以解决上面那一大堆, p1,p2,p3 是三个 Promise 实例,数组元素顺序即输出顺序
let p = Promise.all([p1, p2, p3]);
//将三个 Promise 实例的回调组合成数组输出
p.then(value => {
console.log(value);
})
PS:虽然 p1,p2,p3 都是异步操作,但最终要等待所有异步完成,才可以输出;
PS:只要 p1,p2,p3 中有一个出现了 Rejected,则会执行失败回调
//p1,p2,p3 只要有一个改变状态,即回调
let p = Promise.race([p1, p2, p3]);
//所以,这里只输出 p2
p.then(value => {
console.log(value);
});
//直接返回成功或失败的 Promise 实例
let ps = Promise.resolve('成功');
let pj = Promise.reject('失败');
ps.then(value => {
console.log(value);
return pj;
}).catch(reason => {
console.log(reason);
})
等价于
new Promise(resolve => resolve('成功'));
那这样的快捷语法糖有什么用呢?下面是一个例子
function getP() {
if (false) {
return new Promise(resolve => {
resolve('异步成功');
})
} else {
return 0; //强制类型一致保证程序正确性 Promise.resolve(0)
}
}
getP().then(value => {
console.log(value);
});
这样就可能出问题,因为你很有可能会读取失败,我们要保持返回类型的一致性,就可以通过这种语法糖快速调用 resolve回调
function getP() {
if (false) {
return new Promise(resolve => {
resolve('异步成功');
})
} else {
//return 0; //强制类型一致保证程序正确性 Promise.resolve(0)
return Promise.resolve(0);
}
}
//这里你调用.then就肯定可以成功
getP().then(value => {
console.log(value);
});
学习要点:
1.代理能力
本节课我们来开始学习 ES6 新增的 Proxy 代理方法。
//目标对象
let obj = {
name : 'Mr.Lee',
age : 100,
gender : '男'
};
//创建一个代理,参数 1 拦截的目标对象,参数 2 拦截行为
//参数 2 如果是空对象,代理直接会调用目标对象
let p = new Proxy(obj, {
//get 方法用于拦截某个属性的读取操作
//这里直接 return,通过代理对象无论访问目标对象的任何属性都是 fail
get(target, property) {
return 'fail';
},
});
//代理对象访问 name 为 fail
console.log(p.name);
//目标对象
let obj = {
name : 'Mr.Lee',
age : 100,
gender : '男'
};
//创建一个代理,参数 1 拦截的目标对象,参数 2 拦截行为
//参数 2 如果是空对象,代理直接会调用目标对象
let p = new Proxy(obj, {
//get 方法用于拦截某个属性的读取操作
get(target, property) {
if (property === 'age') {
return target[property] - 80;
}
},
});
console.log(p.name);//undefined
console.log(p.age);//20
console.log(p.abc);//不存在的属性 undefined
//目标对象
let obj = {
name : 'Mr.Lee',
age : 100,
gender : '男'
};
//创建一个代理,参数 1 拦截的目标对象,参数 2 拦截行为
//参数 2 如果是空对象,代理直接会调用目标对象
let p = new Proxy(obj, {
//get 方法用于拦截某个属性的读取操作
get(target, property) {
if (property === 'age') {
return target[property];
}
},
//set 可以拦截某个属性的赋值操作,比 get 多了参数 3
set(target, property, value) {
if (property === 'age') {
if (!Number.isInteger(value) || value > 150) {
throw new TypeError('年龄数据不合法!');
}
target[property] = value;
}
}
});
p.age = 150;
// p.age = 200;//年龄数据不合法!
console.log(p.age);//150
console.log(obj.age); //150 目标对象属性也被更改
PS:代理并不是复制克隆目标对象,只是拦截目标对象更改默认行为;
PS:代理可以使用 set()和 get()方法,对目标对象的数据进行过滤和验证;
PS:代理对象中任何未公开或不存在的属性,可自定义返回内容,比如:fail 或已屏蔽;
PS:代理也可以阻止赋值的默认行为:直接 return false,就禁止赋值了;
set(target, property, value) {
return false;
}
学习要点:
1.async 语法
本节课我们来开始学习 ES8 新增的异步 async 方法。
let p1 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('1.返回异步通信');
}, 3500);
});
let p2 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('2.返回异步通信');
}, 800);
});
let p3 = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('3.返回异步通信');
}, 1500);
});
//创建一个 async 函数,执行异步操作
//await 关键字:等待异步执行完毕后回调;
let as = async () => {
let result = await p1;
console.log(result);
};
//执行 async 函数
as();
PS:上面语法,用 ES5 过渡一下,帮助理解,具体如下:
async function as() {}
let as = async function () {}
let obj = {async as() {}}; //也支持对象方式
//多个异步,按输出顺序加载,没有 then,清晰很多
async function as() {
let r1 = await p1,
r2 = await p2,
r3 = await p3;
console.log(r1);
console.log(r2);
console.log(r3);
}
as();
PS:await 关键字只能在 async 函数内部,否则不可识别;
PS:从上面的例子中,能感受到语义和清晰度都得到了很大提升,更像同步代码;
async function as() {
let all = [await p1, await p2, await p3];
console.log(all);
}
as();
//返回值是 Promise 对象
//相当于 Promise.resolve()
async function as() {
return 'hello, async!';
}
//所以还需要 Promise 对象的then
as().then(value => {
console.log(value);
});
async function as() {
return await p1;
}
console.log(as()); //得到的是 Promise 对象的 pending 状态
as().then(value => { //这里还是需要 then
console.log(value);
});
学习要点:
1.类 class
2.getter 和 setter
本节课我们来开始学习 ES6 新增的类 class 的实现方法。
//创建一个类
class Person {
//构造函数(构造方法)
constructor(name) {
//this.name 是类的属性
//name 是构造参数赋值给属性
this.name = name;
}
//普通方法
run() {
console.log('类的方法输出!' + this.name);
}
}
//实例化一个 Person 对象
let p = new Person('Mr.Lee');
//执行 run()方法
p.run();
//给成员属性赋值
p.name = 'Mr.wang';
//输出对象的属性
console.log(p.name);
//判断 p 是否是 Person 对象
console.log(p instanceof Person);
//判断类的类型:function
console.log(typeof Person);
注意:这里是javascropt才有的写法
//No.1
let Per = class Person {};
//此时 new Person 会报错
let p = new Per('Mr.Lee');
//No.2
let Person = class {};
//No.3
let p = new class {}('Mr.Lee');
p.run();
// //创建一个类
// class Person {
// //构造函数(构造方法)
// constructor(name) {
// //this.name 是类的属性
// //name 是构造参数赋值给属性
// this.name = name;
// }
// //普通方法
// run() {
// console.log('类的方法输出!' + this.name);
// }
// }
//
// //实例化一个 Person 对象
// let p = new Person('Mr.Lee');
// //执行 run()方法
// p.run();
//
// //给成员属性赋值
// p.name = 'Mr.wang';
//
// //输出对象的属性
// console.log(p.name);
// //判断 p 是否是 Person 对象
// console.log(p instanceof Person);
// //判断类的类型:function
// console.log(typeof Person);
//创建一个类
class Person {
#name; //提案,浏览器暂时不支持
//构造函数(构造方法)
constructor(name) {
this.#name = name; //私有属性,类外无法访问
}
get name() {
return this.#name;
}
set name(value) {
this.#name = value;
}
}
let p = new Person('Mr.Lee');
//
// // p.#name = 'Mr.Wang'; // Private field '#name' must be declared in an enclosing class 直接不给修改
//
// p.name = 'Mr.Wang';
// console.log(p.name); //为什么这两句可以呢?
//因为上面两句,其实它并没有访问私有成员属性,而是自己创建了一个属性name,就相当于下面的代码
// let obj = {};
// obj.name = 'Mr.wang';
// console.log(obj.name);
//所以这就是容易混淆的地方,此时我们应该访问的是 #name, 那么#name 是私有的属性,那么我们应该怎么访问和修改呢?同时又要拦截外部 name的访问?
//利用 get set 同时名字取成和name相同的名字,就可以防止外部修改了。
学习要点:
1.类的继承
本节课我们来开始学习 ES6 新增的类 class 的继承功能
class Person {
constructor(name) {
this.name = name;
}
get user() {
return this.name;
}
set user(value){
this.name = value;
}
run() {
return 'name:' + this.name;
}
}
class Son extends Person {
}
//可以使用父类的构造
let c = new Son('Mr.li');
console.log(c.name);
//get,set 以及方法均可使用
c.user = 'Mr.Wang';
console.log(c.user);
console.log(c.run());
class Person {
constructor(name) {
this.name = name;
}
get user() {
return this.name;
}
set user(value){
this.name = value;
}
run() {
return 'name:' + this.name;
}
}
class Son extends Person {
//子类继承
constructor(name, age) { //覆写构造
super(name); //执行父类构造并传参
this.age = age;
}
run() { //覆写方法
return super.run() + this.age; //执行父类方法并返回内容
}
}
//覆写
let son = new Son('Mr.Lee', 100);
console.log(son.age);//子类构造自己传递进来的age
console.log(son.run());//先执行父类的方法,然后再执行子类自己的处理
console.log(Object.getPrototypeOf(Children) === Person);
class Person {
static gender = '男';
static go() {
return 'GO GO GO !' + Person.gender;//类名调用静态属性
}
}
class Children extends Person {
static gender = '女'; //覆写静态
static go() {
return 'o o o ' + Person.gender;//这里使用 Person 和 Children 是不一样的 如果这里使用 this.就等于Children类
}
}
console.log(Person.gender);//男
console.log(Person.go());//调用Person的静态方法
console.log(Children.gender);
console.log(Children.go());
拓展:es5演示静态方法和实例方法
let Animal = function (type) {
this.type = type
}
// 动态方法
Animal.prototype.walk = function(){
// 调用静态方法
Animal.eat()
console.log('I am walking')
}
// 静态方法
Animal.eat = function (food) {
console.log(`I am eating`);
}
let cat = new Animal('cat')
cat.walk()
cat.eat()
学习要点:
1.浏览器加载
2.Node 加载
本节课我们来开始学习 ES6 新增的模块化导入导出的方法。
export let name = 'Mr.Lee'; //导出这个变量
PS:里面有很多变量,导出那个那个才可以用,其它不可见
import {name} from './module.js';
console.log(name);
<script type="module" src="js/25.js"></script>
PS:注意,这种导入导出的方式属于 ES6 模块,仅支持浏览器模式;
如果不设置type="module"则会报错
export let name = 'Mr.Lee';
export function sum(x, y) {
return x + y;
}
export class Person {
constructor(name) {
this.name = name;
}
run() {
return 'name : ' + this.name;
}
}
import {name, sum, Person} from './module.js';
console.log(name);
console.log(sum(10, 20));
console.log((new Person('Mr.Lee')).run());
import * as obj from './module.js';
console.log(obj.name);
console.log(obj.sum(10, 20));
console.log((new obj.Person('Mr.Lee')).run());
import {name as user} from './module.js';
console.log(user); //name 无效了
let name = 'Mr.Lee';
function sum(x, y) {
return x + y;
}
class Person {
constructor(name) {
this.name = name;
}
run() {
return 'name : ' + this.name;
}
}
export {
name,
sum,
Person
}
export default name;
import name from './module.js';//导入得时候直接name就可以了
import name, {sum, Person} from './module.js';//如果还要引入别的,逗号,+花括号
新建common.js
文件
let name = 'Mr.Lee';
module.exports = {
name : name,
};
const name = require('./common.js');
console.log(name);