Yang's Blog

拥抱ES2015(ES6)

介绍ES2015(ES6,即ECMAScript 6)

ES6(下面就用ES6来写) 是新版的 JavaScript,Node.js 已经完全支持

运行本文示例代码,可以直接在Chrome浏览器(谷歌浏览器)运行

使用 letconst

ES6 可以用 constlet 替换 var ,它们定义了块级作用域变量。

示例代码:

1
2
3
4
for(let i = 0; i < 5; i++){
var val = i;
}
console.log(val) // 4

1
2
3
4
for(let i = 0; i < 5; i++){
let val = i;
}
console.log(val) // 报错: val is not defined

是不是发现变量 val 在用 var 定义的时候可以打印,而用 let 定义的时候却不能。
用 let 定义的时候变量 val 只能在 for 循环中使用。

constlet 很像,但是它定义的变量值无法改变。

示例代码:

1
2
3
const user = {name: "Arunoda"};
user.name = "Susiripala";
console.log(user.name); // Susiripala

改变的是变量 user 内部的属性,并没有改变 user 本身。

许多人更喜欢用 const 代替 let

使用箭头函数整理你的代码

熟悉的方式:

1
2
3
4
5
const numbers = [10, 20, 30, 50];
const multiplyBy10 = numbers.map(function(a) {
return a * 10;
});
console.log(multiplyBy10); // [100, 200, 300, 500]

使用箭头函数以后:

1
2
3
const numbers = [10, 20, 30, 50];
const multiplyBy10 = numbers.map(a => a * 10);
console.log(multiplyBy10); // [100, 200, 300, 500]

如果方法接受不止1个参数,可以这么写:

1
2
3
const numbers = [10, 20, 30, 50];
const multiplyByIndex = numbers.map((a, i) => a * i);
console.log(multiplyByIndex);

箭头函数返回一个对象的话,需要加圆括号:

1
2
3
const numbers = [10, 20, 30, 50];
const multiplyBy10 = numbers.map(a => ({res: a * 10}));
console.log(multiplyBy10);

不再使用“self=this”
以前的代码:

1
2
3
4
5
6
7
8
9
function Clock() {
this.currentTime = new Date();
}
Clock.prototype.start = function() {
var self = this;
setInterval(function() {
self.currentTime = new Date();
}, 1000);
}

可以用箭头函数代替 self=this

1
2
3
4
5
6
7
8
function Clock() {
this.currentTime = new Date();
}
Clock.prototype.start = function() {
setInterval(() => {
this.currentTime = new Date();
}, 1000);
}

setInterval 里面用了箭头函数,它携带了 start 方法的上下文(this)。

使用箭头函数要多加小心,并不是随处可用的,箭头函数会携带函数定义时的上下文。

改良的对象字面量

在对象里面定义一个方法,可以这么写:

1
2
3
4
5
6
const user = {
getName() {
return 'Arunoda';
}
}
console.log(user.getName());

不必每次都写 function 关键字。

这是最酷的特性,你会喜欢的:

1
2
3
const name = 'Arunoda';
const age = 80;
const user = {name, age};

瞅瞅多简单,并不用这么啰嗦:

1
2
3
4
5
6
const name = 'Arunoda';
const age = 80;
const user = {
name: name,
age: age
};

解构对象
很容易地提取 user 对象的 name 和 age 字段:

1
2
3
4
5
6
7
const user = {
name: 'Arunoda',
age: 80,
city: 'Colombo'
};
const {name, age} = user;
console.log(name, age);

对于函数相当有用,上代码:

1
2
3
4
5
6
7
8
9
function printName({name}) {
console.log('Name is: ' + name);
}
const user = {
name: 'Arunoda',
age: 80,
city: 'Colombo'
};
printName(user);

不仅简化了代码,而且可以自描述。看到函数第一行时,我们便会明白使用传入对象的哪个字段。

可以定义传入对象的默认值。

1
2
3
function printUser({name, age = 20}) {
console.log('Name is: ' + name + ' Age: ' + age);
}

像传入对象一样,同样可以从传入的数组中解构值:

1
2
3
4
function printUser([name, age = 20]) {
console.log('Name is: ' + name + ' Age: ' + age);
}
printUser(["Arunoda", 80]);

前所未见的方式传递(spread)数组
以前的代码:

1
2
3
4
5
6
7
8
9
function sum(a, b) {
return a + b;
}
function sumAndLog(a, b) {
var result = sum(a, b);
console.log('Result is: ' + result);
return result;
}
sumAndLog(10, 20);

ES6 代码:

1
2
3
4
5
6
7
8
9
function sum(a, b) {
return a + b;
}
function sumAndLog(...args) {
const result = sum(...args);
console.log('Result is: ' + result);
return result;
}
sumAndLog(10, 20);

在 sumAndLog 方法中使用 spread 操作符(…),可以很简单地把所有参数存入 args 变量,然后再用 spread 操作符把 args 传入 sum 方法。

再看以下例子:

1
2
3
4
5
function printTeam(leader, ...others) {
console.log('Leader: ' + leader + ' - Others: ' + others);
}
printTeam('Arunoda', 'John', 'Singh');
//输出结果:"Leader: Arunoda - Others: John,Singh"

克隆、合并对象
以往都是用 underscore 或者 lodash,克隆、合并对象:

1
2
3
4
5
var user = {name: "Arunoda"};
var newUser = _.clone(user);
var withAge = _.extend(user, {age: 20});
var newUserVersion = _.defaults({age: 80}, user);
console.log(newUser, withAge, newUserVersion);

ES6 不需要任何工具库,轻松实现以上功能。

1
2
3
4
5
const user = {name: "Arunoda"};
const newUser = {...user};
const withAge = {...user, age: 20};
const newUserVersion = {age: 80, ...user};
console.log(newUser, withAge, newUserVersion);

看以下例子:

1
2
3
4
5
6
7
8
const user = {
name: 'Arunoda',
emails: ['hello@arunoda.io']
};
const newUser = {...user};
newUser.emails.push('mail@arunoda.io');
console.log(user.emails);
//输出结果:["hello@arunoda.io", "mail@arunoda.io"]

尽管我们克隆了对象,但不是深度克隆,只克隆了顶层字段,emails 数组字段使用的仍是同一个。

往数组里添加元素

跟对象类似,我们同样可以克隆数组:

1
2
3
4
const marks = [10, 20, 30];
const newMarks = [...marks, 40];
console.log(marks, newMarks);
JavaScript 不变性(Immutability)

这些日子,JavaScript 也兴起函数式编程的概念。因此,我们可以尝试写写纯函数。

纯函数:一个函数接收一些值,并且返回一些值,但是通过参数接收到的值不会被改变。 同样的输入总是返回同样的值。
random() 就不是一个纯函数,任何可以修改全局状态的函数都不能称之为纯。

用 spread 操作符可以轻松实现。

用于对象:

1
2
3
4
5
6
7
8
9
function addMarks(user, marks) {
return {
...user,
marks
};
}
const user = {username: 'arunoda'};
const userWithMarks = addMarks(user, 80);
console.log(user, userWithMarks);

用于数组:

1
2
3
4
5
6
7
8
9
10
11
function addUser(users, username) {
const user = {username};
return [
...users,
user
];
}
const user = {username: 'arunoda'};
const users = [user];
const newUsers = addUser(users, 'john');
console.log(users, newUsers);

多行字符串

既然支持模板字符串,多行字符串也不在话下:

1
2
3
4
5
6
const message = `
# Title
This is a multi line string as markdown.
It's pretty nice.
`;
console.log(message);

没有模板字符串的话,是这个样子的:

1
2
var message = "\n # Title\n\n This is a multi line string as markdown.\n It's pretty nice.\n";
console.log(message);

像 Java 一样写 Class

JavaScript 并不是真正的面向对象语言,但是可以用函数和原型模拟类。ES2015 可以写真正原生的类了。

1
2
3
4
5
6
7
8
9
10
11
class Vehicle {
constructor(type, number) {
this.type = type;
this.number = number;
}
display() {
return `Number: ${this.number}`;
}
}
const v1 = new Vehicle('Car', 'GH-2343');
console.log(v1.display());

继承一个类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Vehicle {
constructor(type, number) {
this.type = type;
this.number = number;
}
display() {
return `Number: ${this.number}`;
}
}
class Car extends Vehicle {
constructor(number) {
super('Car', number);
}
display() {
const value = super.display();
return `Car ${value}`;
}
}
const v1 = new Car('GH-2343');
console.log(v1.display());

小汽车继承了车辆:

在 Car constructor 内部调用了 super constructor (Vehicle 的 constructor)。
Car 的 display() 方法内部,调用了 super.display() 。这里展示了子类如何继承方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Vehicle {
constructor(type, number) {
this.type = type;
this.number = number;
}
display() {
return `Number: ${this.number}`;
}
}
class Car extends Vehicle {
display() {
const value = super.display();
return `Car ${value}`;
}
}
const v1 = new Car('GH-2343');
console.log(v1.display());

Car 类没有实现 constructor 的话,它会用 Vehicle 的 constructor 。

Enjoy it ? Donate me ! 欣赏此文?求鼓励,求支持!