JS以奇怪著称,其中几个重要‼️的概念值得牢记并弄清楚:
- Class类
- Object对象
- Plain Object:纯粹对象
- JSON
- Constructor Function构造函数
Class
要点:
- ES6原生支持Class写法
- ES6的Class跟Typescript的Class有所不同,TS增加了一些特性比如 constructor(public ...args)以及一整套完整的Class体系,Abstract Class,Private/Protected/Readonly等关键字。
- 在ES6之前,原始人类通过constructor function构造函数 new Func()来实现Class
- 不管是TS还是ES6,最终的JS代码的Class还是原型链prototype chain的继承
注意:
- Class只是蓝图,类似房子的图纸,不是房子;房子是基于图纸的实例instance
- 明白了这图纸的概念,方便理解 TS中 private,protected,和public的区别,比如private:只能在本图纸使用,protected:可以在复印的图纸中使用,并修改;public:在图纸和造好的房子(instance)中都可以修改。
Object
对象可以通过object literal快速粗暴实现
注意:
- object本身就是一个实例,不是图纸,而是instance
- 如果object可以直接生成,为何还用Class?因为Class可以被无限自由生成多个instance,重复利用
如何把Class转换为Plain Object?
1) Helper 函数
toJSON(proto) {
let jsoned = {};
let toConvert = proto || this;
Object.getOwnPropertyNames(toConvert).forEach((prop) => {
const val = toConvert[prop];
// don't include those
if (prop === 'toJSON' || prop === 'constructor') {
return;
}
if (typeof val === 'function') {
jsoned[prop] = val.bind(jsoned);
return;
}
jsoned[prop] = val;
});
const inherited = Object.getPrototypeOf(toConvert);
if (inherited !== null) {
Object.keys(this.toJSON(inherited)).forEach(key => {
if (!!jsoned[key] || key === 'constructor' || key === 'toJSON')
return;
if (typeof inherited[key] === 'function') {
jsoned[key] = inherited[key].bind(jsoned);
return;
}
jsoned[key] = inherited[key];
});
}
return jsoned;
}
2) 用工具 github.com/typestack/c…
JSON
JSON String
{
"name" : "john"
...
}
如何把JsonString转换为Object?
利用插件 marketplace.visualstudio.com/items?itemN…
构造函数 Function Constructor
利用闭包实现react的memo工厂函数
利用闭包实现jest的mock工厂函数
source: juejin.cn/post/708049…
利用Class实现Promise,即Promise是个Class,Promise的实例Instance才是Object (不是函数哦)
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class Promise{
constructor(executor){
this.state = PENDING
this.value = undefined
this.reason = undefined
//存放onFulfilled
this.onResolvedCallbacks = []
//存放onRejected
this.onRejectedCallbacks = []
const resolve = (value) => {
if (this.state === PENDING) {
this.value = value
this.state = FULFILLED
//promise实例状态改变后调用暂存的onFulfilled
this.onResolvedCallbacks.forEach(fn => fn())
}
}
const reject = (reason) => {
if (this.state === PENDING) {
this.reason = reason
this.state = REJECTED
//promise实例状态改变后调用的onRejected
this.onRejectedCallbacks.forEach(fn => fn())
}
}
try {
executor(resolve,reject)
} catch (error) {
reject(error)
}
}
then(onFulfilled, onRejected){
if (this.state === FULFILLED) {
onFulfilled(this.value)
}
if (this.state === REJECTED) {
onRejected(this.reason)
}
if (this.state === PENDING) {
//如果此时promise实例的状态还未确定,我们需要将onFulfilled与onRejected存起来,等到promise实例状态改变后再去调用
this.onResolvedCallbacks.push(() => {
onFulfilled(this.value)
})
this.onRejectedCallbacks.push(() => {
onRejected(this.reason)
})
}
}
}
Source: juejin.cn/post/702627…
总结:无论是Jest的mock还是Promise,原理都差不多,就是在构造函数(jest.fn()其实是可以用来 new jest.fn()的)和Class的内部,注入一个property(属性)来跟踪记录调用结果:jest的calls和Promise的state等!