作用域
使用let
/const
替代var
。
var
有什么错?
var
说明的变量会产生作用于提升的概念。
ES5:
var x = 'outer'; function test(inner) { if (inner) { var x = 'inner'; // scope whole function return x; } return x; // gets redefined because line 4 declaration is hoisted } test(false); // undefined 😱 test(true); // inner
test(false)
返回的是undefined而不是outer。
为什么?
因为if-block没有执行,第四行的var x
被提升了。
提升后,上面的代码变成了下面的样子:
var x = 'outer'; function test(inner) { var x; // 提升到了 if (inner) { x = 'inner'; // 初始化没有提升 return x; } return x; }
ES6中可以这样解决这个问题:
let x = 'outer'; function test(inner) { if (inner) { let x = 'inner'; return x; } return x; // gets result from line 1 as expected } test(false); // outer test(true); // inner
将var
改为let
后,返回的就是如你所愿的outer了。如果if
block没有调用,x
变量也不会提升了。
IIFE
ES5:
{ var private = 1; } console.log(private); // 1
可以看到private
暴露出来了。为了不暴露它,你需要用IIFE包裹住它:
ES5
(function(){ var private2 = 1; })(); console.log(private2); // Uncaught ReferenceError
如果你看过jQuery/lodash的源码,你会发现它们都使用了IIFE来避免全局变量污染。
在ES6中解决这个问题简单许多,不需要再使用IIFE了,我们只需要使用block和let
:
ES6:
{ let private3 = 1; } console.log(private3); // Uncaught ReferenceError
const
如果有个变量你永远都不想它改变的话,你可以使用const
。
模板字面量
ES5:
var first = 'Adrian'; var last = 'Mejia'; console.log('Your name is ' + first + ' ' + last + '.');
在ES6中,我们可以使用${}来代替+:
const first = 'Adrian' const last = 'Mejia' console.log('Your name is ${first} ${last}.');
多行字符串
不再需要像下面一样使用 +\n
了。
ES5:
var template = '<li *ngFor="let todo of todos" [ngClass]="{completed: todo.isDone}" >\n' + ' <div class="view">\n' + ' <input class="toggle" type="checkbox" [checked]="todo.isDone">\n' + ' <label></label>\n' + ' <button class="destroy"></button>\n' + ' </div>\n' + ' <input class="edit" value="">\n' + '</li>'; console.log(template);
在ES6中使用反引号来解决这个问题:
const template = `<li *ngFor="let todo of todos" [ngClass]="{completed: todo.isDone}" > <div class="view"> <input class="toggle" type="checkbox" [checked]="todo.isDone"> <label></label> <button class="destroy"></button> </div> <input class="edit" value=""> </li>`; console.log(template);
解构赋值
获取一个数组中的元素
ES5:
var array = [1, 2, 3, 4, 5]; var first = array[0]; var third = array[2]; console.log(first, third); // 1 3
ES6:
const array = [1, 2, 3, 4, 5]; const [first, ,third] = array; console.log(first, third); // 1 3
交换变量
ES5:
var a = 1; var b = 2; var temp = a; a = b; b = temp; console.log(a, b); // 2 1
ES6:
let a = 1; let b = 2; [a, b] = [b, a]; console.log(a, b); // 2 1
解构多个返回值
ES5:
function margin() { var left=1, right=2, top=3, bottom=4; return { left: left, right: right, top: top, bottom: bottom }; } var data = margin(); var left = data.left; var bottom = data.bottom; console.log(left, bottom); // 1 4
在ES6中,调用者可以从选择的选取返回数据(第6行):
ES6:
function margin() { const left=1, right=2, top=3, bottom=4; return { left, right, top, bottom }; } const { left, bottom } = margin(); console.log(left, bottom); // 1 4
注意第3行,我们可以将{ left: left }
简写为{ left }
。
解构参数匹配
ES5:
var user = {firstName: 'Adrian', lastName: 'Mejia'}; function getFullName(user) { var firstName = user.firstName; var lastName = user.lastName; return firstName + ' ' + lastName; } console.log(getFullName(user)); // Adrian Mejia
ES6:
const user = {firstName: 'Adrian', lastName: 'Mejia'}; function getFullName({ firstName, lastName }) { return `${firstName} ${lastName}`; } console.log(getFullName(user)); // Adrian Mejia
解构对象
ES5:
function settings() { return { display: { color: 'red' }, keyboard: { layout: 'querty'} }; } var tmp = settings(); var displayColor = tmp.display.color; var keyboardLayout = tmp.keyboard.layout; console.log(displayColor, keyboardLayout); // red querty
ES6:
function settings() { return { display: { color: 'red' }, keyboard: { layout: 'querty'} }; } const { display: { color: displayColor }, keyboard: { layout: keyboardLayout }} = settings(); console.log(displayColor, keyboardLayout); // red querty
最佳练习
- 使用解构数组来获取数组中的元素或交换变量。这将减少创建临时变量。
- 不要使用解构数组来获取多个返回值,使用解构对象来获取多个返回值。
类和对象
在ES6中,我们不再使用构造函数Function,而是使用class
。
在ES5中,我们使用构造函数Function来实现OOP。
ES5:
var Animal = (function () { function MyConstructor(name) { this.name = name; } MyConstructor.prototype.speak = function speak() { console.log(this.name + ' makes a noise.'); }; return MyConstructor; })(); var animal = new Animal('animal'); animal.speak(); // animal makes a noise.
ES6提供了class
和constructor
关键字来实现类。同时使用speak()
来替代constructor.prototype.speak = function() {}
。
ES6:
class Animal { constructor(name) { this.name = name; } speak() { console.log(this.name + ' makes a noise.'); } } const animal = new Animal('animal'); animal.speak(); // animal makes a noise.
继承
在ES5中,使用原型链来实现继承。
ES5:
var Lion = (function () { function MyConstructor(name){ Animal.call(this, name); } // prototypal inheritance MyConstructor.prototype = Object.create(Animal.prototype); MyConstructor.prototype.constructor = Animal; MyConstructor.prototype.speak = function speak() { Animal.prototype.speak.call(this); console.log(this.name + ' roars 🦁'); }; return MyConstructor; })(); var lion = new Lion('Simba'); lion.speak(); // Simba makes a noise. // Simba roars.
ES6提供了extends
和super
关键字。
ES6:
class Lion extends Animal { speak() { super.speak(); console.log(this.name + ' roars 🦁'); } } const lion = new Lion('Simba'); lion.speak(); // Simba makes a noise. // Simba roars.
原生的Promise
ES5:
function printAfterTimeout(string, timeout, done){ setTimeout(function(){ done(string); }, timeout); } printAfterTimeout('Hello ', 2e3, function(result){ console.log(result); // nested callback printAfterTimeout(result + 'Reader', 2e3, function(result){ console.log(result); }); });
ES6:
function printAfterTimeout(string, timeout){ return new Promise((resolve, reject) => { setTimeout(function(){ resolve(string); }, timeout); }); } printAfterTimeout('Hello ', 2e3).then((result) => { console.log(result); return printAfterTimeout(result + 'Reader', 2e3); }).then((result) => { console.log(result); });
箭头函数
在ES5中this
有些问题:
ES5:
var _this = this; // need to hold a reference $('.btn').click(function(event){ _this.sendData(); // reference outer this }); $('.input').on('change',function(event){ this.sendData(); // reference outer this }.bind(this)); // bind to outer this
需要使用一个临时变量或者bind
来绑定this。在ES6中,你可以使用箭头函数。
ES6:
// this will reference the outer one $('.btn').click((event) => this.sendData()); // implicit returns const ids = [291, 288, 984]; const messages = ids.map(value => `ID is ${value}`);
for of
ES6中提供了for of
ES5:
// for var array = ['a', 'b', 'c', 'd']; for (var i = 0; i < array.length; i++) { var element = array[i]; console.log(element); } // forEach array.forEach(function (element) { console.log(element); });
ES6:
// for ...of const array = ['a', 'b', 'c', 'd']; for (const element of array) { console.log(element); }
参数默认值
ES5:
function point(x, y, isFlag){ x = x || 0; y = y || -1; isFlag = isFlag || true; console.log(x,y, isFlag); } point(0, 0) // 0 -1 true 😱 point(0, 0, false) // 0 -1 true 😱😱 point(1) // 1 -1 true point() // 0 -1 true
ES6:
function point(x = 0, y = -1, isFlag = true){ console.log(x,y, isFlag); } point(0, 0) // 0 0 true point(0, 0, false) // 0 0 false point(1) // 1 -1 true point() // 0 -1 true
Rest parameters
ES5:
function printf(format) { var params = [].slice.call(arguments, 1); console.log('params: ', params); console.log('format: ', format); } printf('%s %d %.2f', 'adrian', 321, Math.PI);
ES6提供了...
操作符。
ES6:
function printf(format, ...params) { console.log('params: ', params); console.log('format: ', format); } printf('%s %d %.2f', 'adrian', 321, Math.PI);
展开操作符(Spread operator)
ES5:
Math.max.apply(Math, [2,100,1,6,43]) // 100
ES6:
Math.max(...[2,100,1,6,43]) // 100
同样适用...
来替代concat。
ES5:
var array1 = [2,100,1,6,43]; var array2 = ['a', 'b', 'c', 'd']; var array3 = [false, true, null, undefined]; console.log(array1.concat(array2, array3));
ES6:
const array1 = [2,100,1,6,43]; const array2 = ['a', 'b', 'c', 'd']; const array3 = [false, true, null, undefined]; console.log([...array1, ...array2, ...array3]);
来源:https://www.cnblogs.com/irocker/p/ECMAScript-Features.html