1. 迭代器
1.1 定义
遍历器(Iterator
)就是一种机制。它是一种接口,为各种不同的数据结构提 供统一的访问机制。任何数据结构只要部署 Iterator
接口,就可以完成遍历操作。
- ES6 创造了一种新的遍历命令
for...of
循环,Iterator
接口主要供for...of
消费。 - 原生具备
iterator
接口的数据(可用for of 遍历)Array
Arguments
Set
Map
String
TypedArray
NodeList
案例:使用 next()
方法遍历原生自带 iterator
接口的数据:
// Iterator是一种新的遍历机制,可以通过next()进行一一遍历
// (1)迭代器是一个接口,能快捷的访问数据,通过Symbol、iterator来创建迭代器,
// 通过迭代器的next()方法获取迭代之后的结果
//(为各种不同的数据结构提供统一的访问机制,任何数据结构只要部署Iterator接口,就可以完成遍历操作)
// 2. 迭代器是用于遍历数据结构的指针(数据库的游标)
// 遍历 Map
const mp = new Map();
mp.set('a', 1);
mp.set('b', 2);
mp.set('c', 3);
let iter1 = mp[Symbol.iterator]();
// next() 方法每执行一次,指针自增
console.log(iter1.next()); // { value: [ 'a', 1 ], done: false }
console.log(iter1.next()); // { value: [ 'b', 2 ], done: false }
console.log(iter1.next()); // { value: [ 'c', 3 ], done: false }
console.log(iter1.next()); // { value: undefined, done: true }
// 遍历数组
let xiyou = ['唐僧','孙悟空','猪八戒','沙僧'];
let iter2 = xiyou[Symbol.iterator]();
console.log(iter2.next()); // { value: '唐僧', done: false }
console.log(iter2.next()); // { value: '孙悟空', done: false }
console.log(iter2.next()); // { value: '猪八戒', done: false }
console.log(iter2.next()); // { value: '沙僧', done: false}
console.log(iter2.next()); // { value: undefined, done: true}
上面的案例只是为了证明他们自带 iterator
接口,实际上直接使用 for...of
方法遍历即可(iterator
接口为 for...of
)服务。例如,可以使用 for [k, v] of map
来遍历 Map 数据结构中的键和值。
const mp = new Map();
mp.set('a', 1);
mp.set('b', 2);
mp.set('c', 3);
for (let [k, v] of mp) {
console.log(k, v);
}
/*
a 1
b 2
c 3
*/
1.2 工作原理
- 创建一个指针对象,指向当前数据结构的起始位置
- 第一次调用对象的
next
方法,指针自动指向数据结构的第一个成员 - 接下来不断调用
next
方法,指针一直往后移动,直到指向最后一个成员 - 每调用
next
方法返回一个包含value
和done
属性的对象
应用场景:需要自定义遍历数据的时候,要想到迭代器。
1.3 自定义遍历数据
我们可以通过给数据结构添加自定义 [Symbol.iterator]()
方法来使该数据结构能够直接被遍历,从而使 for...of
能够直接遍历指定数据,达到为 for...of
服务的功能。
// 需求:遍历对象中的数组
const xiaomi = {
uname: '小明',
course: [ '高数', '大物', '英语', '数据库' ],
// 通过自定义 [Symbol.iterator]() 方法
[Symbol.iterator]() {
// 初始指针对象指向数组第一个
let index = 0;
// 保存 xiaomi 的 this 值
let _this = this;
return {
next: function () {
// 不断调用 next 方法,直到指向最后一个成员
if (index < _this.course.length) {
return { value: _this.course[index++], done: false };
} else {
// 每调用next 方法返回一个包含value 和done 属性的对象
return { value: undefined, done: true };
}
}
}
}
}
// for...of直接遍历达到目的
for (let v of xiaomi) {
console.log(v);
}
2. Generator 生成器函数
2.1 生成器函数的声明和调用
生成器函数是 ES6 提供的一种 异步编程解决方案,语法行为与传统函数完全不同。
*
的位置没有限制- 使用
function * gen()
和yield
可以声明一个生成器函数。生成器函数返回的结果是迭代器对象,调用迭代器对象的next
方法可以得到yield
语句后的值。 - 每一个
yield
相当于函数的暂停标记,也可以认为是一个分隔符,每调用一次next()
,生成器函数就往下执行一段。 next
方法可以传递实参,作为yield
语句的返回值
// Generator 生成器函数 可以通过yield关键字,将函数挂起,为改变执行流程提供了可能,同时为做异步编程提供了方案
// Generator函数与普通函数区别
// 1. function后面 函数名之有个*
// 2. 只能在函数内部使用yield表达式,让函数挂起
function* fn(a) {
console.log('start');
yield 2;
console.log('end');
}
let o = fn();
console.log(o.next());//会卡在 yield 2; 这里不在往下打印
console.log(o.next());//再调用一次next(),才会打印 end,并且返回{value: undefined, done: true}
// 总结:Generator 生成器函数是分段执行的,yield语句是暂停执行,而next()是恢复执行
console.log('--------------');
function* fun() {
console.log('start');//start
// x不是 yield '2'; 的返回值,它是next() 调用 恢复当前yield() 执行传入的实参
let x = yield '2';
console.log('one:' + x);//one:10
let y = yield '3';
console.log('two:' + y);
return x + y;
}
const add = fun();
console.log(add.next()); //{value: "2", done: false},这里不用赋值,因为执行到yield '2';这里就暂停了不会继续赋值给x
console.log(add.next(10));//就是给前面的x赋值10, {value: "3", done: false}
console.log(add.next(20));//就是给前面的y赋值20, {value: 30, done: true}
// 使用场景:为不具备Iterator接口的对象提供了遍历操作
2.2 生成器函数案例
案例1:1s后输出111,2s后输出222,3s后输出333
-
传统方式:嵌套太多,代码复杂,产生 回调地狱。
setTimeout(() => { console.log(111); setTimeout(() => { console.log(222); setTimeout(() => { console.log(333); }, 3000); }, 2000); }, 1000);
-
生成器实现:结构简洁明了
<script> function one() { setTimeout(() => { console.log(111); iter.next(); }, 1000); } function two() { setTimeout(() => { console.log(222); iter.next(); }, 2000); } function three() { setTimeout(() => { console.log(333); iter.next(); //个人认为这一句可有可无 }, 3000); } function* gen() { yield one(); yield two(); yield three(); } let iter = gen(); iter.next(); </script>
3. Promise
3.1 Promise 的定义和使用
Promise
是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步操作并可以获取其成功或失败的结果。
一个 Promise
必然处于以下几种状态之一:
- 待定(
pending
):初始状态,既没有被兑现,也没有被拒绝。 - 已兑现(
fulfilled
):意味着操作成功完成。 - 已拒绝(
rejected
):意味着操作失败。
Promise
的使用:
- Promise 构造函数:
new Promise((resolve, reject)=>{})
Promise.prototype.then
方法Promise.prototype.catch
方法
<script>
// Promise 承诺
// 相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果
// 各种异步操作都可以用同样的方法进行处理 axios
// 特点:
// 1. 对象的状态不受外界影响,处理异步操作 三个状态 Promise(待定) fulfilled/Resolved(成功) rejected(失败)
// 2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果
let pro = new Promise(function (Resolved, rejected) {
// 执行异步操作
let res = {
code: 200,
data: {
name: 'lsy'
},
error: {
age: 18
}
}
setTimeout(() => {
if (res.code === 300) {
Resolved(res.data);
} else {
rejected(res.error)
}
}, 2000)
})
console.log(pro);
pro.then((val) => {
console.log(val);//接收的是Resolved这个函数
}, (err) => {
console.log(err);//接收的是rejected这个函数
})
</script>
3.2
Promise 封装读取文件
// 封装一个异步操作
function timeOut(ms) {
return new Promise((Resolved, rejected) => {
setTimeout(() => {
console.log('成功了!');
}, ms);
})
}
timeOut(2000).then((val) => {
console.log(val);
})
3.3 Promise 封装 Ajax 请求(待补充)
下面代码还没完善,没看懂,要重看...
<script>
// 自己封装的
const getJSON = function (url) {
return new Promise((resole, reject) => {
const xhr = new XMLHttpRequest();
// 第一步:打开
xhr.open('GET', url);//方式是GET,对象是形参
//当前状态发生改变(0-4)0初始化,1还没发送,2 3当前进行中,4成功回调
xhr.onreadystatechange = handler;//对应的是一个回调函数
xhr.responseType = 'json';//约定返回数据的类型为json
xhr.setRequestHeader('Accept', 'application/json');
// 发送
xhr.send();//必须写
function handler() {
// console.log(this);
if (this.readyState === 4) {
if (this.status === 200) {
resole(this.response.HeWeather6)
} else {
reject(new Error(this.statusText))
}
}
}
})
}
// 调用的
getJSON('http://free-api.heweather.net/s6/weather/now?location=beijing&key=4693ff5ea653469f8bb0c29638035976')
.then((data) => {
console.log(data);
}, (err) => {
console.log(err);
})
// then() 第一个参数是resole回调函数,第二个参数是可选的,是reject状态回调的函数
// then()返回一个新的Promise实例,可以用来链式编程
// resole() reject() all() race() done() finally()
// 1. resole() 能将现有的任何对象转换成Promise对象
// let p = Promise.resolve('foo');//等价于 ↓
// let p=new Promise(resole=>resole('foo'));
// console.log(p);//Promise {<fulfilled>: "foo"}
// p.then((data) => {
// console.log(data);//foo
// })
// 2. all() 应用:一些游戏类的素材比较多,等待图片、flash、静态资源文件,都加载完成,才进行页面的初始化
let p1 = new Promise((resole, reject) => { })
let p2 = new Promise((resole, reject) => { })
let p3 = new Promise((resole, reject) => { })
let p4 = Promise.all([p1, p2, p3])
p4.then(() => {
// 三个都成功 才成功
}).catch(err => {
// 如果有一个失败 则失败
})
// 3. race() 某个异步请求设置超时时间,并且在超时后执行相应操作
// (1)请求图片
function requestImg(imgSrc) {
return new Promise((resole, reject) => {
const img = new Image();
img.onload = function () {
resole(img);
};
img.src = imgSrc;
});
};
function timeOut() {
return new Promise((resole, reject) => {
setTimeout(() => {
reject('图片请求超时');
}, 3000)
})
}
Promise.race([requestImg('images/loginbg.png').timeOut()]).then((res) => {
console.log(res);
}).catch(err => {
console.log(err);
})
</script>
4. async 的用法(待补充)
<script>
// Generator Promise async 1. 解决回调地域,2. 使得异步操作更加方便
// 作用:使得异步操作更加方便
// 基本操作:async会返回一个Promise对象 then catch
// async是Generator的一个语法糖
async function fn() {
// return await 'hello';
let s = await 'hello';
let data = await s.split('')
return data;
}
// console.log(fn());//返回promise对象
// 如果async函数中有多个await 那么then函数会等待所有的await指令运行完的结果,才去执行
fn().then(v => {
console.log(v);//["h", "e", "l", "l", "o"]
}).catch(e => {
console.log(e);
})
async function fun() {
// throw new Error('出错了');
await Promise.reject('出错了');
await Promise.resolve('hello');
}
fun().then(v => {
console.log(v);//["h", "e", "l", "l", "o"]
}).catch(e => {
console.log(e);
})
</script>
5. class 类
<script>
// es5 造类
// function Person(name, age) {
// this.name = name;
// this.age = age;
// }
// Person.prototype.sayName = function () {
// return this.name
// }
// let p1 = new Person('lsy', 18);
// console.log(p1);
class Person {
// 实例化的时候会立即被调用
constructor(name, age) {
this.name = name;
this.age = age;
}
}
Object.assign(Person.prototype, {
sayName() {
return this.name;
},
sayAge() {
return this.age;
}
})
let p1 = new Person('lsy', 18);
console.log(p1);
</script>
6. 类的继承 extends
<script>
// 使用关键字 extends
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
return this.name;
}
sayAge() {
return this.age;
}
}
class Dog extends Animal {
constructor(name, age, color) {
super(name, age);//相当于 ↓
// Animal.call(this,name,age);
this.color = color;
}
// 子类自己的方法
sayColor() {
return `${this.name}有${this.age}岁了,它的颜色是${this.color}`
}
// 重写父类的方法
sayName() {
return this.name + super.sayAge + this.color;
}
}
let d1 = new Dog('大黄', 3, 'yello');
// console.log(d1.sayName());//大黄
console.log(d1.sayColor());//大黄有3岁了,它的颜色是yello
console.log(d1.sayName());
</script>
7.ES6 的模块化实现
module
<body>
<script type="module">
// CommonJS和AMD
// import obj, { name, age, sayName } from './modules/index.js';
// console.log(obj);//{foo: "foo"} 这两个obj都可以自己命名
// console.log(name, age, sayName());//lsy 18 my name is lsy
// import * as f from './modules/index.js';
// console.log(f);//出来一个模块Module
// console.log(f.default);//{foo: "foo"}
import Person, { name, age, sayName } from './modules/index.js';
// console.log(Person);
const p = new Person();
p.sayAge()
</script>
</body>
index.js 部分
// es6模块功能主要有两个命令构成:export和import
// export 用于规定模块的对外接口,import用于输入其他模块提供的功能
// 一个模块就是独立的文件
// export const name = 'lsy';
// export const age = 18;
// export function sayName() {
// return 'my name is lsy';
// }
// export { sayName }
// 两个写法:1. 前面 export后面跟function函数 ,(推荐)
// 2. 前面不写 export 函数外写export,但要用{}括起来 如果这样写export.sayName()会报错
const name = 'lsy';
const age = 18;
function sayName() {
return 'my name is lsy';
}
export {
name, age, sayName
}
// const obj = {
// foo: 'foo'
// }
class Person {
constructor() {
}
sayAge() {
console.log('16');
}
}
// export default obj;
export default Person;
笔记并不完善,要结合某位不知名兄弟的笔记一起看才行