迭代器Iterator
//Iterator
//是一种新的遍历机制
/*1.迭代器是一个接口,能快捷的访问数据,通过Symbol.iterator创建迭代器
通过迭代的next方法获得迭代之后的结果*/
//2.迭代器适用于遍历数据结构的指针
//使用迭代
const items = ['one', 'two', 'three'];
//1.创建新的迭代器
const ite = items[Symbol.iterator]();
console.log(ite.next());
//{done: false value: "one"} done如果为false表示遍历继续 如果为true表示遍历完成
console.log(ite.next());
console.log(ite.next());
console.log(ite.next()); //{done: true value: undefined}
生成器Generator
function* add() {
console.log('start');
/* x 不是yield'2'的返回值,它是next()调用
恢复当前yield()执行传入的实参*/
let x = yield '2';
console.log('one:' + x);
let y = yield '3';
console.log('two:' + y);
return x + y;
}
const fn = add();
console.log(fn.next());//start {value: "2", done: false}
console.log(fn.next(10));
//one:10 {value: "3", done: false}
console.log(fn.next(20));//two:20 {value: 30, done: true}
使用场景:为不具备Inetrator接口的对象提供了便利操作
function* objEntries(obj) {
//获取对象的所有的key保存到数组[name,age]
const propKeys = Object.keys(obj);//必须要有keys()操作
for (const propkey of propKeys) {
yield [propkey, obj[propkey]];
}
}
const obj = {
name: 'qaq',
age: 20
}
obj[Symbol.iterator] = objEntries;
for (let [key, value] of objEntries(obj)) {
console.log(`${key}:${value}`);//name:qaq age:20
}
解决页面加载的异步问题(让异步代码同步化)
function* load(name) {
let a = yield;
loadUI();
yield showData(a);
hideUI();
}
let load1 = load();
load1.next();
load1.next(load1);
function loadUI() {
console.log('加载loading...页面');
}
function showData(name) {
//模拟异步操作
setTimeout(() => {
console.log('数据加载完成');
name.next();
}, 1000);
}
function hideUI() {
console.log('隐藏loading...页面');
}
打印结果为
- 加载loading...页面
- 数据加载完成
- 隐藏loading...页面
如果不使用该操作由于有setTimeout,hideUI()会比showData()更先加载出来
Promise
//相当于一个容器,保存着未来才会结束的事件(异步操作)的一个结果
//各种异步操作都可以用同样的操作进行处理
//特点:
//1.对象的状态不受外界影响
//处理异步操作三个状态 Pending(进行中)Resolved(成功) Rejected(失败)
//2.一旦状态改变,就不会再变,任何时候都可以得到这个结果
let pro = new Promise(function (resolved, rejected) {
//执行异步操作
let person = {
code: 201,
data: {
name: 'qaq'
},
error: '验证错误'
}
setTimeout(() => {
if (person.code === 200) {
resolved(person.data)
} else {
rejected(person.error)
}
}, 1000)
})
console.log(pro);
pro.then((val) => {
console.log(val);
}, (err) => {
console.log(err);
})
改变延迟时间(封装)
function timeOut(ms) {
return new Promise((resolved, rejected) => {
setTimeout(() => {
resolved('hello');
}, ms);
})
}
timeOut(2000).then((val) => {
console.log(val);
})
Promise方法
1. then()有两个参数第一个为resolved回调函数,第二个参数是可选的 为rejected状态的回调函数,then()返回的是一个新的promise实例,可以采用链式编程
2. catch()只有rejected状态的回调函数
3. resolve() 能将现有的任何对象转换成promise对象
//resolve()
let p = Promise.resolve('foo');
console.log(p);//Promise {<resolved>: "foo"}
p.then((val) => {
console.log(val);//foo
})
let p = Promise.resolve('foo');
等同于
let p = new Promise(resolve => {
return resolve('foo')
});
4. all()
应用:一些游戏类的素材比较多,等待图片、flash、静态资源都加载完成,才进行页面的初始化
//all()
let promise1 = new Promise((resolve,reject) => {});
let promise2 = new Promise((resolve,reject) => {});
let promise3 = new Promise((resolve,reject) => {});
let p4 = Promise.all([promise1,promise2,promise3]);
p4.then(() => {
//三个都成功才成功
}).catch(err =>{
//如果有一个失败 则失败
})
5. race()超时
race([要进行的操作方法,超时的方法]).then(如果在规定时间内完成操作返回这部分代码).catch(如果没在规定时间内完成操作返回这部分代码))
//race() 某个异步请求设置超时时间,并且在超时后执行相应的操作
//1.请求图片资源
function requestImg(imgSrc) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = function () {
resolve(img);
}
img.src = imgSrc;
});
}
//2.设置超时条件及内容
function timeout() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error('图片请求超时'));
}, 3000);
})
}
//3.实现超时操作
Promise.race([requestImg(
'https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=3252521864,872614242&fm=26&gp=0.jpg'), timeout()])
.then(val => {
console.log(val);
document.body.appendChild(val);
}).catch(err => {
console.log(err);
})
6.done() finally()
无论加载状态成功还是失败都会运行
async
then()执行await语句 catch()执行throw语句
//作用:使异步操作更加方便
//基本操作 async它会返回一个Promise对象 then catch
//asynv是Generator的一个语法糖
async function f() {
//return await ('hello async');
let a = await 'hello async';
let data = await a.split('');
return data;
}
//如果async函数中有多个await,那么then函数会等待所有的await指令运行完的结果才会执行
f().then((val) => {
console.log(val); //(11) ["h", "e", "l", "l", "o", " ", "a", "s", "y", "n", "c"]
}).catch(e => {
console.log(e);
})
如果一旦运行了 await rejected 后面就不会再继续运行了
async function f2() {
throw new Error('出错了');
}
f2().then(v => console.log(v)).catch(e => console.log(e));
//Error: 出错了
async function f3() {
try {
await Promise.reject('出错了');
} catch (error) {
}
return await Promise.resolve('hello');
}
f3().then(v => console.log(v)).catch(e => console.log(e));
//hello
Class类
//es6 造类(构造函数)
class Person {
//实例化的时候会立即被调用
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
return this.name
}
sayAge() {
return this.age
}
}
// 通过Object.assign()方法一次性向类中添加多个方法
Object.assign(Person.prototype,{
sayName() {
return this.name
},
sayAge() {
return this.age
}
})
let p1 = new Person('qaq', 20);
console.log(p1); //Person {age: 20 name: "qaq"}
console.log(p1.sayName()); //qaq
class语法
参考文章:cloud.tencent.com/developer/a… (写得非常详尽,强力安利!)
1. constructor
当我们用class定义了一个类,然后用关键字new调用该类,则会自动调用该类中的 constructor函数,最后生成一个实例对象。constructor函数内部的 this 指向的也是新生成的实例对象。
如果要生成一个不需要任何属性的实例对象,则我们不需要在 constructor函数里写任何代码,此时可以省略它,如果没有写constructor,则会自动生成一个空的constructor函数。也正是因为 constructor函数的存在,class 定义的类必须通过 new 来创建实例对象,否则就会报错.
而传统的构造函数就可以不通过new来调用,因为其本身就是一个函数,若不加关键字 new,则相当于直接执行该函数
1. class上的方法为不可枚举属性
用Aniaml.prototype.test = function(){}; 可以用object.keys(Animal.prototype)遍历到,因为是可枚举属性。如果在class Animal{ test()=function(){} }; 则用object.keys(Animal.prototype)遍历不到,是因为class定义的方法为不可枚举属性。可以用Object.getOwnPropertyNames(Animal.prototype)可以获取到。
2. static
在 class类中的方法都是写在原型上的,因此生成的实例对象可以直接调用。现在有一个关键字 static,若写在方法的前面,则表示此方法不会被写在原型上,而只作为该类的一个方法,这样的方法叫做静态方法;相反,若没加关键字 static 的方法就叫做非静态方法
class Person {
show() {
console.log('我是非静态方法show')
}
static show() {
console.log('我是静态方法show')
}
static hide() {
console.log('我是静态方法hide')
}
}
Person.show() // 我是静态方法show
var person = new Person()
person.show() // 我是非静态方法show
person.hide() /* person.hide()
^
TypeError: person.hide is not a function
*/
除了静态方法还有静态属性
static test = 'test';
如何访问静态属性,在静态方法中用this.test 就能获取到(根据下一条知识点 3. this指向的原理)
3. this指向
class中static方法里的this指向class本身,原型上的方法this指向实例对象
extends(类的继承)
//class类的继承 extends
class Animal {
constructor(name, age) {
this.name = name;
this.age = age;
}
sayName() {
return this.name;
}
sayAge() {
return this.age;
}
}
//写个Dog类 继承Animal
class Dog extends Animal {
constructor(name, age, color) {
super(name, age); //super会调用父类函数
this.color = color;
}
//重写父类的方法
sayName() {
return this.name + '年龄是' + super.sayAge() + '岁'
}
}
let d1 = new Dog('小黄', 5, '黄色');
console.log(d1); //Dog {name: "小黄", age: 5, color: "黄色"}
console.log(d1.sayName());小黄年龄是5岁
class的继承
1. super
在ES6中规定了,在子类继承了父类以后,必须先在子类的 constructor函数中调用 super函数,其表示的就是父级的 constructor函数,作用就是为子类生成 this对象,将父类的属性和方法赋值到子类的 this上。因此,若没有调用 super函数,则子类无法获取到 this对象,紧接着就会报错.
一: super指向
super()代表的是父类的构造函数,其实 super还可以作为对象使用,即不作为函数调用。当 super在子类的普通方法内时,指向的是父类的原型对象;在子类的静态方法内时,指向的是父类
class A{
show1() {
console.log('我是A类的show1方法')
}
}
class B extends A{
constructor() {
super()
}
show2() {
super.show1()
}
}
var b = new B()
b.show2() // 我是A类的show1方法
上述代码,B类继承 A类,其中 A类有一个 show1方法,是写在其原型 A.prototype上的,而在 B类的 show2方法中调用了 super.show1(),我们说过 super在普通的方法中指向的是父类的原型对象,所以 super.show1() 相当于 A.prototype.show1()
二:super在子类静态方法的指向
我们再来看一个super在子类的静态方法中的例子
class A{
static hide1() {
console.log('我是A类的hide1方法')
}
}
class B extends A{
constructor() {
super()
}
static hide2() {
super.hide1()
}
}
B.hide2() // 我是A类的hide1方法
上述代码,B类继承 A类,B类在其静态方法 hide2中调用了 super.hide1(),因为 super在静态方法中指向的是父类,所以super.hide1()就相当于 A.hide1()
三:子类普通方法中用super调用了父类的方法,this指向
还需要注意的是,当我们在子类的普通方法中通过 super调用父类的方法时,方法中的 this指向的是当前子类的实例对象
class A {
constructor() {
this.name = 'Jack'
}
show1() {
console.log(this.name)
}
}
class B extends A{
constructor() {
super();
this.name = 'Lpyexplore'
}
show2() {
super.show1()
}
}
var b = new B()
b.show2() // Lpyexplore
四:子类静态方法中用super调用父类方法,this指向
那么,当我们在子类的静态方法中通过super调用父类的方法时,方法中的 this指向的是子类,而不是子类的实例对象
class A {
constructor() {
this.x = 1
}
static show1() {
console.log(this.x)
}
}
class B extends A{
constructor() {
super();
this.x = 2
}
static show2() {
super.show1()
}
}
B.show2() // undefined
B.x = 3
B.show2() // 3
ES6模块化
- es6模块功能主要由两个命令构成: export、import
- export用于规定模块的对外接口 import用于输入其它模块提供的功能
- 一个模块就是一个独立的文件
例子:先创建一个JS文件
export const name = '张三';
export const age = 24;
export function sayName() {
return 'my name';
}
const obj = {
foo: 'foo'
}
export default obj;
dafault指的是默认值 所有变量都要经过export对外抛出(除了default)每个文件只有一个default
接下来是html文件
<script type="module">
// //es6 module
import obj,{name,age,sayName} from './modules/index.js'
//obj指的是默认值 每个js文件只能抛出一个默认值default
//等同于下一句
//import * as f from './modules/index.js'
console.log(obj);//{foo: "foo"}
console.log(name,age,sayName());//张三 24 my name
引用的格式: import 默认值(可无),{需要引用的值} from '需要引用的文件路径'
ES6模块与CommonJS模块有什么区别?
1、ES6 Module和CommonJS模块的区别:
CommonJS 是对模块的浅拷贝,ES6 Module 是对模块的引用,即ES6 Module只存只读,不能改变其值,具体点就是指针指向不能变,类似 const import 的接口是 read-only(只读状态),不能修改其变量值。 即不能修改其变量的指针指向,但可以改变变量内部指针指向,可以对 commonJS 对重新赋值(改变指针指向),但是对 ES6 Module 赋值会编译报错。
2、ES6 Module和CommonJS模块的共同点:
CommonJS和ES6 Module都可以对引入的对象进行赋值,即对对象内部属性的值进行改变。
3、 COMMONJS和ES6的区别
它们有两个重大差异:
CommonJS 模块输出的是一个值的拷贝,ES6 模块输出的是值的引用。
CommonJS 模块是运行时加载,ES6 模块是编译时输出接口。