JavaScript快速入门:计算方法

您可能知道对象中的计算键,但您是否意识到可以使用方法简写来使用计算键?您可能永远都不想这样做。

const methodName = 'myMethod';
const computedKey = 'computed';

const myObj = {
  // Computed Property
  [computedKey]: 'It worked!',

  // 🤔 Is this a good idea? Probably not, no.
  // Computed property + Method shorthand
  [methodName]() {
    return this.computed;
  },
};

myObj.myMethod();
// 'It worked!'

历史课

在 JavaScript 的早期版本中,所有函数都是在全局范围内定义的。即使在那时,你也可以使用括号来获取或设置计算值,但我们想到的大多数功能都无法实现。

ECMAScript 3

ECMAScript 3 为我们带来了函数表达式和对象方法。您可以使用括号表示法来设置属性或方法。

// Old JavaScript.
var computedKey = 'computed';

var myObj = {
  // Key and function separately.
  myMethod: function () {
    return this.computed;
  },
};

myObj[computedKey] = 'It worked!';

myObj.myMethod();
// 'It worked!'

如果您愿意,可以使用动态方法名称,但它们必须在创建对象后定义。

myObj = {};
myObj[methodName] = function() {
  return this.computed;
};

ECMAScript 2015

ECMAScript 2015 引入了对象方法简写和计算属性。

// Exciting new JavaScript!
const computedKey = 'computed';

const myObj = {
  // Method shorthand
  myMethod() {
    return this.computed;
  },
  // Computed Property
  [computedKey]: 'It worked!',
};

myObj.myMethod();
// 'It worked!'

尽管 MDN 文章没有特别提到,但您可以将方法简写与计算属性名称混合使用,如文章开头所示。

问题

在某些极端情况下,这样做是有意义的,但一般来说,我们应该避免使用这种技术。当试图理解代码时,它会使查找方法变得非常困难,并降低代码编辑器支持的有效性,如 IntelliSense 和类型信息。

替代方案

哈希或代理可以很好地替代计算方法名称。看看我们可以实现这一点的一些方法,然后让我知道您认为哪种方法最适合您!

通用代码

下面的所有示例都是用顶部的这几行代码编写和测试的。如果您在控制台、REPL 或 RunJS 中运行这些示例,则可以看到它们可以正常工作。

const methodName = 'myMethod';
const computedKey = 'computed';

const myObj = {
  getComputed() {
    return this.computed;
  },
  [computedKey]: 'It worked!',
};

平原地图

用于匹配方法名称的简单字符串映射几乎不需要设置,但却使得调用方法变得有点困难。

const methodMap = {
  [methodName]: 'getComputed',
};

myObj[methodMap.myMethod]();
// 'It worked!';

边界映射

使用与原始对象绑定的方法的对象需要更多设置,但可以简化消费者的代码。

const methodMapBound = {
  [methodName]: myObj.getComputed.bind(myObj),
};

methodMapBound.myMethod();
// 'It worked!'

基本代理

Proxy 对象消除了大部分复杂性,因为您可以直接与代理交互。这使用 getter 中的静态检查来查找我们的计算属性。

const basicProxy = new Proxy(myObj, {
  get(target, prop, receiver) {
    if (prop === methodName) {
      return myObj.getComputed;
    }
    return Reflect.get(...arguments);
  },
});

basicProxy.myMethod();
// 'It worked!'

代理加地图

使用 Plain Mapping 示例中的属性名映射 a,我们可以支持任意数量的方法映射。如果我们愿意接受一点无限循环的风险,我们实际上可以支持多个间接引用!

const methodMap = {
  [methodName]: 'getComputed',
  'thisIsWild': methodName,
};

const methodProxy = new Proxy(myObj, {
  get(target, prop, receiver) {
    if (methodMap[prop]) {
      // Using receiver allows multiple indirection
      return receiver[methodMap[prop]];
    }
    return Reflect.get(...arguments);
  },
});

methodProxy.myMethod();
// 'It worked!'

methodProxy.thisIsWild();
// 'It worked!'

结论

我希望您喜欢这篇简短的文章,了解一些意想不到的和(希望)未使用的 JavaScript 功能!