ES6类上的自定义类似数组的getter

时间:2016-12-26 22:22:26

标签: javascript arrays class constructor ecmascript-6

我想创建一个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?

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

它是否可能,如果可能,最好的方法是什么?

3 个答案:

答案 0 :(得分:1)

是的,您正在寻找代理:

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?')

答案 1 :(得分:0)

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

&#13;
&#13;
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"
&#13;
&#13;
&#13;

get陷阱中返回的任何内容都是评估proxy[index]的结果,例如,您可以返回Reflect.get(target, property)而不是返回{{1}}。

答案 2 :(得分:0)

在阅读了这些答案并挖掘了更多内容后,我设法使用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

感谢所有贡献的人。

快乐编码:)