ES6的…展开运算符

1
2
3
4
5
6
7
let a = [1,2,3];
let b = [0, ...a, 4]; // [0,1,2,3,4]
 
let obj = { a: 1, b: 2 };
let obj2 = { ...obj, c: 3 }; // { a:1, b:2, c:3 }
let obj3 = { ...obj, a: 3 }; // { a:3, b:2 }
let obj4 = {a:3,...obj}; // { a:1, b:2 }

mapState

store.js

1
2
3
4
5
6
7
8
9
const state = {
  activeFirstMenu: 'overView',
  loginUser: {
    userName: '',
    deptName: '',
    logined: false,
    loginTime: new Date()
  }
}

未使用mapState

 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
export default {
  name: 'HeadMenu',
  props: {
    direction: {
      type: [String],
      default: 'left'
    },
    menuKey: {
      type: [String],
      required: true
    }
  },
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  computed: {
    ifFocus () {
      return this.$store.state.activeFirstMenu === this.menuKey
    }
    
  },
  methods: {}
}

使用了mapState后

 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
import { mapState } from 'vuex'
export default {
  name: 'HeadMenu',
  props: {
    direction: {
      type: [String],
      default: 'left'
    },
    menuKey: {
      type: [String],
      required: true
    }
  },
  data () {
    return {
      msg: 'Welcome to Your Vue.js App'
    }
  },
  computed: {
    ifFocus () {
      console.log(this.activeFirstMenu)
      return this.activeFirstMenu === this.menuKey
    },
    ...mapState(['activeFirstMenu'])
    
  },
  methods: {}
}

批量赋值运算符

1
2
3
let obj = {a:1,b:2,c:3};
const {b} = obj;
console.log(b)

回调地狱与Promise

参见:廖雪峰的博客 https://www.liaoxuefeng.com/wiki/1022910821149312/1023024413276544

在JavaScript的世界中,所有代码都是单线程执行的。

由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现:

1
2
3
4
5
6
function callback() {
    console.log('Done');
}
console.log('before setTimeout()');
setTimeout(callback, 1000); // 1秒钟后调用callback函数
console.log('after setTimeout()');

观察上述代码执行,在Chrome的控制台输出可以看到:

before setTimeout()
after setTimeout()
(等待1秒后)
Done

可见,异步操作会在将来的某个时间点触发一个函数调用。

AJAX就是典型的异步操作。以上一节的代码为例:

1
2
3
4
5
6
7
8
9
request.onreadystatechange = function () {
    if (request.readyState === 4) {
        if (request.status === 200) {
            return success(request.responseText);
        } else {
            return fail(request.status);
        }
    }
}

把回调函数success(request.responseText)fail(request.status)写到一个AJAX操作里很正常,但是不好看,而且不利于代码复用。

有没有更好的写法?比如写成这样:

1
2
3
var ajax = ajaxGet('http://...');
ajax.ifSuccess(success)
    .ifFail(fail);

这种链式写法的好处在于,先统一执行AJAX逻辑,不关心如何处理结果,然后,根据结果是成功还是失败,在将来的某个时候调用success函数或fail函数。

古人云:“君子一诺千金”,这种“承诺将来会执行”的对象在JavaScript中称为Promise对象。

Promise有各种开源实现,在ES6中被统一规范,由浏览器直接支持。 我们先看一个最简单的Promise例子:生成一个0-2之间的随机数,如果小于1,则等待一段时间后返回成功,否则返回失败:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
function test(resolve, reject) {
    var timeOut = Math.random() * 2;
    log('set timeout to: ' + timeOut + ' seconds.');
    setTimeout(function () {
        if (timeOut < 1) {
            log('call resolve()...');
            resolve('200 OK');
        }
        else {
            log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}

这个test()函数有两个参数,这两个参数都是函数,如果执行成功,我们将调用resolve('200 OK'),如果执行失败,我们将调用reject('timeout in ' + timeOut + ' seconds.')。可以看出,test()函数只关心自身的逻辑,并不关心具体的resolvereject将如何处理结果。

有了执行函数,我们就可以用一个Promise对象来执行它,并在将来某个时刻获得成功或失败的结果:

1
2
3
4
5
6
7
var p1 = new Promise(test);
var p2 = p1.then(function (result) {
    console.log('成功:' + result);
});
var p3 = p2.catch(function (reason) {
    console.log('失败:' + reason);
});

变量p1是一个Promise对象,它负责执行test函数。由于test函数在内部是异步执行的,当test函数执行成功时,我们告诉Promise对象:

// 如果成功,执行这个函数:

1
2
3
p1.then(function (result) {
    console.log('成功:' + result);
});

当test函数执行失败时,我们告诉Promise对象:

1
2
3
p2.catch(function (reason) {
    console.log('失败:' + reason);
});

Promise对象可以串联起来,所以上述代码可以简化为:

1
2
3
4
5
new Promise(test).then(function (result) {
    console.log('成功:' + result);
}).catch(function (reason) {
    console.log('失败:' + reason);
});

综合测试:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
new Promise(function (resolve, reject) {
    console.log('start new Promise...');
    var timeOut = Math.random() * 2;
    console.log('set timeout to: ' + timeOut + ' seconds.');
    setTimeout(function () {
        if (timeOut < 1) {
            console.log('call resolve()...');
            resolve('200 OK');
        }
        else {
            console.log('call reject()...');
            reject('timeout in ' + timeOut + ' seconds.');
        }
    }, timeOut * 1000);
}).then(function (r) {
    console.log('Done: ' + r);
}).catch(function (reason) {
    console.log('Failed: ' + reason);
});

#ES6的模块化

参见:阮一峰的博客 https://es6.ruanyifeng.com/#docs/module

历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他语言都有这项功能,比如 Ruby 的require、Python 的import,甚至就连 CSS 都有@import,但是 JavaScript 任何这方面的支持都没有,这对开发大型的、复杂的项目形成了巨大障碍。

在 ES6 之前,社区制定了一些模块加载方案,最主要的有 CommonJS 和 AMD 两种。前者用于服务器,后者用于浏览器。ES6 在语言标准的层面上,实现了模块功能,而且实现得相当简单,完全可以取代 CommonJS 和 AMD 规范,成为浏览器和服务器通用的模块解决方案。