ES6 Class对象研究

es6 class 的 new 实例和 es5 的 new 实例有什么区别?

ES6中(和ES5相比),classnew实例有以下特点:

  • class的构造参数必须是new来调用,不可以将其作为普通函数执行
  • es6class不存在变量提升
  • 最重要的是:es6 内部方法不可以枚举。es5 的prototype上的方法可以枚举。

为此我做了以下测试代码进行验证:

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
console.log(ES5Class()); // es5:可以直接作为函数运行
// console.log(new ES6Class()) // 会报错:不存在变量提升
function ES5Class() {
console.log("hello");
}
ES5Class.prototype.func = function() {
console.log("Hello world");
};
class ES6Class {
constructor() {}
func() {
console.log("Hello world");
}
}
let es5 = new ES5Class();
let es6 = new ES6Class();
// 推荐在循环对象属性的时候,使用for...in
// 在遍历数组的时候的时候,使用for...of
console.log("ES5 :");
for (let _ in es5) {
console.log(_);
}
// es6:不可枚举
console.log("ES6 :");
for (let _ in es6) {
console.log(_);
}

ES6 class 实现状态函数(static变量)

在C语言中,使用 static 关键字来增加函数变量的生命周期(不是范围),使其超出函数的调用范围。
在JS/TS中,也可以实现。通过class

1
2
3
4
5
6
7
8
9
const { called } = new (class {
count = 0;
called = () => {
this.count++;
console.log("Called: ", this.count);
};
})();
called(); called();

也可以用闭包:

1
2
3
4
5
6
7
8
9
10
11
12
const { called: called2 } = (() => {
var count = 0;
return {
called: () => {
count++;
console.log("Called: ", count);
}
};
})();
called2();
called2();

ES6 Class怎么把Class变成Iterator?

使用 class 的 name属性 + generator 方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//定义类
class Foo {
constructor(...args) {
this.args = args;
}
*[Symbol.iterator]() {
for (let arg of this.args) {
yield arg;
}
}
}
var foo = new Foo(1, 2, 3);
for (let x of foo) {
console.log(x);
}

ES6 Class 如何解决 this 指向问题?

问题描述:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Logger {
constructor(name) {
this.name = name;
}

print() {
console.log(this.name);
}
}
const logger = new Logger('sysdesign.fun');
const { print } = logger;
print(); // this 指针丢失。TypeError: Cannot read property 'name' of undefined

解决1: 构建函数中,绑定 this

1
2
3
4
5
6
7
class Logger {
constructor(name) {
this.name = name;

this.print = this.print.bind(this);
}
}

解决2: 使用 Proxy 自动绑定 this

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
function proxyClsThis(instance) {
const cache = new WeakMap();

const proxy = new Proxy(instance, {
get(target, propKey) {
const val = Reflect.get(target, propKey);
if (typeof val !== 'function') {
return val;
}
// return val.bind(target);
// 可以直接返回,但是用上缓存,性能更好;同时 WeakMap 能防止内存泄漏;注意 WeakMap 的 key 设计
if (!cache.has(val)) {
cache.set(val, val.bind(target));
}
return cache.get(val);
},
});

return proxy;
}

const logger = proxyClsThis(new Logger('sysdesign.fun'));
const { print } = logger;
print();

ES6 Class 如何解决私有属性问题?

准确来说,对象的操作,都可以通过Proxy来实现。具体可以见 [[ES6的Proxy,以及Reflect]] ,或者参考前面的解决2方案。

参考/推荐《JavaScript 创建对象—从 es5 到 es6》