ES6 Tutorial
ES6的新特性包含以下内容:
- 变量的作用域
- this
- Arrow function
- destructuring assignment
- Template literal
- Spread operator
- class
- modules
- Promise
变量的作用域
function sayHello() {
for (var i = 0; i < 5; i++) {
console.log(i);
}
console.log(i);
}
sayHello();
上述代码正常运行,第5行输出i=5,说明使用var定义的变量i的作用域是sayHello整个函数。
function sayHello() {
for (let i = 0; i < 5; i++) {
console.log(i);
}
console.log(i);
}
sayHello();
上述代码在第5行会报错:Uncaught ReferenceError: i is not defined
。说明在第2行使用let定义的变量i只在for循环这个block内生效。
const x = 1;
x = 2;
上述代码在第2行会报错:Uncaught TypeError: Assignment to constant variable.
说明使用const定义的常量x,不能被再次赋值。const声明的常量的作用域和let声明的变量的作用域一样。
this关键字
JavaScript中的this关键词和c#、Java中的this关键词不同,返回当前对象的引用。
const person = {
name: 'name',
walk() {console.log(this)}
};
person.walk(); // {name: 'name', walk: f}
上述代码中的this返回{name: 'name', walk: f}
,即person对象的引用。
const person = {
name: 'name',
walk() {console.log(this)}
};
const walk = person.walk;
console.log(walk);
walk();
第5行是对walk方法的引用,第6行打印结果是f walk() {console.log(this)}
第7行来调用walk方法,结果返回一个Window
对象。
总结:this指的是什么?如果将函数作为对象中的方法调用时(case1),this返回的永远是对象的引用;如果将调用函数作为对象外的函数单独调用(case2),this返回的是浏览器中的全局Window对象。
如何避免case2?在JavaScript中 functions are objects
(method) Function.bind(this: Function, thisArg: any, …argArray: any[]): any
For a given function, creates a bound function that has the same body as the original function. The this object of the bound function is associated with the specified object, and has the specified initial parameters.
对于给定函数,创建与原始函数具有相同主体的绑定函数。绑定函数的this对象与指定的对象相关联,并且具有指定的初始参数。
@param
thisArg
— An object to which the this keyword can refer inside the new function.@param
argArray
— A list of arguments to be passed to the new function.
const person = {
name: 'baiyin',
walk() {console.log(this)}
};
const walk = person.walk.bind(person);
walk();
本例中,person.walk.bind(person)
创建了一个句person.walk函数具有相同主体的绑定函数walk,将walk函数的this对象与person对象关联。
array functions
在JavaScript中,我们通常会遇到这种情况:不需要对函数命名,特别是将函数作为参数传递给另一个函数时,这时我们使用行内函数inline function,这种函数不会被复用。
类似于python中的匿名函数,Java中的lambda表达式,array function是一种简化函数的写法,主要和filter、map、reduce等函数结合使用。
const square = function(number) {
return number * number;
}
const square = number => number * number
console.log(square(5));
参数的简化写法:
-
没有参数:()
-
单个参数:parameter
-
多个参数:(param1, param2)
-
带默认值的参数:(param1, param2 = value)
-
动态参数个数:(…args)
函数体的简化写法:
- 如果函数体只有一条语句,可以省略大括号{}、return关键字和分号。
常见用法:
- 和filter函数结合使用
const jobs = [
{ id: 1, isActive: true },
{ id: 2, isActive: true },
{ id: 3, isActive: false}
]
const activeJobs = jobs.filter(function(job) { return job.isActive; });
// 使用箭头函数简化
const activeJobs = jobs.filter(job => job.isActive);
箭头函数不会重新绑定this
map函数
const colors = ['red', 'yellow', 'blue'];
const items = colors.map(function(color) {
return '<li>' + color + '</li>';
})
console.log(items)
使用箭头函数优化:
const colors = ['red', 'yellow', 'blue'];
const items = colors.map(color => '<li>' + color + '</li>')
console.log(items)
使用模板优化字符串拼接:
const colors = ['red', 'yellow', 'blue'];
const items = colors.map(color => `<li>${color}</li>`)
console.log(items)
destructuring 析构
从对象中解析属性并赋值给新的变量:
const address = {
country: 'China',
city: 'Xi\'an',
district: 'Yanta',
street: 'Yuhua'
}
// extract properties one-by-one
const country = address.country;
const city = address.city;
const district = address.district;
const street = address.street;
// extract specific properties
const {country, city} = address;
// extract specific properties and assign to renamed variable
const {country, city, street: st} = address;
解析层级对象:
const LOCAL_FORECAST = {
yesterday: { low: 61, high: 75 },
today: { low: 64, high: 77 },
tomorrow: { low: 68, high: 80 }
};
const { today: {low: lowToday, high: highToday} } = LOCAL_FORECAST;
解析数组:
const arr = [1, 2, 3, 4, 5, 6];
const [a, b,,, c] = arr;// a = 1, b = 2, c = 5
const [a, b, ...c] = arr; // a = 1, b = 2, c = [3, 4, 5, 6]
对象作为函数的入参:
const stats = {
max: 100,
min: 0,
median: 20,
mode: 21,
average: 46
}
const half = (stats) => (stats.max + stats.min) / 2.0;
console.log(half(stats));
const half = ({min, max}) => (min + max) / 2.0;
console.log(half(stats));
Template literal
- 使用template创建复杂字符串
const person = {
name: "bai",
age: 28
};
const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;
console.log(greeting);
- 根据array内容生成
const result = {
success: ["max-length", "no-amd", "prefer-arrow-functions"],
failure: ["no-var", "var-on-top", "linebreak"],
skipped: ["no-extra-semi", "no-dup-keys"],
};
function makeList(arr) {
const failureItems = arr.map(
(element) => `<li class="text-warning">${element}</li>`
);
return failureItems;
}
const failuresList = makeList(result.failure);
使用ES6,您可以在定义对象中的函数时完全删除函数关键字和冒号。
spread operator
...arr
returns an unpacked array. In other words, it spreads the array. However, the spread operator only works in-place, like in an argument to a function or in an array literal.
- 组装数组:
const first = [1, 2, 3];
const second = [4, 5, 6];
const third = [7, 8, 9];
// old usage
const combined = first.concat(second).concat(third);
// spread operator
const combined = [...first, ...second, ...third];
// using spread clone
const clone = [...first];
- 组装对象:
const first = {name: 'bai'};
const second = {job: 'instructor'};
// combine object
const combined = {...first, ...second, location: 'China'};
// clone object
const clone = {...first}
class
- 创建类
class Person {
constructor(name) {
this.name = name;
}
walk() {
console.log('walk');
}
}
const person = new Person('bai');
person.walk();
- 继承
class Person {
constructor(name) {
this.name = name;
}
walk() {
console.log(this.name + ' is walking.');
}
}
class Teacher extends Person{
constructor(name, degree) {
super(name);
this.degree = degree;
}
teach() {
console.log(this.name + ' (' + this.degree + ') is teaching.');
}
}
const teacher = new Teacher('bai', 'degree');
teacher.walk();
teacher.teach();
modules
上述代码的实现都在index.js中,需要进行模块化。一个文件作为一个模块,拆分如下:
// person.js
export class Person {
constructor(name) {
this.name = name;
}
walk() {
console.log(this.name + ' is walking.');
}
}
// teacher.js
import { Person } from "./person";
export class Teacher extends Person{
constructor(name, degree) {
super(name);
this.degree = degree;
}
teach() {
console.log(this.name + ' (' + this.degree + ') is teaching.');
}
}
// index.js
import { Teacher } from "./teacher";
const teacher = new Teacher('bai', 'degree');
teacher.walk();
teacher.teach();
export分为named export和default export。
- named export
export class Person
import {Person} from "./person"
- Default export
export default class Person
import Person from "./person"
使用export *导入整个模块:
import * as myMathModule from "./math_function.js";
myMathModule.add(2, 3);
Promise
- 创建promise
创建一个promise需要resolve和reject两个参数,分别表明promise成功和失败后需要调用的方法。
一个promise有三个状态:pending、fulfilled、rejected。刚创建的promise是pending状态,当希望promise成功时调用resolve方法,当希望promise失败时调用reject方法。
const makeServerRequest = new Promise((resolve, reject) => {
// responseFromServer represents a response from a server
let responseFromServer;
if(responseFromServer) {
resolve('We got the data');
} else {
reject('Data not received');
}
});
- 使用then处理fulfilled promise
当有一段代码需要花费未知的时间(异步任务等)时promise是有用的,通常是服务器请求。当创建一个服务器请求,它需要花费一些时间,它完成之后希望使用来自服务器的响应进行操作。这可以通过使用then方法来实现。then方法会在promise被使用resolve方法完成之后立即执行。
myPromise.then(result => {
console.log(result);
});
- 使用catch处理rejected promise
myPromise.catch(error => {
console.log(error);
});