# 一、字符串函数
函数 | 描述 |
---|---|
includes(text,index) | 如果在字符串中检测到指定文本则返回true ,否则返回false ,第二个参数指定从哪个字符开始搜索 |
startsWidth(text,index) | 如果在字符串的起始部分检测到指定文本则返回true ,否则false ,第二个参数指定从哪个字符开始搜索 |
endsWidth(text,index) | 如果在字符串的结束部分检测到指定文本则返回true ,否则false ,第二个参数指定从哪个字符开始搜索 |
repeat(count) | 该字符串重复的次数 |
# 二、模板
# 字符串模板
let name = 'chfree'
let hello = `hello ${name}`
console.log(hello) // 输出 hello chfree
模板字符串中的占位符都是JavaScript
的表达式,可以支持除变量外的,比如:运算符、函数调用,等等。
# 标签模板
let name = 'chfree', age = 18
let message = tag`hello${name}age${age}end`
function tag(literals, ...substi){
// 通过模板字符串占位符的进行分割的字符串数组
console.log(literals) // ['hello','age','']
// 每一个模板字符串占位符的实际值的数组
console.log(substi) // ['chfree',18]
let result = ''
for(let i = 0; i < substi.length; i++){
result += literals[i] + ':'
result += substi[i] + ';'
}
result += literals[literals.length - 1]
return result
}
console.log(message) // hello:chfree;age:18;end
# 三、函数
# 函数默认值
function makeRequest(url, timeout = 2000, callback = function(){}){
}
使用场景
makeRequest('/test') // timeout, callback 使用默认值
makeRequest('/test', undefined, null) // timeout使用默认值,callback不使用默认值
默认值可以时一个函数返回
function getValue(){
return 5
}
function add(first, second = getValue()){
return first + second
}
// 还可以这样
function add(first, second = first){
return first + second
}
// 在变体一下
function getValue(value){
return 5 + value
}
function add(first, second = getValue(first)){
return first + second
}
# 展开运算符
展开运算符,是在传参数的时候,在参数前面加...
,不定参数是在定义形参的时候,最后一个参数前面加...
es5中
let values = [25,50,75,100]
console.log(Math.max.apply(Math,values)) // 100
es6
let values = [25,50,75,100]
console.log(Math.max(...values)) // 100
console.log(Math.max(...values, 200, 300)) // 300
# 箭头函数
- 没有
this
、super
、arguments
和new.target
绑定 - 不能通过
new
关键字调用 - 没有原型
- 不可以改变
this
对象的绑定 - 不支持
arguments
对象 - 不支持重复的命名参数
无参带返回值
let getName = () => 'chfree'
// 实际上相当于
let getName = function() {
return 'chfree'
}
一个参数带返回值;一个参数的时候,不需要加小括号
let reflect = value => value
// 实际上相当于
let reflect = function(value){
return value
}
二个参数带返回值;如果返回值由多个表达式组成,则需要加花括号,且最后要明确加上return
let sum (num1, num2) => num1+num2
// or
let sum (num1, num2) => {
// do other someThing
return num1+num2
}
// 实际上相当于
let sum = function(num1, num2){
// do other someThing
return num1 + num2
}
返回对象
let getTempItem = id => ({id: id, name: 'temp'})
// 实际上相当于
let getTempItem = function(id) {
return {
id: id,
name: 'Temp'
}
}
一个简单实例
var result = values.sort(function(a, b){
return a-b
})
// 使用箭头函数
var result = values.sort((a,b) => a - b)
题外:
call()
、apply()
、bind()
typeof
与instanceof
var comparator = (a,b) => a -b
console.log(typeof comparator) // "function"
console.log(comparator instanceof Function) // true
# 尾调用优化
- 尾调用不访问当前栈桢的变量(也就是说函数不是一个闭包)
- 在函数内部,尾调用是最后一条语句
- 尾调用的结果作为函数值返回
错误实例
function doSomeThing(){
// 无法优化,没有返回值
doSomeThingElse()
}
function doSomeThing(){
// 无法优化,必须在返回值后添加其他操作
return 1 + doSomeThingElse()
}
function doSomeThing(){
// 无法优化,调用不在尾部
let result = doSomeThingElse()
return result
}
function doSomeThing() {
var num = 1, func = () => num
// 无法优化,该函数是一个闭包
return func()
}
正确优化示例
function factorial(n){
if(n <= 1){
return 1
} else {
return n * factorial(n - 1)
}
}
// 优化后
function factorial(n, p = 1){
if(n <= 1){
return 1 * p
} else {
let result = n * p
return factorial(n - 1, result)
}
}
# 四、扩展对象的功能性
方法
// es5
function createPerson(name, age)
return { name: name, age: age }
}
// es6
function createPerson(name, age)
return { name, age }
}
对象
// es5
var person = {
name: 'chfree',
sayHello: function(){
cosnole.log(`hello:${this.name}`)
}
}
// es6
var person = {
name: 'chfree',
sayHello(){
console.log(`hello:${this.name}`)
}
}
# 新增方法
Object.is(a, b)
判断两个对象是否相等
console.log(+0 == -0) // true
console.log(+0 === -0) // true
console.log(Object.is(+0, -0)) // false
console.log(NaN == NaN) // false
console.log(NaN === NaN) // false
console.log(Object.is(NaN, NaN)) // true
console.log(5 == 5) // true
console.log(5 == '5') // true
console.log(5 === 5) // true
console.log(5 === '5') // false
console.log(Object.is(5, 5)) // true
console.log(Object.is(5, '5')) // false
Object.assign()
对象合并/深复制
const testUser = { name: 'chfree', age: 18}
let user = Object.assign({}, testUser)
const userOther = { age: 19, area: 'wuhan', code:'430000'}
let user = Object.assign(testUser, userOther)
console.log(user) // { name: 'chfree', age: 19, area: 'wuhan', code:'430000'}
# 五、解构
# 对象解构
简单示例
let options = {
name: 'chfree',
age: 18
}
let name = options.name, age = options.age
// 解构赋值
let { name , age } = options
错误定义,解构必须要提供初始化程序,就是=
右边的值
var { name, age }
let { name, age }
const { name, age }
默认值
let options = {
name: 'chfree',
age: 18
}
let { name , age, sex } = options // name: 'chfree', age: 18, sex: undefined
// 赋默认值
let { name , age, sex = '1'} = options // name: 'chfree', age: 18, sex: '1'
别名
let options = {
name: 'chfree',
age: 18
}
let { name: localName, age: localAge, sex: localSex = '01' } = options
已经存在的对象解构
let options = {
name: 'chfree',
age: 18
}, name = 'zhang',age = 19
({name, age} = option) // name: 'chfree', age: 18
# 嵌套对象解构
嵌套解构中,所有:
号前面的标识符都代表在对象中的检索位置,其右侧为被赋值的变量名,这么看,其实与取别名差不多的意思。如果冒号后面是花括号,则意味着要赋予的最终值嵌套在对象内部更深的层级中
let options = {
name: 'chfree',
age: 18,
loc: {
start: {
line: 1,
column: 1
},
start: {
line: 1,
column: 4
}
}
}
// loc给了默认值如果loc不存在start就是{}
/// start也给了默认值
let { loc: { start = {} } = {}} = options
console.log(start.line, start.column) // 1 1
# 数组解构
let colors = ['red', 'green', 'blue']
let [firstColor, secondColor] = colors
console.log(firstColor, secondColor) // 'red', 'green'
// 只取第三个
let [,,thirdColor] = colors
console.log(thirdColor) // 'blue'
// 默认值
let [firstColor = 'white'] = colors // 'red'
解构交互变量
let a = 1, b = 2
[a, b] = [b , a]
# 嵌套数组解构
let colors = ['red' ['green', 'lightgreen'], 'blue']
let [firstColor, [secondColor]] = colors // 'red', 'green'
不定元素解构
let colors = ['red', 'green', 'blue']
let [firstColor, ...restColors] = colors
console.log(firstColor) // 'red'
console.log(restColors) // ['green', 'blue']
克隆数组
let colors = ['red', 'green', 'blue']
// es5
let cloneColors = colors.concat()
// 解构方式
let [...cloneColors] = colors
# 参数解构
在jq
时代封装函数经常会传入一个option
参数作为控制这个组件的参数选项
function setCookie(name, value, options){
options = options || {}
let secure = options.secure,
path = options.path
}
// 解构用法
function setCookie(name, value, {secure, path} = {}){
}
// 单个参数默认值
function setCookie(name, value, {secure = false, path='/'}){
}
const defaultOption = {
secure: false,
path: '/'
}
function setCookie(name, value, {secure = false, path='/'} = defaultOption){
}
# 六、Symbol和Symbol属性
5
种数据原始类型:String
,Number
,Boolean
,null
,undefined
,ES6
:Symbol
const s1 = Symbol();
const s2 = Symbol();
console.log(s1 === s2); // false
Symbol
是作为对象的隐藏属性(或是叫私有属性)
const obj = {}
const sym = Symbol()
obj[sym] = "foo"
obj.bar = "bar"
console.log(obj) // { bar: 'bar' }
console.log(sym in obj) // true
console.log(obj[sym]) // foo
console.log(Object.keys(obj)) // ['bar']
Symbol
共享
let uid = Symbol.for('uid')
let object ={
[uid]: '12345'
}
console.log(object[uid]) // '12345'
console.log(uid) // Symbol(uid)
let uid2 = Symbol.for('uid')
console.log(uid === uid2) // true
console.log(object[uid2]) // '12345'
console.log(uid2) // Symbol(uid)
# well-known Symbol暴露内部操作
Symbol.hasInstance
function myObject(){
}
Object.defineProperty(MyObject, Symbol.hasInstance, {
value: function(v){
return false
}
})
let obj = new myObject()
console.log(obj instanceof myObject) // false
一个好玩的示例
function SpecialNumber(){
}
Object.defineProperty(SpecialNumber, Symbol.hasInstance, {
value: function(v){
return (v instanceof Number) && (v >= 1 && v <= 100)
}
})
let two = new SpecialNumber(2),
zero = new SpecialNumber(0)
console.log(two instanceof SpecialNumber) // true
console.log(zero instanceof SpecialNumber) // false
Symbol.isConcatSpreadable
let collection = {
0: 'hello',
1: 'world',
length: 2,
[Symbol.isConcatSpreadable]: true
}
let message = ['hi'].concat(collection)
console.log(message) // ['hi','hello','world']
# 七、Set集合和Map集合
es5
模拟集合
var map = Object.create(null),
key1 = {}
key2 = {name: 'chfree'}
map[key1] = 'hello'
// key1和key2作为键都会转换为字符串,都是[object Object]
console.log(map[key2]) // 'hello'
# set中的方法
set
不支持通过下标获取值
let set = new Set()
// or
let set = new Set([1,2,3,4,5])
set.add(6) // set.size 6
set.delete(5) // set.size 5
set.has(3) // true
set.clear() // set.size 0
forEach
中,this
的处理
let set = new Set([1,2,3,4,5])
let processor = {
output(val){
console.log(val)
},
process(dataSet){
dataSet.forEach(function(val){
this.output(val)
}, this)
},
process2(dataSet){
dataSet.forEach(val => this.output(val))
}
}
processor.process(set)
数组和set
互相转换
let arr = [1,2,3]
// 数组转set
let set =new Set(arr)
// set 转数组
let arr2 = [...set]
# WeakSet
- 在
WeakSet
的实例中,如果向add(),has()和delete()传入非对象参数都会导致程序报错 WeakSet
集合不可迭代,所以不能用于for-of
循环WeakSet
集合不暴露任何迭代器(例如keys()
和values()
方法),所以无法通过程序本身来检测其中的内容WeakSet
集合不支持forEach()
方法WeakSet
集合不支持seize
属性
let key1 = {}, key2 = {}
let set = new WeakSet([key1,key2])
set.add(key2)
console.log(set.has(key1)) // true
// 移除对象key的最后一个强引用后,WeakSet中的引用也自动移除;因为WeakSet保存的是对象的弱引用
key1 = null
# Map
let map = new Map()
map.set('name', 'chfree')
map.set('age', 18)
map.set(5, 'int5')
map.set('5', 'str5')
console.log(map.get('name')) // 'chfree'
console.log(map.get('age')) // 18
console.log(map.get(5)) // 'int5'
console.log(map.get('5')) // 'str5'
map
也支持has(key)
,delete(key)
,clear()
,forEach()
,支持size
属性
map
集合的初始化
let map =new Map([['name','chfree'],['age',18]])
console.log(map.get('name')) // 'chfree'
console.log(map.get('age')) // 18
// val, key, 集合本身
map.forEach(function(val, key, ownerMap){
})
WeakMap也支持,与WeakSet整体类似
# 八、迭代器(Iterator)和生成器(Generator)
# es5
实现一个迭代器
function createIterator(items){
var i = 0
return {
next: function(){
var done = ( i>= items.length )
var value = !done ? items[i++] : undefined
return {
done: done,
value: value
}
}
}
}
var iterator = createIterator([1,2,3])
console.log(iterator.next()) // {done: false, value: 1}
console.log(iterator.next()) // {done: false, value: 2}
console.log(iterator.next()) // {done: false, value: 3}
console.log(iterator.next()) // {done: true, value: undefined}
# es6
中迭代器
需要生成器来支持,是一种新的函数定义方式
function *createIterator(items){
for(let i =0; i<items.length; i++){
yield items[i]
}
}
// 结果与es手动创建一致,但代码量少很多
var iterator = createIterator([1,2,3])
console.log(iterator.next()) // {done: false, value: 1}
console.log(iterator.next()) // {done: false, value: 2}
console.log(iterator.next()) // {done: false, value: 3}
console.log(iterator.next()) // {done: true, value: undefined}
// 另外一种定义方式
let createIterator = function *(items){
// doSomeThing
yield
}
yield
字段必须在生成器内容使用。个人理解可以把yield
的地方当前生成器暂定的定点,只有生成器对象调用next()
方法,才会继续执行下一次。
可迭代对象for-of循环就是迭代器的典型应用,且可迭代对象具有Symbok.iterator
属性,该属性的值就是一种默认实现的迭代器
访问默认迭代器
let values = [1,2,3]
let iterator = values[Symbol.iterator]()
console.log(iterator.next()) // {done: false, value: 1}
console.log(iterator.next()) // {done: false, value: 2}
console.log(iterator.next()) // {done: false, value: 3}
console.log(iterator.next()) // {done: true, value: undefined}
# 判断是否是可迭代对象
function isIterator(obj){
return typeof obj[Symbol.iterator] === 'function'
}
console.log(isIterator([1,2,3])) // true
console.log(isIterator('Hello')) // true
console.log(isIterator(new Set())) // true
console.log(isIterator(new Map())) // true
console.log(isIterator(new WeakSet())) // false
console.log(isIterator(new WeakMap())) // false
# 创建可迭代对象
let collection = {
items: [],
*[Symbol.iterator]() {
for(let item of this.items){
yield item
}
}
}
collection.items.push(1)
collection.items.push(2)
collection.items.push(3)
for(let x of collection){
console.log(x) // 1,2,3
}
# 迭代器传参
function *createIterator(){
let first = yield 1
let second = yield first + 2
yield second + 3
}
let iterator = createIterator()
console.log(iterator.next()) // {done: false, value: 1}
console.log(iterator.next(4)) // {done: false, value: 6}
// 如果在这里迭代器抛出异常,后面的将不会执行
consloe.log(iterator.throw(new Error('Boom')))
console.log(iterator.next(5)) // {done: false, value: 8}
console.log(iterator.next()) // {done: true, value: undefined}
这里的first
是上一次迭代yield 1
执行后的传参,所以第一次next
的参数不会传到生成器里面,第二次传参会先赋值给first
,然后在执行yield first + 2
# 提前返回
function *createIterator(){
yield 1 // next() {done: false, value: 1}
return 100 // next() {done: true, value: 100}
yield 2 // next() {done: true, value: undefined}
yield 3 // next() {done: true, value: undefined}
}
# 委托生成器
function *createNumberIterator(){
yield 1
yield 2
}
function *createColorIterator(){
yield 'red'
yield 'blue'
}
function *createCombinedIterator(){
yield *createNumberIterator()
yield *createColorIterator()
yield true
}
var iterator = createCombinedIterator()
console.log(iterator.next()) // {done: false, value: 1}
console.log(iterator.next()) // {done: false, value: 2}
console.log(iterator.next()) // {done: false, value: 'red'}
console.log(iterator.next()) // {done: false, value: 'blue'}
console.log(iterator.next()) // {done: false, value: true}
console.log(iterator.next()) // {done: true, value: undefined}
# 委托生成器传参
function *createNumberIterator(){
yield 1
yield 2
return 3
}
function *createRepeationIterator(count){
for(let i = 0; i < count; i++){
yield 'repeat'
}
}
function *createCombinedIterator(){
let result = yield *createNumberIterator()
// 如果要输出3则需要yield一下
yield result
yield *createRepeationIterator(result)
}
var iterator = createCombinedIterator()
console.log(iterator.next()) // {done: false, value: 1}
console.log(iterator.next()) // {done: false, value: 2}
console.log(iterator.next()) // {done: false, value: 3}
console.log(iterator.next()) // {done: false, value: 'repeat'}
console.log(iterator.next()) // {done: false, value: 'repeat'}
console.log(iterator.next()) // {done: false, value: 'repeat'}
console.log(iterator.next()) // {done: true, value: undefined}
# 九、JavaScript中的类
# es5中的近类结构
function personType(name){
this.name = name
}
PersonType.prototype.sayName = function(){
console.log(this.name)
}
var person = new PersonType('chfree')
person.sayName() // 'chfree'
console.log(person instanceof PersonType) // true
console.log(person instanceof Object) // true
# es6中的类
class PersonClass {
constructor(name) {
this.name = name
}
sayName() {
console.log(this.name)
}
}
var person = new PersonClass('chfree')
person.sayName() // 'chfree'
console.log(person instanceof PersonClass) // true
console.log(person instanceof Object) // true
console.log(typeof PersonClass) // 'function'
console.log(typeof PersonClass.prototype.sayName) // 'function'
上述中的类定义转换为等价代码如下
let PersonType2 = (function(){
'use strict'
const PersonType2 = function(name){
if(typeof new.target === 'undefined'){
throw new Error('必须通过关键字new调用构造函数')
}
this.name = name
}
Object.defineProperty(PersonType2.protoype,'sayName', {
value: function() {
// 确保不会通过new关键字调用该方法
if(typeof new.target === 'undefined'){
throw new Error('不可使用new关键字调用该方法')
}
console.log(this.name)
},
enumerable: false,
writable: true,
configurable: true
})
return PersonType2
}())
class
的另一种等价定义, 表达式语法
let PersonClass = class {
constructor(name) {
this.name = name
}
sayName() {
console.log(this.name)
}
}
console.log(PersonClass.name) // 'PersonClass'
命名类表达式
let PersonClass = class PersonClass2{
constructor(name) {
this.name = name
}
sayName() {
console.log(this.name)
}
}
console.log(PersonClass.name) // 'PersonClass2'
console.log(typeof PersonClass) // 'function'
console.log(typeof PersonClass2) // 'indefined'
# 访问器属性
class CustomHTMLElement {
constructor(element){
this.element = element
}
get html() {
return this.element.innerHTML
}
set html(value){
this.element.innerHTML = value
}
}
# 可计算成员名称
let methodName = 'sayName'
let propertyName = 'html'
class PersonClass {
constructor(name, element){
this.name = name
this.element =element
}
[methodName]() {
console.log(this.name)
}
get [propertyName]() {
return this.element.innerHTML
}
set [propertyName](value){
this.element.innerHTML = value
}
}
let me = new PersonClass('chfree', document.createElement('div'))
me.sayName() // 'chfree'
me.html = '<span>html</span>'
console.log(mt.html) // '<span>html</span>'
# 生成器方法
class Collection {
constructor(){
this.items = []
}
push(item){
this.items.push(item)
}
*[Symbol.iterator](){
yield *this.items.values()
}
}
var collection = new Collection()
collection.push(1)
collection.push(2)
collection.push(3)
for(let x of collection){
console.log(x)
}
# 静态成员
class PersonClass{
constructor(name) {
this.name = name
}
sayName() {
console.log(this.name)
}
static create(name){
return new PersonClass(name)
}
}
let person = new PersonClass.create('chfree')
# 派生类与继承
class Rectangle{
constructor(width, height) {
this.width = width
this.height = height
}
getArea(){
return this.width * this.height
}
static create(width, height){
return new Rectangle(width, height)
}
}
class Square extends Rectangle {
constructor(width) {
super(width, width)
}
}
let square = new Square(3)
console.log(square.getArea()) // 9
console.log(square instanceof Square) // true
console.log(square instanceof Rectangle) // true
// 派生类也会继承静态成员
let square = Square.create(3,4)
console.log(square.getArea()) // 12
console.log(square instanceof Square) // false
console.log(square instanceof Rectangle) // true
如果没有添加构造函数等价于
class Square extends Rectangle {
// 没有添加构造函数
}
// 等价于
class Square extends Rectangle {
constructor(...args){
super(...args)
}
}
类方法遮蔽/覆盖,即子类覆盖/重写父类中的方法
class Square extends Rectangle {
getArea() {
return super.getArea()
}
}
# 派生自表达式的类
let SerializableMixin = {
serialize() {
return JSON.stringify(this)
}
}
let AreaMixin = {
getArea() {
return this.width * this.height
}
}
function mixin(...mixins){
var base = function(){}
Object.assign(base.prototype, ...mixins)
return base
}
class Square extends mixin(AreaMixin,SerializableMixin){
constructor(width){
super()
this.width = width
this.height = width
}
}
var square = new Square(3)
console.log(square.getArea()) // 9
console.log(square.serialize()) // '{"width":3,"height":3}'
# 内建对象的继承
比如继承自Array
,在es6以前几乎是不可能的
class MyArray extends Array{
}
var colors = new MyArray()
colors[0] = 'red'
# 构造函数中使用new.target
用这个,可以做出java
中密封类的效果
class Rectangle{
constructor(width, height) {
console.log('Rectangle',new.target)
if(new.target === Rectangle){
throw new Error('Rectangle不能被直接初始化')
}
this.width = width
this.height = height
}
}
class Square extends Rectangle {
constructor(width) {
console.log('Square',new.target)
super(width, width)
}
}
// new Square 在Square的构造中输出的是Square类本身,在Rectangle中输出的也是Square本身
let square = new Square(3)
console.log(square instanceof Rectangle) // true
# 十、改进的数组功能
# 创建数组
Array.of()
// Array.of()
let arr = Array.of(1,2,3,4)
console.log(arr.length) // 4
console.log(arr) // [1,2,3,4]
Array.from()
主要处理类似数组的东西进行转换成数组,比如迭代器、arguments
等
function doSomeThing(){
var args = Array.from(arguments)
}
// 映射转换
function translate(){
return Array.from(arguments, (value) => value + 1)
}
let numbers = translate(1,2,3)
console.log(numbers) // [2,3,4]
let numbers1 = {
*[Symbol.iterator]() {
yield 1
yield 2
yield 3
}
}
let numbers2 = Array.from(numbers1, (value) => value + 1)
console.log(numbers2) // [2,3,4]
# 为所有数组添加的新方法
find()
和findIndex
let numbers = [25, 30, 35, 40, 45, 50]
console.log(numbers.find(n => n > 33)) // 35
console.log(numbers.findIndex(n => n > 33)) // 2
// 如果是想找确切的一个值,还是建议用indexOf()和lastIndexOf()
console.log(numbers.indexOf(35)) // 2
find()
和findIndex()
可以对对象支持
let users = [{name: 'chfree', age: 18}, {name: 'test', age: 19}]
const user = users.find(u => u.name === 'chfree')
console.log(user) // {name: 'chfree', age: 18}
fill()
方法填充,fill(val, startIndex, endIndex)
let numbers = [1, 2, 3, 4]
numbers.file(1)
console.log(numbers) // [1, 1, 1, 1]
numbers.file(3, 2)
console.log(numbers) // [1, 1, 3, 3]
numbers.file(4, 1, 3)
console.log(numbers) // [1, 4, 4, 3]
copyWithin()
复制粘贴值,copyWithin(pasteIndex, copyStart, copyEnd)
let numbers = [1, 2, 3, 4]
numbers.copyWithin(2, 0)
console.log(numbers) // [1, 2, 1, 2]
let numbers = [1, 2, 3, 4]
numbers.copyWithin(2, 0, 1)
console.log(numbers) // [1, 2, 1, 4]
# 十一、Promise与异步编程
js
中是单线程事件队列模式,是无法真正实现多线程异步。Promise
是为了解决当a
函数执行完在执行b
函数的嵌套场景。
比如:示例1
// 示例1
method(function(err, contents){
if(err){
throw err
}
method(function(err, contents){
if(err){
throw err
}
method(function(err, contents){
if(err){
throw err
}
method(function(err, contents){
})
})
})
})
es6
中Promise
使用
let promise = new Promise(function(resolve, reject){
console.log('Promise')
resolve()
})
promise.then(function(){
console.log('resolve')
})
console.log('Hi')
//输出顺序
// Promise Hi resolve
Thenable
对象,拥有then
方法的对象就是Thenable
对象
let thenable = {
then: function(resolve, reject){
resolve(42)
}
}
let p1 = Promise.resolve(thenable)
p1.then(function(value){
console.log(value) // value
})
执行器错误
let promise = new Promise(function(resolve, reject){
throw new Error('this is error')
})
promise.catch(function(msg){
console.log(msg) // 'this is error'
})
// 以上等价于
let promise = new Promise(function(resolve, reject){
try{
throw new Error('this is error')
}catch(err){
reject(err)
}
})
# 串联Promise
对于以上并没有解决我们示例1中的问题。其实对于Promise
已经提供了,只是我们没用到而已。每一个Promise
进行then
或是catch
后,返回的对象还是Promise
let p1 = new Promise(function(resolve, reject){
resolve(42)
})
p1.then(function(value){
console.log(value)
}).then(function(){
console.log('finished')
throw new Error('is error')
}).catch(function(err){
console.log(err)
throw new Error('Boom')
}).catch(function(err){
console.log(err)
})
// 依次输出
// 42
// finished
// is error
// Boom
带返回值的操作
let p1 = new Promise(function(resolve, reject){
resolve(42)
})
p1.then(function(value){
console.log(value)
return value + 1
}).then(function(value){
console.log(value)
})
// 依次输出
// 42
// 43
在Promise
中返回Promise
let p1 = new Promise(function(resolve, reject){
resolve(42)
})
let p2 = new Promise(function(resolve, reject){
resolve(43)
})
p1.then(function(value){
console.log(value)
return p2
}).then(function(value){
console.log(value)
})
// 依次输出
// 42
// 43
# 响应多个Promise
Promise.all()
方法
let p1 = new Promise(function(resolve, reject){
resolve(42)
})
let p2 = new Promise(function(resolve, reject){
resolve(43)
})
let p3 = new Promise(function(resolve, reject){
resolve(44)
})
let p4 = Promise.all([p1,p2,p3])
p4.then(function(values){
console.log(Array.isArray(values)) // true
console.log(values[0]) // 42
console.log(values[0]) // 43
console.log(values[0]) // 44
})
该示例中,当p1\p2\p3
都处于完成状态时,p4
才完成。如果p1\p2\p3
中有一个拒绝返回了,那么p4
的catch
直接监听到这个拒绝返回,并不等待其他的处理状态。
Promise.race()
方法,与all
不同之处在于,race
中的Promise
,只要有一个处理完成,race()
返回的Promise
就是处理完成。如果其中一个返回了拒绝,那么race()直接返回拒绝,另外的只会执行,不会获取其返回值。
let p1 = new Promise(function(resolve, reject){
resolve(42)
})
let p2 = new Promise(function(resolve, reject){
resolve(43)
})
let p3 = new Promise(function(resolve, reject){
resolve(44)
})
let p4 = Promise.all([p1,p2,p3])
p4.then(function(value){
console.log(value) // 42
})
# 自Promise继承
class myPromise extends Promise {
success(resolve, reject){
return this.then(resolve, reject)
}
failure(reject){
return this.catch(reject)
}
}
let p1 = new Promise(function(resolve, reject){
resolve(42)
})
p1.success(function(value){
console.log(value) // 42
}).failure(function(err){
console.log(err)
})