2016-12-26 54 views
1

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

演示我想达到的目标:

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 ing ArrayProxy也进入了我的想法,但不能得到一个工作解决方案。

这是可能的,如果是这样,最好的方法是什么?

+1

你似乎正在围绕着元素周围的包装混合包装。它会是'c.method()'或'c [1] .method()'?他们绝对应该有不同的阶级。 – Bergi

+0

如果你阅读了我的代码演示中的[Magic.here]'部分的推荐内容,你会意识到我确实想从getter调用构造函数,就像这样:'c [0]''returns a'new自定义(this.arr [0])'基本上,然后可以单独调用'method'。 –

+0

是的,但从构造函数的参数名称和数组的示例调用我意识到'Custom'是数组包装器的构造函数,而不是从getter调用的元素的构造函数。 – Bergi

回答

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

嘿!我设法抽象出你的方法,并得到了一个工作的例子,但是......当我创建这个'Proxy'时,它隐藏了主实例的所有类属性,就像'c.method()'将不再存在。我目前对'Proxy'的知识是有限的,但我会接受你的答案,如果你能给我一个解决上述问题的方法,我将永远感激。 :) –

+0

'c'只是一个数组,它从来没有'.method'属性(我不明白为什么它需要)。只有它的元素是'Custom'的实例。 – Bergi

0

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)你可以返回一些对象。

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

感谢大家谁贡献。

快乐编码:)