2016-04-22 24 views
0

diesen Code vor:Proxies mit einfachen Arrays

app.mediaLibrary = new function MediaLibrary() { 
    var self = this; 

    self.media = new Proxy([], { 
     set(target, key, value) { 
      console.log(`Setting value ${key} as ${value}`) 
      if (!(value instanceof self.Media)) 
       throw new Error(`${value} is not instance of Media.`) 
      target[key] = value; 
      return true 
     }, 
     get (target, key) { 
      console.log(`Getting value ${key} as ${target[key]}`) 
      return target[key] 
     } 
    }); 

    self.Media = function Media(file, fileReader) { 
     this.src = fileReader.result; 
     this.file = file; 
    } 

    return self; 
} 

Immer, wenn ich app.mediaLibrary.media.push(new app.mediaLibrary.Media("", "")) In Konsole nennen sehe ich das:

Getting value push as function push() { [native code] } 
Getting value length as 0 
Setting value 0 as [object Object] 
Setting value length as 1 
Uncaught Error: 1 is not instance of Media.(…) 

Ich verstehe, warum ich das sehen, aber wie kann ich um ihn codieren ? Es scheint, dass meine Traps durch interne (push, length) sowie externe Anrufe ([0]=...) ausgelöst werden und ich nicht weiß, wie man zwischen ihnen unterscheidet. Irgendwelche Ideen?

+0

Ich verstehe Ihr Differenzierungsschema nicht. Wenn ein Anruf als "extern" betrachtet werden kann, ist es definitiv "Push". Es ruft wiederum '' get length'' und '' set0'' auf. Was genau qualifiziert den Zugang einer Eigenschaft als intern? – zeroflagL

+0

Ich habe nicht get Länge in meinem Code, so ist es interne/implizite Aufruf, nicht extern/explizit. –

+0

Nach dieser Definition würde jede Bibliothek in der Welt nur aus internen Aufrufen bestehen. Auch wenn jemand Ihren Code in einem Rückruf anruft. Das macht nicht viel Sinn. – zeroflagL

Antwort

1

Ich denke, du stellst die falsche Frage. Es handelt sich nicht um interne oder externe Aufrufe, sondern um das spezifische Objekt, das Sie als Proxy verwenden: Ein Array.

Sie könnten mit drei Bedingungen gehen:

  1. Länge kann auf alles eingestellt werden (nur das Array diese ohnehin behandelt)
  2. Numerische Eigenschaften können nur Medien Instanzen festgelegt werden.
  3. Alle anderen Eigenschaften sind tabu.

Sie könnten das so schreiben:

app.mediaLibrary = new function MediaLibrary() { 
    var self = this; 

    self.media = new Proxy([], { 
     set(target, key, value) { 
      console.log(`Setting value ${key} as ${value}`) 

      // Check if this is a valid array index 
      // See http://www.ecma-international.org/ecma-262/6.0/#sec-array-exotic-objects 
      if (String(key >>> 0) === key && (key >>> 0) != Math.pow(2, 32) - 1) { 
       if (!(value instanceof self.Media)) 
        throw new Error(`${value} is not instance of Media.`); 
      } else if(key !== 'length') { 
       throw new Error(`${key} may not be written to.`); 
      } 
      target[key] = value; 
      return true 
     }, 
     get (target, key) { 
      console.log(`Getting value ${key} as ${target[key]}`) 
      return target[key] 
     } 
    }); 

    self.Media = function Media(file, fileReader) { 
     this.src = fileReader.result; 
     this.file = file; 
    } 

    return self; 
} 

Wenn Sie wirklich zwischen .push und [0]=... unterscheiden müssen, dann nein, es kann nicht getan werden.

+0

Nun, Sie können '.push()' durch die Dekoration der zurückgegebenen Funktion im Getter unterscheiden, aber ich stimme zu, dass es nicht notwendig ist, wenn Sie die Eigenschaftsnamen wie Sie überprüfen. – Bergi

+0

Anstatt "Number (key) == key" zu verwenden, können Sie explizit nach 'String (Taste >>> 0) === Taste && (Taste >>> 0) suchen! = 4294967295' – Bergi

+0

@Bergi gut Idee mit den Dekorateuren, danke. Ich bin ein wenig fleckig auf den bitweisen Operatoren, würde es Ihnen etwas ausmachen, Ihren zweiten Teil zu erklären (die '>>>' scheint die Typkonvertierung und den Rundungstrick zu machen)? Ist '4294967295' der höchstmögliche Index? – nils