javascript 和记忆吸气剂
javascript and memoized getters
This article describe getters。它有一个部分“
智能/自我覆盖/懒惰的吸气剂”
我不清楚,默认情况下是 getter 'memoized' 还是我应该自己实现此功能
例如
class Foo() {
get boo() {
this._boo = this._boo || new Boo();
return this._boo;
}
}
或者我可以只写:
class Foo() {
get boo() {
return new Boo();
}
}
得到相同的结果?
不,JavaScript 中没有对 memoized getter 的语言级支持。在您的第二个示例中,每次访问 boo
时都会创建一个新对象。
考虑这段代码:
class Person {
static get SHORT() { return 0; }//rvalue
}
对比
class Person {}
Person.SHORT = 0;//lvalue
虽然两者return结果相同,但后者实际上更快(因为它避免了函数调用开销);尽管 js 引擎可以进行优化,使一个无效。
那篇文章最有趣的部分是 Smart / self-overwriting / lazy getters,它提供了这种技术:
<del>
class Foo {
get boo() {
delete this.boo;
return this.boo = new Boo();
}
}
</del>
有了这个,您的 Foo
对象就不会经历创建它们的 boo
属性的麻烦,直到您提出要求。然后它被创建一次并进一步请求它 return 同一个对象。如果 new Boo()
在某种程度上需要大量资源来创建并且通常不需要,那么这是有道理的。
理论上,您可以扩展它以允许您删除当前版本并在下次访问时重新创建它。但那是更多的代码,而且可能是一个相当罕见的需求。
更新
A 正确地指出上述技术虽然适用于普通对象,但不适用于 类。
这是一个有效的变体:
class Boo {
static counter = 0
constructor () {
this.x = ++Boo.counter
console .log (`creating Boo(${this.x})`)
}
}
class Foo {
get boo () {
Object .defineProperty (
this,
"boo",
{ value: new Boo(), writable: false}
)
return this .boo;
}
}
const f = new Foo()
console .log (f.boo)
console .log (f.boo) // no 'creating Boo' log, Boo constructor only created once
您可以随意添加备忘,例如
未记忆,
class NonMemoized {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this.prefix + Math.random().toString();
}
}
let nonMemoized = new NonMemoized('new number each time ');
console.log(nonMemoized.myFunc);
console.log(nonMemoized.myFunc);
记忆化,当你想创建一个对象一次并且总是 return 同一个对象时很好(但不想在构造函数中创建,因为可能没有必要一直或其他原因)
class MemoizedManually {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this._myFunc_ = this._myFunc_ || this.prefix + Math.random().toString();
}
}
let memoizedManually = new MemoizedManually('same number ');
console.log(memoizedManually.myFunc);
console.log(memoizedManually.myFunc);
最后,如果你有一堆函数你想记住但不想在每个函数中重复 this.x = this.x || something computation
(你真的不应该重复,因为它不是真正的工作myFunc
自我记忆:
class Memoized {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this.prefix + Math.random().toString();
}
}
const memoizeGetter = (clazz, functionName) => {
let func = Object.getOwnPropertyDescriptor(clazz.prototype, functionName);
let cacheKey = `_${functionName}-cache_`;
Object.defineProperty(clazz.prototype, functionName, {
get: function () {
return this[cacheKey] = this[cacheKey] || func.get.call(this);
}
});
};
memoizeGetter(Memoized, 'myFunc');
let memoized = new Memoized('also same number ');
console.log(memoized.myFunc);
console.log(memoized.myFunc);
getter 的好处是它们不接受参数,因此您不必担心 ...args
,但需要担心绑定 this
This article describe getters。它有一个部分“ 智能/自我覆盖/懒惰的吸气剂” 我不清楚,默认情况下是 getter 'memoized' 还是我应该自己实现此功能
例如
class Foo() {
get boo() {
this._boo = this._boo || new Boo();
return this._boo;
}
}
或者我可以只写:
class Foo() {
get boo() {
return new Boo();
}
}
得到相同的结果?
不,JavaScript 中没有对 memoized getter 的语言级支持。在您的第二个示例中,每次访问 boo
时都会创建一个新对象。
考虑这段代码:
class Person {
static get SHORT() { return 0; }//rvalue
}
对比
class Person {}
Person.SHORT = 0;//lvalue
虽然两者return结果相同,但后者实际上更快(因为它避免了函数调用开销);尽管 js 引擎可以进行优化,使一个无效。
那篇文章最有趣的部分是 Smart / self-overwriting / lazy getters,它提供了这种技术:
<del>
class Foo {
get boo() {
delete this.boo;
return this.boo = new Boo();
}
}
</del>
有了这个,您的 Foo
对象就不会经历创建它们的 boo
属性的麻烦,直到您提出要求。然后它被创建一次并进一步请求它 return 同一个对象。如果 new Boo()
在某种程度上需要大量资源来创建并且通常不需要,那么这是有道理的。
理论上,您可以扩展它以允许您删除当前版本并在下次访问时重新创建它。但那是更多的代码,而且可能是一个相当罕见的需求。
更新
A
这是一个有效的变体:
class Boo {
static counter = 0
constructor () {
this.x = ++Boo.counter
console .log (`creating Boo(${this.x})`)
}
}
class Foo {
get boo () {
Object .defineProperty (
this,
"boo",
{ value: new Boo(), writable: false}
)
return this .boo;
}
}
const f = new Foo()
console .log (f.boo)
console .log (f.boo) // no 'creating Boo' log, Boo constructor only created once
您可以随意添加备忘,例如
未记忆,
class NonMemoized {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this.prefix + Math.random().toString();
}
}
let nonMemoized = new NonMemoized('new number each time ');
console.log(nonMemoized.myFunc);
console.log(nonMemoized.myFunc);
记忆化,当你想创建一个对象一次并且总是 return 同一个对象时很好(但不想在构造函数中创建,因为可能没有必要一直或其他原因)
class MemoizedManually {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this._myFunc_ = this._myFunc_ || this.prefix + Math.random().toString();
}
}
let memoizedManually = new MemoizedManually('same number ');
console.log(memoizedManually.myFunc);
console.log(memoizedManually.myFunc);
最后,如果你有一堆函数你想记住但不想在每个函数中重复 this.x = this.x || something computation
(你真的不应该重复,因为它不是真正的工作myFunc
自我记忆:
class Memoized {
constructor(prefix) {
this.prefix = prefix;
}
get myFunc() {
return this.prefix + Math.random().toString();
}
}
const memoizeGetter = (clazz, functionName) => {
let func = Object.getOwnPropertyDescriptor(clazz.prototype, functionName);
let cacheKey = `_${functionName}-cache_`;
Object.defineProperty(clazz.prototype, functionName, {
get: function () {
return this[cacheKey] = this[cacheKey] || func.get.call(this);
}
});
};
memoizeGetter(Memoized, 'myFunc');
let memoized = new Memoized('also same number ');
console.log(memoized.myFunc);
console.log(memoized.myFunc);
getter 的好处是它们不接受参数,因此您不必担心 ...args
,但需要担心绑定 this