ES6, DvaJS 知识地图

237 阅读4分钟

JavaScript语言

变量声明

let 和 const

不要用 var, 而是用 constlet, 分别表示常量和变量。 不同于 var 的函数作用域,constlet 都是块级作用域。

const DELAY = 1000;

let count = 0;
count = count + 1;

模板字符串

模板字符串提供了另一种做字符串组合的方法。

const user = "world";
console.log(`hello${user}`); // hello world

// 多行
const content = `
  Hello ${user},
  greet guests.
`;

默认参数

function logActivity(activity = 'skiing') {
  console.log(activity);
}

logActivity();  // skiing

箭头函数

函数的快捷写法,不需要通过 function 关键字创建函数,并且还可以省略 return 关键字。

同时,箭头函数还会继承当前上下文的 this 关键字。

比如:

[1, 2, 3].map((x) => x + 1);  //[2, 3, 4]

等同于:

[1, 2, 3].map(function(x){
    return x + 1;
})  // [2, 3, 4]

[1, 2, 3].map((function(x) {
  return x + 1;
}).bind(this)); // [2, 3, 4]

[1, 2, 3].reduce(function(accumulator, currentValue){
  accumulator.push(currentValue + 1);
  return accumulator;
}, []);  // [2, 3, 4]

对于reduce函数不清楚的同学可以参考阮一峰老师的reduce讲解

模块的 Import 和 Export

import 用于引入模块,export 用于导出模块。

比如:

// 引入全部
import React from "react";

// 引入部分
import { useState } from "react";
import React, { useState, useEffect } from "react";

// 引入全部并作为 github对象
import * as github from './services/github';
import App from "./02_函数式组件的refs";

// 导出默认
export default App;
// 部分导出, 需 import { App } from './file; 引入
export class App extends React.Component {} ;

ES6 对象和数组

解构赋值

解构赋值可以让我们从 ObjectArray 里取部分数据存为变量。

// 对象
const user = { name: "kobe", age: 38 };
const { name, age } = user;
console.log(`${name}: ${age}`); // kobe: 38

// 数组
const arr = [1, 2];
const [foo, bar] = arr;
console.log(foo, bar); // 1 2

我们也可以解构传入的函数参数。

const add = (state, { payload }) => {
  console.log("payload", payload); //2 
  return state.concat(payload);
};
add([ 1 ], { payload : 2 })

解构时还可以配alias,让代码更具有语义。

const add = (state, { payload: todo }) => {
  console.log("todo", todo);   // todo 2
  return state.concat(todo);
};
add([1], { payload: 2 });
// 函数调用时,将从第二个实参中匹配模式为 payload 的属性,并重命名为 todo

字面量改进

这是解构的反向操作,用于重新组织一个 Object。

const name = "kobe";
const age = 38;
const user = { name, age }; // { name: 'kobe', age:38 }

定义对象方法时,还可以省去 function 关键字。

const example1 = new Vue({
  el: '#example-1',
  mounted(){
    this.$nextTick(function () {
      // Code that will run only after the
      // entire view has been rendered
    })
  },
  // 等同于
  // mounted: function () {}
})

app.model({
  reducers: {
    add() {}  // 等同于 add: function() {}
  },
  effects: {
    *addRemote() {}  // 等同于 addRemote: function*() {}
  },
});

Spread Operator 展开语法

Spread Operator 即3个点 ...,有几种不同的使用方法。

可用于组装数组。

const todos = [1, 2, 3];
[...todos, 'Learn English'];  // [1, 2, 3, 'Learn English']

也可用于获取数组的部分项。

const arr = ["a", "b", "c"];
const [first, ...rest] = arr;
console.log(rest); // [ 'b', 'c' ]

// With igore
const [first, , ...rest] = arr;
rest; // ['c']

还可以收集函数参数为数组

function directions(first, ...rest) {
  console.log(rest);
}
directions('a', 'b', 'c');  // ['b', 'c'];

代替 apply。

function foo(x, y, z) {}
const args = [1,2,3];

// 下面两句效果相同
foo.apply(null, args);
foo(...args);

对于 Object 而言,用于组合成新的 Object 。(ES2017 stage-2 proposal)

const foo = {
  a: 1,
  b: 2,
};
const bar = {
  b: 3,
  c: 2,
};
const d = 4;

const ret = { ...foo, ...bar, d };  // { a:1, b:3, c:2, d:4 }

此外,在 JSX 中 Spread Operator 还可用于扩展 props,详见 Spread Attributes

对象属性名表达式

JavaScript 定义对象的属性,有两种方法。

// 方法一
obj.foo = true;

// 方法二
obj['bar'] = 123;

上面代码的方法一是直接用标识符作为属性名,方法二是用表达式作为属性名,这时要将表达式放在方括号之内。

但是,如果使用字面量方式定义对象(使用大括号),在 ES5 中只能使用方法一(标识符)定义属性。

const obj = {
  foo: true,
  abc: 123
};

ES6 允许字面量定义对象时,用方法二(表达式)作为对象的属性名,即把表达式放在方括号内。

const propKey = "bar";
const obj = {
  foo: true,
  [propKey]: 123,
};
// obj :  { foo: true, bar: 123 }

在react里setState函数应用如下:

我们实现点击按钮给球星投票

<script type="text/babel">
  class App extends React.Component {
    constructor(props) {
      super(props);

      this.state = {
        jordan: 0,
        james: 0,
        kobe: 0,
      };
    }

    render() {
      const { jordan, james, kobe } = this.state;
      return (
        <div>
          <h2>球星列表</h2>
          <ul>
            <li>
              <h2>乔丹:{jordan} 票</h2>
            </li>
            <li>
              <h2>詹姆斯:{james} 票</h2>
            </li>
            <li>
              <h2>科比:{kobe} 票</h2>
            </li>
          </ul>
          <button onClick={this.increment.bind(this, "jordan")}>
            乔丹+1
          </button>
          <button onClick={this.increment.bind(this, "james")}>
            詹姆斯+1
          </button>
          <button onClick={this.increment.bind(this, "kobe")}>
            科比+1
          </button>
        </div>
      );
    }

    increment(startKey) {
      const { jordan, james, kobe } = this.state;
      const sourceMap = { jordan, james, kobe };

      this.setState({ [startKey]: sourceMap[startKey] + 1 });
    }
  }

  ReactDOM.render(<App />, document.getElementById("app"));
</script>

更多关于ES6对象的增强可以参考阮一峰老师ECMAScript 6 入门

Promises

Promise 用于更优雅的处理异步请求,比如发起异步请求:

fetch('/api/todos')
  .then(res => res.json())
  .then(data => ({ data }))
  .catch(err => ({ err }));

定义 Promise 。

const delay = (timeout) => {
  return new Promise((resolve) => {
    setTimeout(resolve, timeout);
  });
};

delay(1000).then((_) => {
  console.log("executed");
});

更多有关Promise的详细内容请参考阮一峰老师ES6中Promise

Generators

dva 的 effects 是通过 generator 组织的。Generator 返回的是迭代器,通过 yield 关键字实现暂停功能。

这是一个典型的 dva effect,通过 yield 把异步逻辑通过同步的方式组织起来。

app.model({
  namespace: 'todos',
  effects: {
    *addRemote({ payload: todo }, { put, call }) {
      yield call(addTodo, todo);
      yield put({ type: 'add', payload: todo });
    },
  },
});
// 先发异步请求addTodo,等到响应之后再调用reducer更新state