let和const
-
let
:声明变量,只在let所在作用域内有效,在声明变量之前,该变量都不能使用,被称为暂时性死区。 -
let
和const
没有变量提升 -
let
不允许在相同的作用域内重复声明同一个变量 -
const
:声明的值不得改变,const
一旦声明变量就必须立即初始化,不能留到以后赋值const
:实质是保证变量指向的内存地址所保存的数据不能改动。 - 顶层对象,浏览器中指
window
,node中指global
模板字符串
- 模板字符串用反引号标识:``
- 可以使用${} 添加变量,{}中也可以是函数,表达式
变量的解构赋值
- 解构赋值的规则:只要等号右边的值不是对象或数组,就会先将其转换为对象。数组的解构赋值
- 模式匹配:等号两边的模式相同,左边的变量就会被赋予右边的对应的值。解构不成功时,会被赋值为
undefined
。 - 默认值:解构赋值允许有默认值,所以要,只有===undefined时,默认值才能生效
对象的解构赋值
- 属性名字匹配:变量名与属性名相同时才能取到正确的值,解构不成功,被赋值为
undefined
对象的解构赋值是将前者的值解构赋予后者:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
字符串解构赋值
- 字符串的解构赋值是默认将字符串转换为类数组对象了数值与布尔值的解构赋值
- 如果等号右边的值是数值和布尔值,那么会先转换为对象,再进行解构赋值。
对象字面量
- ES6允许在对象之中,直接写变量。属性可以简写,如:
function f(x, y) {
return {x, y};
}
// 等同于
function f(x, y) {
return {x: x, y: y};
}
f(1, 2) // Object {x: 1, y: 2}
- 方法也可以简写,省略function:
const o = {
method() {
return "Hello!";
}
};
// 等同于
const o = {
method: function() {
return "Hello!";
}
};
- ES6允许字面量定义对象时,用表达式作为对象的属性名,但是要将表达式放在方括号内
let lastWord = 'last word';
const a = {
'first word': 'hello',
[lastWord]: 'world'
};
a['first word'] // "hello"
a[lastWord] // "world"
a['last word'] // "world"
- 表达式也可以用于定义方法名
let obj = {
['h' + 'ello']() {
return 'hi';
}
};
obj.hello() // hi
箭头函数
- ES6允许使用“箭头”
(=>)
定义函数,箭头函数可以省略function
关键字
var f = v => v;
// 等同于
var f = function (v) {
return v;
};
- 如果箭头函数没有参数或者有多个参数,就需要使用圆括号,如果只有一个参数,可以将圆括号省略
var f = () => 5;
// 等同于
var f = function () { return 5 };
var sum = (num1, num2) => num1 + num2;
// 等同于
var sum = function(num1, num2) {
return num1 + num2;
};
- 箭头函数的
this
指针指向的是定义时所在的对象,而不是使用时所在的对象 - 箭头函数不可以当作构造函数,不可以使用
new
命令 - 不可以使用
arguments
对象,该对象在函数体内不存在。可以使用rest参数代替
Import和Export
- ES6的模块自动采用严格模式,不管有没有在模块头部添加
‘use strict’
- 严格模式的限制有:
- 变量必须声明后使用
- 函数的参数不能有同名的属性不能对只读属性赋值
- 禁止this指向全局对象,ES6中顶层的this指向
undefined
export命令
- 模块的功能主要由两个命令构成:
export
和import
。 -
export
用于规定模块的对外接口,import
命令用于输入其他模块提供的功能 如果你需要在外部读取到模块内部的某个变量,就必须使用export
输出该变量
export var firstName = 'Michael';
export var lastName = 'Jackson';
export var year = 1958;
// 等同于
var firstName = 'Michael';
var lastName = 'Jackson';
var year = 1958;
export { firstName, lastName, year };
-
export
除了输出变量,还可以输出函数或类(class)
export function multiply(x, y) {
return x * y;
};
- 通常情况下,
export
输出的变量就是本来的名字,但是可以使用as
关键字重命名
function v1() { ... }
function v2() { ... }
export {
v1 as streamV1,
v2 as streamV2,
v2 as streamLatestVersion
};
// 重命名后v2可以以不同的名字输出两次
-
export
命令规定的是对外的接口,必须与模块内部的变量建立一一对应的关系
import命令
- 使用
export
定义了模块的对接口以后,就可以通过import
命令来加载这个模块了
import { firstName, lastName, year } from './profile.js';
-
import
命令接受一对大括号,里面指定要从其他模块导入的变量名。大括号里面的变量名必须与被导入模块对 外接口的名称相同。import
后面的from
指定模块的文件位置,可以是相对位置,也可以是绝对位置。 - 如果想要重新命名,可以使用
as
关键字
import { lastName as surname } from './profile.js';
-
import
命令输入的变量都是只读的,不允许在加载模块的脚本里面,改写接口。但是可以改写接口的属性。 -
import
是静态执行,所以不能使用表达式变量。
export default命令
-
export default
就是输出一个default
的变量或者方法,在import
输入的时候允许为他命名为任意的名字。 - 一个模块只能有一个默认输出,因此
export default
命令只能使用一次。所以,import
命令后不需要加{},因为只能唯一对应到export default
的值
// modules.js
function add(x, y) {
return x * y;
}
export {add as default};
// 等同于
// export default add;
// app.js
import { default as foo } from 'modules';
// 等同于
// import foo from 'modules';
-
export default
命令其实是输出一个叫做default
的值,所以他的后面不能跟变量声明的语句
// 正确
export var a = 1;
// 正确
var a = 1;
export default a;
// 错误
export default var a = 1;
装饰器
- 修饰作用于类,
- 修饰器函数的第一个参数是要修饰的目标类。修饰器可以接受参数,相当于修改修饰器
function testable(isTestable) {
return function(target) {
target.isTestable = isTestable;
}
}
@testable(true)
class MyTestableClass {}
MyTestableClass.isTestable // true
@testable(false)
class MyClass {}
MyClass.isTestable // false
- 修饰器对类的行为改变,是代码编译时发生的。意味着修饰器能在编译阶段运行代码。 修饰器的本质就是编译时执行的函数
- 修饰器修饰类的属性
- 修饰器的第一个参数是类的原型对象,第二个参数是所要修饰的属性名,第三个参数是该属性的描述对象
class Person {
@readonly
name() { return `${this.first} ${this.last}` }
}
function readonly(target, name, descriptor){
// descriptor对象原来的值如下
// {
// value: specifiedFunction,
// enumerable: false,
// configurable: true,
// writable: true
// };
descriptor.writable = false;
return descriptor;
}
readonly(Person.prototype, 'name', descriptor);
// 类似于
Object.defineProperty(Person.prototype, 'name', descriptor);
- 修饰器不能作用于函数的原因是:函数存在变量提升,导致函数实际执行顺序与书写的不一致
Promise
- promise对象的两个特点
- 对象的状态不受外界影响。
promise
有三种状态,pending
(进行中)、fufilled
(已成功)、rejected
(已失败)。只有异步操作的结果可以决定当前的状态。 - 一旦状态改变,就不会再改变,任何时候都可以得到这个结果。
promise
对象的状态改变只有两种可能: 从pending
变为fufilled
和从pending
变成rejected
。
- 对象的状态不受外界影响。
- promise的基本用法:
const promise = new Promise(function(resolve, reject) {
// ... some code
if (/* 异步操作成功 */){
resolve(value);
} else {
reject(error);
}
});
-
promise
构造函数接受一个函数作为参数,该函数的两个参数分别是resolve
和reject
。 -
resolve
函数作用是将promise
对象的状态变为成功,并将异步操作的结果作为参数传递出去。 -
reject
函数 的作用是将promise
的状态变为失败,并将异步操作的错误作为参数传递出去。 -
promise
实例生成后,可以使用then
方法来分别指定resolved
状态和rejected
状态的回调。
promise.then(function(value) {
// success
}, function(error) {
// failure
});
- promise新建后就会立即执行,then函数会进入异步队列等候执行
- Promise.prototype.then()
-
then
方法定义在原先对象promise.prototype
上。作用是为promise
实例添加状态改变时的回调函数 -
then
方法的第一个参数是resolved
状态的回调函数,第二个参数(可选)是rejected
状态的回调函数。then
方法的返回值是一个新的promise
实例,因此可以采用链式写法,在then
方法后再调用另一个then
方 法。
-
getJSON("/posts.json").then(function(json) {
return json.post;
}).then(function(post) {
// ...
});
- promise.prototype.catch()
-
Promise.prototype.catch
方法是.then(null, rejection)
或.then(undefined, rejection)
的别名,用于指定发生错误时的回调函数。
-
getJSON('/posts.json').then(function(posts) {
// ...
}).catch(function(error) {
// 处理 getJSON 和 前一个回调函数运行时发生的错误
console.log('发生错误!', error);
});
- 如果没有使用
catch
方法指定错误处理的回调函数,promise
对象抛出的错误就不会传递到外层代码。
因此建议在promise
对象后面要跟catch
方法,catch
方法返回的也是一个promise
对象,接着还可以调用
then
方法。promise.prototype.finally()
-
finally
方法用于指定不管promise
对象最后状态如何,都会执行的操作。
promise
.then(result => {···})
.catch(error => {···})
.finally(() => {···});
// 不管promise最后的状态,在执行完then或catch指定的回调函数以后,都会执行finally方法指定的回调函数。
-
finally
方法的回调不接受任何参数,也就是无法指定promise
的状态是成功还是失败。finally
里面的操作是 与状态无关的,不依赖promise
的状态。 - promise.all()
promise.all
方法用于将多个promise
实例,包装成一个新的promise
实例。
const p = Promise.all([p1, p2, p3]);
// Promise.all方法接受一个数组作为参数,p1、p2、p3都是 Promise 实例
// p的状态由p1、p2、p3决定,分成两种情况。
// 只有p1、p2、p3的状态都变成fulfilled,p的状态才会变成fulfilled
如果作为参数的promise
实例,自己定义了catch
方法,那么他被rejected
之后也不会触发promise.all
的
catch
方法
const p1 = new Promise((resolve, reject) => {
resolve('hello');
})
.then(result => result)
.catch(e => e);
const p2 = new Promise((resolve, reject) => {
throw new Error('报错了');
})
.then(result => result)
.catch(e => e);
Promise.all([p1, p2])
.then(result => console.log(result))
.catch(e => console.log(e));
// ["hello", Error: 报错了]
// p1会resolved,p2首先会rejected,但是p2有自己的catch方法,该方法返回的是一个新的 Promise 实例,p2指向的实际上是这个实例。该实例执行完catch方法后,也会变成resolved,导致Promise.all()方法参数里面的两个实例都会resolved,因此会调用then方法指定的回调函数,而不会调用catch方法指定的回调函数。
// 如果p2没有自己的catch方法,就会调用Promise.all()的catch方法。