声明变量的新姿势
用let不用var
ES6之前我们用var声明一个变量,但是它有很多弊病:
- 因为没有块级作用域,很容易声明全局变量
- 变量提升
- 可以重复声明还记得这道面试题吗?
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i);
};
}
a[6](); // 10
a[7](); // 10
a[8](); // 10
a[9](); // 10
所以,你现在还有什么理由不用let?
有时候const比let更好
const和let的唯一区别就是,const不可以被更改,所以当声明变量的时候,尤其是在声明容易被更改的全局变量的时候,尽量使用const。
- 更好的代码语义化,一眼看到就是常量。
- 另一个原因是因为JavaScript 编译器对const的优化要比let好,多使用const,有利于提高程序的运行效率。
- 所有的函数都应该设置为常量。
动态字符串
不要使用“双引号”,一律用单引号或反引号
// low
const a = "foobar";
const b = 'foo' + a + 'bar';
// best
const a = 'foobar';
const b = `foo${a}bar`;
const c = 'foobar';
解构赋值的骚操作
变量赋值
在用到数组成员对变量赋值时,尽量使用解构赋值。
const arr = [1, 2, 3, 4];
// low
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
函数传对象
函数的参数如果是对象的成员,优先使用解构赋值。
// low
function getFullName(user) {
const firstName = user.firstName;
const lastName = user.lastName;
}
// good
function getFullName({ firstName, lastName }) {
}
如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序。
// low
function processInput(input) {
return [left, right, top, bottom];
}
// good
function processInput(input) {
return { left, right, top, bottom };
}
const { left, right } = processInput(input);
关于对象的细节
逗号
单行定义的对象结尾不要逗号:
// low
const a = { k1: v1, k2: v2, };
// good
const a = { k1: v1, k2: v2 };
多行定义的对象要保留逗号:
// low
const b = {
k1: v1,
k2: v2
};
// good
const b = {
k1: v1,
k2: v2,
};
一次性初始化完全
不要声明之后又给对象添加新属性:
// low
const a = {};
a.x = 3;
// good
const a = { x: null };
a.x = 3;
如果一定非要加请使用Object.assign:
const a = {};
Object.assign(a, { x: 3 });
如果对象的属性名是动态的,可以在创造对象的时候,使用属性表达式定义:
// low
const obj = {
id: 5,
name: 'San Francisco',
};
obj[getKey('enabled')] = true;
// good
const obj = {
id: 5,
name: 'San Francisco',
[getKey('enabled')]: true,
};
再简洁一点
在定义对象时,能简洁表达尽量简洁表达:
var ref = 'some value';
// low
const atom = {
ref: ref,
value: 1,
addValue: function (value) {
return atom.value + value;
},
};
// good
const atom = {
ref,
value: 1,
addValue(value) {
return atom.value + value;
},
};
数组
...
使用扩展运算符(...)拷贝数组:
// 还在用for i 你就太low了
const len = items.length;
const itemsCopy = [];
let i;
for (i = 0; i < len; i++) {
itemsCopy[i] = items[i];
}
// cool !
const itemsCopy = [...items];
不要跟我提类数组
用 Array.from 方法,将类似数组的对象转为数组:
const foo = document.querySelectorAll('.foo');
const nodes = Array.from(foo);
函数
箭头函数=>
立即执行函数可以写成箭头函数的形式:
(() => {
console.log('Welcome to the Internet.');
})();
尽量写箭头函数使你的代码看起来简洁优雅:
// low
[1, 2, 3].map(function (x) {
return x * x;
});
// cool !
[1, 2, 3].map(x => x * x);
不要把布尔值直接传入函数
// low
function divide(a, b, option = false ) {
}
// good
function divide(a, b, { option = false } = {}) {
}
别再用arguments(类数组)了!
使用 rest 运算符(...)代替,rest 运算符可以提供一个真正的数组。
// low
function concatenateAll() {
const args = Array.prototype.slice.call(arguments);
return args.join('');
}
// good
function concatenateAll(...args) {
return args.join('');
}
传参时试试设置默认值?
// low
function handleThings(opts) {
opts = opts || {};
}
// good
function handleThings(opts = {}) {
// ...
}
Object?Map!
简单的键值对优先Map
如果只是简单的key: value结构,建议优先使用Map,因为Map提供方便的遍历机制。
let map = new Map(arr);
// 遍历key值
for (let key of map.keys()) {
console.log(key);
}
// 遍历value值
for (let value of map.values()) {
console.log(value);
}
// 遍历key和value值
for (let item of map.entries()) {
console.log(item[0], item[1]);
}
更加简洁直观class语法
// low
function Queue(contents = []) {
this._queue = [...contents];
}
Queue.prototype.pop = function() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
// good
class Queue {
constructor(contents = []) {
this._queue = [...contents];
}
pop() {
const value = this._queue[0];
this._queue.splice(0, 1);
return value;
}
}
模块化
引入模块
使用import取代require,因为Module是Javascript模块的标准写法。
// bad
const moduleA = require('moduleA');
const func1 = moduleA.func1;
const func2 = moduleA.func2;
// good
import { func1, func2 } from 'moduleA';
输出模块
使用export输出变量,拒绝module.exports:
import React from 'react';
class Breadcrumbs extends React.Component {
render() {
return <nav />;
}
};
export default Breadcrumbs;
- 输出单个值,使用
export default
- 输出多个值,使用
export
export default
与普通的export
不要同时使用
编码规范
- 模块输出一个函数,首字母应该小写:
function getData() {
}
export default getData;
- 模块输出一个对象,首字母应该大写
const Person = {
someCode: {
}
};
export default Person ;
虽然ES6的规范并不是特别地新,但我认为很多开发人员对其仍然不太熟悉。 主要原因在于Web浏览器的支持可能比较差。目前,该规范发布已经有两年多了,很多浏览器对ES6的支持还算不错。 即使不使用最新版本的Web浏览器,也可以在应用程序的构建过程中使用代码转译工具(如Babel)将ES6的源代码转换为ES5的源代码。 赶快提升自己,学习ES6吧。
本文尽可能简单地介绍了ES6中最有用的功能。 在阅读完本教程之后,你就可以把学到的这些基本技能应用到实际项目中去了。本文并不是指南或说明文档。本文的目标是鼓励读者深入研究并熟悉ES6。
让我们开始吧
1. const和let关键字
const用于定义常量。 let用于定义变量。但是JavaScript中不是已经有变量了吗? 是的,这很正确,但用var声明的变量具有函数作用域,并会被提升到顶部。 这意味着在声明之前就可以使用这个变量。 let变量和常量具有块作用域(用{}包围),在声明之前不能被使用。
function f() {
var x = 1
let y = 2
const z = 3
{
var x = 100
let y = 200
const z = 300
console.log('x in block scope is', x)
console.log('y in block scope is', y)
console.log('z in block scope is', z)
}
console.log('x outside of block scope is', x)
console.log('y outside of block scope is', y)
console.log('z outside of block scope is', z)
}
f()
x in block scope is 100
y in block scope is 200
z in block scope is 300
x outside of block scope is 100
y outside of block scope is 2
z outside of block scope is 3
2. 数组助手函数
非常酷的助手函数出现了。像这样的逻辑你实现了多少次了:过滤,检查是否有元素满足条件,然后进行元素转换。也许有无数次吧。现在,有一些非常强大的功能可以代替你做这些事情。在我看来,这些是最有价值的功能:
forEach
对数组的每个元素执行所提供的函数,将数组元素作为参数传递进入。
var colors = ['red', 'green', 'blue']
function print(val) {
console.log(val)
}
colors.forEach(print)
red
green
blue
map
创建一个包含相同数量元素的新数组,但是由提供的函数创建输出元素。它只是将数组中的每个元素做了转换。
var colors = ['red', 'green', 'blue']
function capitalize(val) {
return val.toUpperCase()
}
var capitalizedColors = colors.map(capitalize)
console.log(capitalizedColors)
["RED","GREEN","BLUE"]
- 1
filter
创建一个包含原始数组子集的新数组。新数组的元素则是那些通过了所提供函数测试的元素,测试函数应返回true或false。
var values = [1, 60, 34, 30, 20, 5]
function lessThan20(val) {
return val < 20
}
var valuesLessThan20 = values.filter(lessThan20)
console.log(valuesLessThan20)
[1,5]
- 1
find
找到通过所提供函数测试的第一个元素,测试函数应返回true或false。
var people = [
{name: 'Jack', age: 50},
{name: 'Michael', age: 9},
{name: 'John', age: 40},
{name: 'Ann', age: 19},
{name: 'Elisabeth', age: 16}
]
function teenager(person) {
return person.age > 10 && person.age < 20
}
var firstTeenager = people.find(teenager)
console.log('First found teenager:', firstTeenager.name)
First found teenager: Ann
- 1
every
检查数组的每个元素是否通过所提供函数的测试,测试函数应返回true或false。
var people = [
{name: 'Jack', age: 50},
{name: 'Michael', age: 9},
{name: 'John', age: 40},
{name: 'Ann', age: 19},
{name: 'Elisabeth', age: 16}
]
function teenager(person) {
return person.age > 10 && person.age < 20
}
var everyoneIsTeenager = people.every(teenager)
console.log('Everyone is teenager: ', everyoneIsTeenager)
Everyone is teenager: false
- 1
some
检查数组中是否有某个元素能够通过所提供函数的测试,测试函数应返回true或false。
var people = [
{name: 'Jack', age: 50},
{name: 'Michael', age: 9},
{name: 'John', age: 40},
{name: 'Ann', age: 19},
{name: 'Elisabeth', age: 16}
]
function teenager(person) {
return person.age > 10 && person.age < 20
}
var thereAreTeenagers = people.some(teenager)
console.log('There are teenagers:', thereAreTeenagers)
There are teenagers: true
- 1
reduce
第一个参数是一个函数,该函数的参数为一个累加器以及数组中的每个元素(从左到右),并最终输出单个值。累加器的初始值则由reduce函数的第二个参数提供。
var array = [1, 2, 3, 4]
function sum(acc, value) {
return acc + value
}
function product(acc, value) {
return acc * value
}
var sumOfArrayElements = array.reduce(sum, 0)
var productOfArrayElements = array.reduce(product, 1)
console.log('Sum of', array, 'is', sumOfArrayElements)
console.log('Product of', array, 'is', productOfArrayElements)
Sum of [1,2,3,4] is 10
Product of [1,2,3,4] is 24
3. 箭号函数
有时候,实现一些简单的功能也需要编写大量的重复代码。有什么补救办法吗?有,请尝试一下箭头函数!
var array = [1, 2, 3, 4]
const sum = (acc, value) => acc + value
const product = (acc, value) => acc * value
var sumOfArrayElements = array.reduce(sum, 0)
var productOfArrayElements = array.reduce(product, 1)
箭头函数也可以内联。它真的让代码更简单了:
var array = [1, 2, 3, 4]
var sumOfArrayElements = array.reduce((acc, value) => acc + value, 0)
var productOfArrayElements = array.reduce((acc, value) => acc * value, 1)
- 箭头函数也可以更复杂:
var array = [1, 2, 3, 4]
const sum = (acc, value) => {
const result = acc + value
console.log(acc, ' plus ', value, ' is ', result)
return result
}
var sumOfArrayElements = array.reduce(sum, 0)
4. 类
当转移到JS项目的时候,哪个Java开发人员不会错过类?谁不喜欢像Java语言那样的显式继承?虽然一些JS开发者对此非常抱怨,但ES6实际已经引入了类的概念。它们不改变继承这个概念,它们只是原型继承的语法糖。
class Point {
constructor(x, y) {
this.x = x
this.y = y
}
toString() {
return '[X=' + this.x + ', Y=' + this.y + ']'
}
}
class ColorPoint extends Point {
static default() {
return new ColorPoint(0, 0, 'black')
}
constructor(x, y, color) {
super(x, y)
this.color = color
}
toString() {
return '[X=' + this.x + ', Y=' + this.y + ', color=' + this.color + ']'
}
}
console.log('The first point is ' + new Point(2, 10))
console.log('The second point is ' + new ColorPoint(2, 10, 'green'))
console.log('The default color point is ' + ColorPoint.default())
The first point is [X=2, Y=10]
The second point is [X=2, Y=10, color=green]
The default color point is [X=0, Y=0, color=black]
- 1
- 2
- 3
5. 增强的对象字面量
对象字面量已得到了增强。现在我们可以更容易地:
- 定义具有相同名称的变量赋值字段
- 定义函数
- 定义动态属性
const color = 'red'
const point = {
x: 5,
y: 10,
color,
toString() {
return 'X=' + this.x + ', Y=' + this.y + ', color=' + this.color
},
[ 'prop_' + 42 ]: 42
}
console.log('The point is ' + point)
console.log('The dynamic property is ' + point.prop_42)
The point is X=5, Y=10, color=red
The dynamic property is 42
6. 模板字符串
谁喜欢写一连串的字符串与变量的连接?我相信只有极少数人会喜欢。谁讨厌阅读这样的连接?每个人。幸运的是,ES6引入了非常易于使用的带有占位符的字符串模板。
function hello(firstName, lastName) {
return `Good morning ${firstName} ${lastName}!
How are you?`
}
console.log(hello('Jan', 'Kowalski'))
Good morning Jan Kowalski!
How are you?
请注意,我们可以将文本写成多行。
重要提示:请使用反引号而不是撇号来将文本包围起来。
7. 默认函数参数
你不喜欢提供所有可能的函数参数?请使用默认值。
function sort(arr = [], direction = 'ascending') {
console.log('I\'m going to sort the array', arr, direction)
}
sort([1, 2, 3])
sort([1, 2, 3], 'descending')
I'm going to sort the array [1,2,3] ascending
I'm going to sort the array [1,2,3] descending
8. Rest和Spread操作符
Spread
它可以将数组或对象内容提取为单个元素。
示例 - 数组的浅拷贝:
var array = ['red', 'blue', 'green']
var copyOfArray = [...array]
console.log('Copy of', array, 'is', copyOfArray)
console.log('Are', array, 'and', copyOfArray, 'same?', array === copyOfArray)
Copy of ["red","blue","green"] is ["red","blue","green"]
Are ["red","blue","green"] and ["red","blue","green"] same? false
示例 - 合并数组:
var defaultColors = ['red', 'blue', 'green']
var userDefinedColors = ['yellow', 'orange']
var mergedColors = [...defaultColors, ...userDefinedColors]
console.log('Merged colors', mergedColors)
Merged colors ["red","blue","green","yellow","orange"]
- 1
Rest
要将前几个函数参数绑定到指定变量,而将其他参数作为数组绑定到单个变量上吗?现在你可以很容易地做到这一点。
function printColors(first, second, third, ...others) {
console.log('Top three colors are ' + first + ', ' + second + ' and ' + third + '. Others are: ' + others)
}
printColors('yellow', 'blue', 'orange', 'white', 'black')
Top three colors are yellow, blue and orange. Others are: white,black
对于数组
从数组中提取指定元素并将其赋值给变量。
function printFirstAndSecondElement([first, second]) {
console.log('First element is ' + first + ', second is ' + second)
}
function printSecondAndFourthElement([, second, , fourth]) {
console.log('Second element is ' + second + ', fourth is ' + fourth)
}
var array = [1, 2, 3, 4, 5]
printFirstAndSecondElement(array)
printSecondAndFourthElement(array)
对于对象
从对象中提取指定的属性,并将其赋值给具有相同名称的变量。
function printBasicInfo({firstName, secondName, profession}) {
console.log(firstName + ' ' + secondName + ' - ' + profession)
}
var person = {
firstName: 'John',
secondName: 'Smith',
age: 33,
children: 3,
profession: 'teacher'
}
printBasicInfo(person)
John Smith - teacher
10. Promises
Promise承诺,你将会得到延时任务或者长期运行任务的未来结果。Promise有两个通道:第一个为结果,第二个为潜在的错误。要获取结果,你要将回调函数作为“then”的函数参数。要处理错误,你要将回调函数作为“catch”的函数参数。
请注意,由于函数调用是随机的,所以,示例每次执行的输出可能是不同的。
function asyncFunc() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const result = Math.random();
result > 0.5 ? resolve(result) : reject('Oppps....I cannot calculate')
}, 1)
});
}
for (let i=0; i<10; i++) {
asyncFunc()
.then(result => console.log('Result is: ' + result))
.catch(result => console.log('Error: ' + result))
}
Result is: 0.7930997430022211
Error: Oppps....I cannot calculate
Result is: 0.6412258210597288
Result is: 0.7890325910244533
Error: Oppps....I cannot calculate
Error: Oppps....I cannot calculate
Result is: 0.8619834683310168
Error: Oppps....I cannot calculate
Error: Oppps....I cannot calculate
Result is: 0.8258410427354488
我希望你能喜欢这篇文章。如果你想要做一些练习,可以使用沙箱进行学习:https://es6console.com/。如果想要获取更多的信息,可以访问这里: