# Modern JavaScript
# 变量声明
# const 和 let
不要用 var
,而是用 const
和 let
,分别表示常量和变量。不同于 var
的函数作用域,const
和 let
都是块级作用域。
const DELAY = 1000;
let count = 0;
count = count + 1;
2
3
4
# Arrow Functions 箭头函数
- 不需要通过 function 关键字创建函数,并且还可以省略 return 关键字。
- 箭头函数还会继承当前上下文的 this 关键字
// JavaScript ES5 function
function getGreeting() {
return "Welcome to JavaScript";
}
// JavaScript ES6 arrow function with body
const getGreeting = () => {
return "Welcome to JavaScript";
};
// JavaScript ES6 arrow function without body and implicit return
const getGreeting = () => "Welcome to JavaScript";
2
3
4
5
6
7
8
9
10
# Classes 类
# 类声明
在 ES6 中,我们将原型的实现写在了类中,但本质上还是一样的,都是需要新建一个类名,然后实现构造函数,再实现原型方法。
class Developer {
constructor(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
getName() {
return this.firstname + " " + this.lastname;
}
}
var me = new Developer("Robin", "Wieruch");
console.log(me.getName());
2
3
4
5
6
7
8
9
10
11
12
# extends 继承
class Developer {
constructor(firstname, lastname) {
this.firstname = firstname;
this.lastname = lastname;
}
getName() {
return this.firstname + " " + this.lastname;
}
}
class ReactDeveloper extends Developer {
getJob() {
return "React Developer";
}
}
var me = new ReactDeveloper("Robin", "Wieruch");
console.log(me.getName());
console.log(me.getJob());
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 实例属性新写法
可以定义在类的最顶层
class IncreasingCounter {
_count = 0;
get value() {
console.log("Getting the current value!");
return this._count;
}
increment() {
this._count++;
}
}
2
3
4
5
6
7
8
9
10
11
12
# 静态属性和方法
静态属性指的是 Class 本身的属性,即 Class.propName,而不是定义在实例对象(this)上的属性。
如果在一个方法前,加上 static 关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Foo {
static classMethod() {
return "hello";
}
}
Foo.prop = 1;
Foo.prop; // 1
Foo.classMethod(); // 'hello'
var foo = new Foo();
foo.classMethod(); // TypeError: foo.classMethod is not a function
2
3
4
5
6
7
8
9
10
11
12
13
14
# Template Literals 模板字符串
模板字符串提供了另一种做字符串组合的方法。
const user = "world";
console.log(`hello ${user}`); // hello world
// 多行
const content = `
Hello ${firstName},
Thanks for ordering ${qty} tickets to ${event}.
`;
2
3
4
5
6
7
8
# Import 和 Export
import
用于引入模块,export
用于导出模块。
比如:
// 引入全部
import React from 'react';
// 引入部分
import { connect } from 'dva';
import { Link, Route } from 'dva/router';
// 引入全部并作为 github 对象
import * as github from './services/github';
// 导出默认
export default App;
// 部分导出,需 import { App } from './file'; 引入
export class App extend Component {};
2
3
4
5
6
7
8
9
10
11
12
13
14
# Destructuring 析构赋值
析构赋值让我们从 Object 或 Array 里取部分数据存为变量。
const state = { counter: 1, list: ["a", "b"] };
// no object destructuring
const list = state.list;
const counter = state.counter;
// object destructuring
const { list, counter } = state;
2
3
4
5
6
数组析构
const list = ["a", "b"];
// no array destructuring
const itemOne = list[0];
const itemTwo = list[1];
// array destructuring
const [itemOne, itemTwo] = list;
2
3
4
5
6
我们也可以析构传入的函数参数。
// no destructuring
function Greeting(props) {
return <h1>{props.greeting}</h1>;
}
// destructuring
function Greeting({ greeting }) {
return <h1>{greeting}</h1>;
}
2
3
4
5
6
7
8
析构时还可以配 alias,让代码更具有语义。
const add = (state, { payload: todo }) => {
return state.concat(todo);
};
2
3
# Spread Operator 展开语法
Spread Operator 即 3 个点 ...
,有几种不同的使用方法。
可用于组装数组。
const todos = ["Learn dva"];
[...todos, "Learn antd"]; // ['Learn dva', 'Learn antd']
2
也可用于获取数组的部分项。
const arr = ["a", "b", "c"];
const [first, ...rest] = arr;
rest; // ['b', 'c']
// With ignore
const [first, , ...rest] = arr;
rest; // ['c']
2
3
4
5
6
7
还可收集函数参数为数组。
function directions(first, ...rest) {
console.log(rest);
}
directions("a", "b", "c"); // ['b', 'c'];
2
3
4
代替 apply。
function foo(x, y, z) {}
const args = [1, 2, 3];
// 下面两句效果相同
foo.apply(null, args);
foo(...args);
2
3
4
5
6
对于 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 }
2
3
4
5
6
7
8
9
10
11
# Promises
Promise 用于更优雅地处理异步请求。比如发起异步请求:
fetch("/api/todos")
.then((res) => res.json())
.then((data) => ({ data }))
.catch((err) => ({ err }));
2
3
4
定义 Promise 。
const delay = (timeout) => {
return new Promise((resolve) => {
setTimeout(resolve, timeout);
});
};
delay(1000).then((_) => {
console.log("executed");
});
2
3
4
5
6
7
8
9
# Async 和 Await
通过 async 函数,可以使得异步操作变得更加方便。返回值是个 Promise
async function fetch() {
await fetchData();
return "done";
}
2
3
4
async function logInOrder(urls) {
// 并发读取远程URL
const textPromises = urls.map(async (url) => {
const response = await fetch(url);
return response.text();
});
// 按次序输出
for (const textPromise of textPromises) {
console.log(await textPromise);
}
}
2
3
4
5
6
7
8
9
10
11
12
# Decorator 装饰器
装饰器(Decorator)是一种函数,用来注释或修改类和类方法,写成@ + 函数名。它可以放在类和类方法的定义前面。
修改类
class MyReactComponent extends React.Component {}
export default connect(mapStateToProps, mapDispatchToProps)(MyReactComponent);
// 使用装饰器
@connect(mapStateToProps, mapDispatchToProps)
export default class MyReactComponent extends React.Component {}
2
3
4
5
6
7
# Set, Map, WeakSet, WeakMap
# Set
Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
let mySet = new Set();
mySet.add(1); // Set [ 1 ]
mySet.add(5); // Set [ 1, 5 ]
mySet.add(5); // Set [ 1, 5 ]
mySet.add("some text"); // Set [ 1, 5, "some text" ]
let o = { a: 1, b: 2 };
mySet.add(o);
mySet.add({ a: 1, b: 2 }); // o 指向的是不同的对象,所以没问题
mySet.has(1); // true
mySet.has(3); // false
mySet.has(5); // true
mySet.has(Math.sqrt(25)); // true
mySet.has("Some Text".toLowerCase()); // true
mySet.has(o); // true
mySet.size; // 5
mySet.delete(5); // true, 从set中移除5
mySet.has(5); // false, 5已经被移除
mySet.size; // 4, 刚刚移除一个值
console.log(mySet); // Set {1, "some text", Object {a: 1, b: 2}, Object {a: 1, b: 2}}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# WeakSet
存储的值只能是对象。
# Map
Map 对象保存键值对,并且能够记住键的原始插入顺序。任何值(对象或者原始值) 都可以作为一个键或一个值。
Map 可以保持 key 的类型。
let myMap = new Map();
let keyObj = {};
let keyFunc = function() {};
let keyString = "a string";
// 添加键
myMap.set(keyString, "和键'a string'关联的值");
myMap.set(keyObj, "和键keyObj关联的值");
myMap.set(keyFunc, "和键keyFunc关联的值");
myMap.size; // 3
// 读取值
myMap.get(keyString); // "和键'a string'关联的值"
myMap.get(keyObj); // "和键keyObj关联的值"
myMap.get(keyFunc); // "和键keyFunc关联的值"
myMap.get("a string"); // "和键'a string'关联的值"
// 因为keyString === 'a string'
myMap.get({}); // undefined, 因为keyObj !== {}
myMap.get(function() {}); // undefined, 因为keyFunc !== function () {}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22