浅谈ECMAScript 6.0(二)

1.class

(1)类的基本定义

  • es5中想要创建某种类型的实例对象时,通过构造函数new出来,想要添加某种方法,则添加在其原型上。但是在es6中,我们使用类来实现上述需求。
  • ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
  • 类的本质是一个函数

类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法

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>
// 1 构造函数new实例对象的方法
// function Point(x,y){
// this.x=x;
// this.y=y;
// }
// Point.prototype.fn=function(){
// return '('+this.x+','+this.y+')'
// }
// var p=new Point(1,2);

// 2 创建类
// 类其实就是 构造函数+原型 的一种简化语法
class Point{
constructor(x,y){
// 该方法定义了实例对象上的属性和方法
this.x=x;
this.y=y;
}
fn(){
// 定义了原型上的方法
console.log('('+this.x+','+this.y+')');
}
}
// 通过类创建实例对象
var p1=new Point(1,3)
console.log(p1);
// 类的本质是一个函数
console.log(typeof Point);//function
console.log(Point.prototype.constructor==Point);//true
</script>
  • 类相当于实例的原型,所有在类中定义的方法,都会被实例继承
  • 如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 class Hobby{
constructor(name,age){
this.name=name;
this.age=age;
}
eat(){
console.log('eat');
}
play(){
console.log('play');
}
static run(){
console.log('run');
}
}
var h1=new Hobby('nancy',22);
var h2=new Hobby('snow',23)
console.log(Hobby);
1
console.log(Hobby.prototype);//可见run添加在了constructor中

(2)类的继承

所谓继承就是让 子类 具备 父类 的属性和方法。可以通过extends关键字实现继承。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Drink extends Hobby {
constructor(name, age, sex) {
// 执行super方法实现了子类实例对父类属性和方法的继承
super();
this.name = name;
this.age = age;
this.sex = sex;
}
play(){
console.log('爱好play');
}
}
var d1=new Drink('小敏',18,'女')
console.log(d1);//父级的属性季继承在子类的原型的实例对象上

2.proxy

Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
 // proxy可以帮助我们代理目标对象中所有属性的读写行为
var film = {
title: '这世界有那么多人',
price: 58
}
//语法格式: Proxy(目标对象,配置对象)
var pr = new Proxy(film, {
// get函数有两个参数;目标对象,读取的属性名
get(target, attr) {
return target[attr]
},
// set方法用来拦截某个属性的赋值操作,
//可以接受四个参数,依次为目标对象、属性名、属性值和 Proxy 实例本身,其中最后一个参数可选。
set() {
target[attr] = val;
}
})
// 使用时应该操作(由目标对象)生成的代理器对象
// 读取目标对象的属性的时候,在前面加一个get拦截
console.log(pr.title);//触发代理器的get方法
pr.title = '阿凡达'
console.log(film);

3.symbol

  • Symbol 值通过Symbol()函数生成。
1
2
3
// 凡是属性名属于 Symbol 类型,就都是独一无二的,可以保证不会与其他属性名产生冲突。
let a=Symbol();
console.log(typeof a);//symbol

symbol是一种类似于字符串的数据类型。

  • Symbol()函数的参数只是表示对当前 Symbol 值的描述
1
2
3
4
// 相同参数的symbol函数的返回值是不同的
let s1=symbol('foo');
let s2=symbol('foo');
console.log(s1===s2);///false
  • Symbol 值不能与其他类型的值进行运算,会报错。
  • Symbol可以显示转换为字符串和布尔值,不可以转换为数值

4.promise

Promise是异步编程的一种解决方案。Promise,简单说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上说,Promise 是一个对象,从它可以获取异步操作的消息。Promise 提供统一的 API,各种异步操作都可以用同样的方法进行处理。

总之,promise是一种包含异步任务的对象。(一般比回调函数更加合理和强大)

  • promise的特点:

(1)对象的状态不受外界影响。只有异步操作的结果可以决定当前是哪种状态

(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果。只有两种状态改变:从pending变为fulfilled和从pending变为rejected。

  • promise的缺点:

一旦新建它就会立即执行,无法中途取消。其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。第三,当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。

  • promise创建实例对象

调用then方法可以指定成功或者失败时要做的事情

Promise.prototype.catch()方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
let a = new Promise(function (resolve, reject) {
// 函数有两个参数resolve和reject,函数内封装一个异步的操作
setTimeout(function () {
let data = '用户数据';
// 1 调用resolve函数之后promise对象的状态就会变为成功
// resolve(data);
// 2 调用reject参数数据状态变为失败,调用then方法的第二个函数
let err = '数据读取失败';
reject(err);
}, 1000)
});
// 调用then方法,接收两个参数,都是函数
// 第一个函数代表成功时执行的函数,第二个函数是失败时执行的
// 成功的参数一般是value,失败的参数一般是reason
a.then(value=>{
console.log(value);
}.catch(reason=> {
console.log(reason);
})
  • promise封装ajax请求
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
let p = new Promise((resolve, reject) => {
// 创建对象
let xhr = new XMLHttpRequest();
xhr.open("get", "https://api.apiopen.top/getJoke");
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
// 状态码在200-300之间表示成功
// 成功时调用promise的resolve函数
resolve(xhr.response);
} else {
reject(xhr.status);
}
}
}
})
p.then(function (value) {
console.log('成功了', value);
}, function (reason) {
console.log('失败了', reason);
})

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
function request(params) {
let { type, url, data } = params;
return new Promise((resolve, reject) => {
// 异步ajax请求
$.ajax({
type,
url,
data,
success(res) {
resolve(res);
},
error(err) {
reject(err);
}
})
})

};
// request是一个封装好的请求方法,可以以promise的形式使用
// 调request得到的是一个promise对象
request({
type: 'get',
url: '112dsdf',
data: {
start: 1,
limit: 10
}
}).then(
res => {
console.log(res);
}
).catch(err => {
console.log(err);
})

5.async与await

async/await 是ES2017(ES8)提出的基于Promise的解决异步的最终方案。

async函数返回一个 Promise对象,语义上理解:当函数前面加上 async 表示函数内部有异步操作。

1
2
3
4
5
6
7
async function main(){ // 声明一个异步函数
return 1 // return的结果 相当于resolve出去的结果
// 会成为then方法回调函数的参数。
}
console.log(main()) // Promise {<resolved>: 1}
// 获取async返回的结果通过.then获取
main().then(res => console.log(res)); // 1

await只能在async中使用

特点:

  • await 关键字要在 async 关键字函数的内部,await 写在外面会报错。
  • 正常情况下,await命令后面是一个 Promise 对象,返回该对象的结果。
  • await右侧如果是函数,那么函数的return值就是「表达式的结果」
  • await右侧如果是一个 ‘hello’ 或者什么值,那表达式的结果就是 ‘hello’
  • await关键字会阻塞后面代码的运行(通过阻塞特点 控制ajax 或者settimeout的执行顺序)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//在 async函数 中, 使用await, 会等待表达式或者当前异步操作有了结果之后, 再去执行后边的语句
async function async1() {
console.log( 'async1 start' )
await async2() // 使用await关键字之后 await下面的代码会被阻塞 也就是说会先跳出当前的async1函数
// 等async2有了结果之后 ,下面代码才会执行。
console.log('async1 end');
}

async function async2() {
console.log( 'async2' )
}

async1();

console.log( 'script start' );

// 打印结果会是
// async1 start
// async2
// script start
// async1 end