Live Note

Remain optimistic

Subtype Polymorphism

通过类继承和方法重写,子类可以提供与父类方法相同的接口,但实现不同的行为。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class Animal {
makeSound(): void {
console.log("Some generic animal sound")
}
}

class Dog extends Animal {
makeSound(): void {
console.log("Woof!")
}
}

class Cat extends Animal {
makeSound(): void {
console.log("Meow!")
}
}

function makeAnimalSound(animal: Animal): void {
animal.makeSound()
}

const dog = new Dog()
const cat = new Cat()

makeAnimalSound(dog) // Woof!
makeAnimalSound(cat) // Meow!

key points:

  • 类型兼容性:TypeScript 的类型系统允许子类实例赋值给父类类型的变量(向上转型)。
  • 运行时行为:实际执行的方法取决于对象的运行时类型,而不是声明时的类型。
Read more »

Promise A+ 规范

  1. promise:是一个拥有then方法的对象或函数,其行为符合本规范。
  2. thenable:是一个定义了then方法的对象或函数。这个主要是用来兼容一些老的Promise实现,只要一个Promise实现是thenable,也就是拥有then方法的,就可以跟Promises/A+
    兼容。
  3. value:指reslove出来的值,可以是任何合法的 JS 值(包括 undefined , thenablepromise等)
  4. exception:异常,在Promise里面用throw抛出来的值
  5. reason:拒绝原因,是reject里面传的参数,表示reject的原因

Promise Status

  1. pending: 一个promiseresolve或者reject前就处于这个状态。
  2. fulfilled: 一个promiseresolve后就处于fulfilled状态,这个状态不能再改变,而且必须拥有一个不可变的值(value)。
  3. rejected: 一个promisereject后就处于rejected状态,这个状态也不能再改变,而且必须拥有一个不可变的拒绝原因(reason)。

thenable

1
promsie.then(onFulfilled, onRejected)

Optional parameters

  1. 如果 onFulfilled 不是函数,其必须被忽略
  2. 如果 onRejected 不是函数,其必须被忽略

onFulfilled

如果 onFulfilled 是函数:

  1. promise 执行结束后其必须被调用,其第一个参数为 promise 的终值value
  2. promise 执行结束前其不可被调用
  3. 其调用次数不可超过一次

onRejected

如果 onRejected 是函数:

  1. promise 被拒绝执行后其必须被调用,其第一个参数为 promise 的据因reason
  2. promise 被拒绝执行前其不可被调用
  3. 其调用次数不可超过一次

then

then 方法可以被同一个 promise 调用多次

  1. promise 成功执行时,所有 onFulfilled 需按照其注册顺序依次回调
  2. promise 被拒绝执行时,所有的 onRejected 需按照其注册顺序依次回调

Return

then 方法必须返回一个 promise 对象。

1
promise2 = promise1.then(onFulfilled, onRejected)
  1. 如果 onFulfilled 或者 onRejected 返回一个值 x ,则运行 Promise 解决过程:[[Resolve]](promise2, x)
  2. 如果 onFulfilled 或者 onRejected 抛出一个异常 e ,则 promise2 必须拒绝执行,并返回拒因 e
  3. 如果 onFulfilled 不是函数且 promise1 成功执行, promise2 必须成功执行并返回相同的值
  4. 如果 onRejected 不是函数且 promise1 拒绝执行, promise2 必须拒绝执行并返回相同的据因

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
var PENDING = "pending"
var FULFILLED = "fulfilled"
var REJECTED = "rejected"

function Promise(fn) {
this.status = PENDING // initial status
this.value = null // initial value
this.reason = null // initial reason
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []

var _this = this

function resolve(value) {
if (_this.status === PENDING) {
_this.status = FULFILLED
_this.value = value

_this.onFulfilledCallbacks.forEach((i) => i(_this.value))
}
}

function reject(reason) {
if (_this.status === PENDING) {
_this.status = REJECTED
_this.reason = reason

_this.onRejectedCallbacks.forEach((i) => i(_this.reason))
}
}

try {
fn(resolve, reject)
} catch (e) {
reject(e)
}
}

function resolvePromise(promise, x, resolve, reject) {
if (promise === x) {
reject(new TypeError("The promise and the return value are the same"))
}

if (x instanceof Promise) {
x.then(function (y) {
resolvePromise(promise, y, resolve, reject)
}, reject)
} else if (typeof x === "object" || typeof x === "function") {
if (x === null) {
return resolve(x)
}

try {
var then = x.then
} catch (e) {
return reject(e)
}

if (typeof then === "function") {
var called = false

try {
then.call(
x,
function (y) {
if (called) return
called = true
resolvePromise(promise, y, resolve, reject)
},
function (r) {
if (called) return
called = true
reject(r)
}
)
} catch (e) {
if (called) return

reject(e)
}
} else {
resolve(x)
}
} else {
resolve(x)
}
}

Promise.prototype.then = function (onFulfilled, onRejected) {
var checkOnFulfilled = onFulfilled
if (typeof onFulfilled !== "function") {
checkOnFulfilled = function (value) {
return value
}
}

var checkOnRejected = onRejected
if (typeof onRejected !== "function") {
checkOnRejected = function (reason) {
throw reason
}
}

var _this = this

if (this.status === FULFILLED) {
// 如果前面的 promise 抛出异常,后面的必须拒绝执行
var promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
if (typeof onFulfilled !== "function") {
resolve(_this.value)
} else {
var x = checkOnFulfilled(_this.value)
resolvePromise(promise2, x, resolve, reject)
}
} catch (e) {
reject(e)
}
}, 0)
})

return promise2
}

if (this.status === REJECTED) {
var promise2 = new Promise(function (resolve, reject) {
setTimeout(function () {
try {
if (typeof onRejected !== "function") {
reject(_this.reason)
} else {
var x = checkOnRejected(_this.reason)
resolvePromise(promise2, x, resolve, reject)
}
} catch (e) {
reject(e)
}
}, 0)
})

return promise2
}

if (this.status === PENDING) {
var promise2 = new Promise(function (resolve, reject) {
_this.onFulfilledCallbacks.push(function () {
setTimeout(function () {
try {
if (typeof onFulfilled !== "function") {
resolve(_this.value)
} else {
var x = checkOnFulfilled(_this.value)
resolvePromise(promise2, x, resolve, reject)
}
} catch (e) {
reject(e)
}
}, 0)
})

_this.onRejectedCallbacks.push(function () {
setTimeout(function () {
try {
if (typeof onRejected !== "function") {
reject(_this.reason)
} else {
var x = checkOnRejected(_this.reason)
resolvePromise(promise2, x, resolve, reject)
}
} catch (e) {
reject(e)
}
}, 0)
})
})

return promise2
}
}

Promise.resolve = function (parameter) {
if (parameter instanceof Promise) {
return parameter
}

return new Promise(function (resolve) {
resolve(parameter)
})
}

Promise.reject = function (reason) {
return new Promise(function (resolve, reject) {
reject(reason)
})
}

Promise.all = function (promises) {
return new Promise(function (resolve, reject) {
var count = 0
var result = []
var len = promises.length

if (length === 0) {
return resolve(result)
}

promises.forEach(function (promise, index) {
Promise.resolve(promise).then(
function (value) {
count++
result[index] = value

if (count === len) {
resolve(result)
}
},
function (reason) {
reject(reason)
}
)
})
})
}

Promise.race = function (promises) {
return new Promise(function (resolve, reject) {
var len = promises.length

if (length === 0) {
return resolve()
} else {
for (var i = 0; i < len; i++) {
Promise.resolve(promises[i]).then(
function (value) {
return resolve(value)
},
function (reason) {
return reject(reason)
}
)
}
}
})
}

Promise.catch = function (onRejected) {
this.then(null, onRejected)
}

Promise.finally = function (fn) {
return this.then(
function (value) {
return Promise.resolve(fn()).then(function () {
return value
})
},
function (error) {
return Promise.resolve(fn()).then(function () {
throw error
})
}
)
}

Promise.allSettled = function (promises) {
return new Promise(function (resolve) {
var len = promises.length
var result = []
var count = 0

if (len === 0) {
resolve(result)
} else {
for (let i = 0; i < len; i++) {
;(function (i) {
var current = Promise.resolve(promises[i])

current.then(
function (value) {
count++
result[i] = {
status: "fulfilled",
value,
}

if (count === len) {
return resolve(result)
}
},
function (reason) {
count++
result[i] = {
status: "rejected",
reason,
}

if (count === len) {
return resolve(result)
}
}
)
})(i)
}
}
})
}

// for promises-aplus-tests test
Promise.deferred = function () {
var result = {}
result.promise = new Promise(function (resolve, reject) {
result.resolve = resolve
result.reject = reject
})

return result
}

module.exports = Promise

Promise 的特点

  1. 对象的状态不受外界影响。Promise 对象代表一个异步操作,有三种状态:Pending(进行中)、Fulfilled(已成功)、Rejected(已失败)。只有异步操作的结果可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。
  2. 一旦状态改变就不会再变,任何时候得到的都是这个结果。Promise 对象的状态改变只有两个可能:从 Pending 变为 Fulfilled,从 Pending 变为 Rejected。只要这两种情况发生,这时就成为 resolve。就算改变已经发生,再对 Promise 对象添加回调函数,也会立即得到这个结果。与 Event 完全不同,Event 一旦错过再监听是得不到结果的。

基本用法

1
2
3
4
5
6
7
8
9
var promise = new Promise(function (resolve, reject) {
//some code

if (/*异步操作成功*/) {
resolve(value);
} else {
reject(error);
}
})
Read more »

Proxy 用于修改某些操作的默认行为,等同与在语言层面做出修改,属于一种 meta programming。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
let obj = new Proxy(
{},
{
get: function (target, key, receiver) {
console.log(`getting ${key}`)
return Reflect.get(target, key, receiver)
},
set: function (target, key, receiver) {
console.log(`setting ${key}`)
return Reflect.set(target, key, receiver)
},
}
)
obj.count = 1
//setting count
obj.count
//getting count
Read more »

进制表示

0b(0B)表示二进制,0o(0O)表示八进制

Number.isFinite()、Number.isNaN()

Number.isFinite 用来检查一个数值是否为有限的。

1
2
3
4
5
6
Number.isFinite(NaN) //false
Number.isFinite(Infinity) //false
Number.isFinite(-Infinity) //false
Number.isFinite("15") //false
Number.isFinite("foo") //false
Number.isFinite(true) //false
Read more »