繁体   English   中英

javascript 和记忆化的 getter

[英]javascript and memoized getters

这篇文章描述了 getter 它有一个部分“智能/自我覆盖/懒惰的getter”我不清楚,默认情况下getter是“记忆化”还是我应该自己实现这个功能

例如

class Foo() {
  get boo() {
    this._boo = this._boo || new Boo(); 
    return this._boo;  
  }
}

或者我可以写:

class Foo() {
  get boo() {
    return new Boo();  
  }
}

有相同的结果?

那篇文章中最有趣的一点是Smart / self-overwriting / lazy getters ,它提供了这种技术:

 class Foo { get boo() { delete this.boo; return this.boo = new Boo(); } } 

有了这个,你的Foo对象不会经历创建它们的boo属性的麻烦,直到你要求它。 然后它被创建一次,对它的进一步请求只是返回相同的对象。 如果new Boo()以某种方式创建资源密集型并且通常不需要,那么这是有道理的。

理论上,您可以扩展它以允许您删除当前版本并在下次访问时重新创建它。 但这需要更多的代码,而且可能是相当罕见的需求。

更新

vrugtehagel评论正确地指出,上述技术虽然适用于普通对象,但不适用于类。

这是一个有效的变体:

 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

不,JavaScript 中没有对记忆化 getter 的语言级支持。 在您的第二个示例中,每次访问boo时都会创建一个新对象。

您可以自由添加备忘录,例如

非记忆,

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);

记忆化,非常适合当您想创建一个对象并始终返回相同的对象时(但不想在构造函数中创建,因为可能没有必要一直或其他原因)

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 每个函数中的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

考虑这个代码:

class Person {
    static get SHORT() { return 0; }//rvalue
}

class Person {}
Person.SHORT = 0;//lvalue

虽然两者都返回相同的结果,但后者实际上更快(因为它避免了函数调用开销); 尽管 js 引擎可以进行优化,使一个无效。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM