JS class 中的 static 使用及问题解析
最近业务代码中在尝试使用类的方法在做代码复用,踩到一个关于 static 的小坑。
描述
demo 代码如下:
class Test {
static defaultOptions = {
arr: []
}
constructor(options) {
this.data = Object.assign(Test.defaultOptions, options)
}
add(num) {
this.data.arr.push(num)
}
getArr() {
return this.data.arr
}
}
const test1 = new Test()
test1.add(1)
const test2 = new Test()
console.log(JSON.stringify(test2.getArr()))
这段代码按照正常的逻辑来讲,重新实例化了对象,那么应该是输出一个空数组,但是在实际的运行过程中会发现,其实输出的是 [1] ,那这里问题出在哪里呢?
分析
static 关键字定义了静态方法或字段,或静态初始化块。静态属性不能在类的实例上直接访问。相反,它们是在类本身上被访问的。
这是 MDN 官网对 class 上 static 关键字的定义,我们在使用的过程用 static 关键字声明变量来存储默认值是没问题的,但这个问题出在我合并默认值 defaultOptions 和传参 options 的过程中,因为我在初始化示例的过程中没有传值,所以本质上 data.arr 指向的就是 defaultOptions.arr 而这个值是存在于类本身的,并不是在每次初始化示例的时候重置,所有就会导致上述的问题。
解决
既然找到了问题的所在,那么解决问题就很快了,可以用使用深拷贝直接在 Object.assign 的时候使用拷贝值,也可以使用工厂函数来生成默认值,确保每一份实例都是一个独立的默认值。
class Test {
static get defaultOptions() {
return {
arr: []
};
}
constructor(options = {}) {
this.data = Object.assign({}, Test.defaultOptions, options);
}
add(num) {
this.data.arr.push(num);
}
getData() {
return this.data;
}
}
const test1 = new Test();
test1.add(1);
const test2 = new Test();
console.log(JSON.stringify(test2.getData())); // 输出: {"arr":[]}