【问题标题】:Custom Array-like getter on ES6 classES6 类上的自定义类数组 getter
【发布时间】:2017-05-11 05:59:33
【问题描述】:

我想创建一个Class,它也是常规Array 的包装器,但是我希望在通过索引引用类实例上的项目时发生一些自定义行为。

演示我想要实现的目标:

class Custom {
    constructor (arr) {
        this.arr = arr;
    }
    method (str) {
        this.arr.forEach(item => {
            console.log(`${item} ${str}`);
        })
    }
    [Magic.here] () {
        // this part should invoke the constructor of this class with a single item of the array passed into it as an array of one as argument.
    }
}

let c = new Custom(['something', 'other thing', 'hello?']);

c[1].method('exists?') // -> other thing exists?

现在,我不完全确定这是可能的。我确实设法通过extending Array 提出了我自己的不太好的解决方案。 Proxy 也出现在我的脑海中,但无法找到可行的解决方案。

有没有可能,如果有,最好的方法是什么?

【问题讨论】:

  • 您似乎将数组周围的包装器与元素周围的包装器混合在一起。是c.method() 还是c[1].method()?他们绝对应该有不同的类。
  • 如果您阅读了我的代码演示的[Magic.here] 位中的推荐,您会意识到我确实想从getter 调用构造函数,如下所示:c[0] 返回一个@987654331 @ 基本上,然后可以单独调用 method
  • 是的,但是从构造函数的参数名称和使用数组的示例调用中,我意识到Custom 是数组包装器的构造函数,而不是要从 getter 调用的元素的构造函数.

标签: javascript arrays class constructor ecmascript-6


【解决方案1】:

Proxy 确实是您正在寻找的。看看这个例子:

const array = ['a', 'b', 'c'];
const proxy = new Proxy(array, {
  get(target, property) {
    console.log(`Proxy get trap, property ${property}`);
    return Reflect.get(target, property);
  },
});

proxy[1]; // logs "Proxy get trap, property 1"

无论您在get 陷阱中返回什么,都将是评估proxy[index] 的结果,因此例如,您可以返回一些对象,而不是返回Reflect.get(target, property)

【讨论】:

    【解决方案2】:

    是的,您正在寻找代理:

    const isArrayIndex = str => (str >>> 0) + '' === str && str < 4294967295;
    const arrayCustomizer = {
        get(target, property, receiver) {
            var el = Reflect.get(target, property, receiver);
            if (isArrayIndex(property) && el != null)
                el = new Custom(el);
            return el;
        }
    }
    class Custom {
        constructor(v) {
            this.value = v;
        }
        valueOf() {
            return this.value;
        }
        method(arg) {
            console.log(this.value + " " + arg.replace("?", "!"));
        }
    }
    
    let c = new Proxy(['something', 'other thing', 'hello?'], arrayCustomizer);
    c[1].method('exists?')
    

    【讨论】:

    • 嘿!我设法抽象出您的方法并得到了一个工作示例,但是...当我创建 Proxy 时,它会隐藏主实例中的所有类属性,例如 c.method() 将不再存在。我目前对Proxy 的了解有限,但我会接受你的回答,如果你也能给我解决上述问题,我将永远感激不尽。 :)
    • c 只是一个数组,它从来没有 .method 属性(我不明白为什么需要它)。只有它的元素是Custom 的实例。
    【解决方案3】:

    在阅读了这些答案并进一步挖掘之后,我设法提出了一个完整的解决方案,使用 Proxy。我在这里发布此内容,以防互联网上有人提出像我这样的疯狂想法并想要一个简单的解决方案。

    为了简单说明,我对代码进行了注释:

    /**
     * The class I want to proxy on
     */
    
    class Random {
      constructor (arr) {this.arr=arr}
      method () {this.arr.forEach(el=>{console.log(el)})}
    }
    
    // Creating a separate function for initializing the class. This will have to be used instead of the regular class' constructor if we want to use the proxy as well.
    
    function init (arr) {
      // Creating a new instance of random class based on arr, passing it into proxy
      var p = new Proxy(new Random(arr), {
        // Modifying the get function on handler
        get: function (target, name) {
          // Checking if the name is a numeric reference
          if (typeof name === 'string' && /^-?\d+$/.test(name)) {
            // ... it is, so we call init with the selected item in the array on our class object
            let r = init([target.arr[name]]);
            // finally we return the new proxy from init
            return r;
          }
          else {
            // otherwise we are looking at a direct reference, maybe to a method or scope variable, like random.method()
            return target[name]
          }
        }
      })
      // we return the proxy
      return p;
    }
    
    let random = init(['hello', 'amazing', 'world'])
    
    console.log(random[0]); // proxy reference to array of hello
    console.log(random[1]); // proxy reference to array of amazing
    
    random.method(); // logs out all 3 items of array
    random[2].method(); // logs out third item

    感谢所有做出贡献的人。

    编码愉快:)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-02-26
      • 2017-07-07
      • 2017-05-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多