2016-12-26 60 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

感謝大家誰貢獻。

快樂編碼:)