2010-12-31 11 views
8

Hallo, gibt es eine Möglichkeit, die '.' (Punkt) und [] -Operator in Javascript zu überladen. Wenn ich also obj.Name oder obj ['Name'] sage, sollte es eine gemeinsame Methode in der obj-Klasse aufrufen, indem Name als Argument übergeben wird. Die ähnliche Funktionalität, die in Python mit der Property-Methode zur Verfügung steht. Aber hier möchte ich den ".Name" als Argument für die gemeinsame Methode übergeben.Javascript überladen dot

wie dieses ..

function Data(){ 
    this.getValue(name){ 
     return '...' 
    } 
} 

data = new Data() 
name = data.Name 
name = data['Name'] 
//both should call data.getValue() 
+0

FYI wie diese mit ein wenig regexp getan werden, die Dinge haben sich geändert, seit die Frage gestellt wurde. Ich habe [meine Antwort aktualisiert] (http://stackoverflow.com/a/4569315/157247). –

Antwort

1

Nö, können Sie es nicht in JavaScript überlasten oder ersetzen. Ich wünschte, ich hätte eine umfassendere/informativere Antwort für Sie ... aber es ist einfach nicht möglich, ich denke, es war nie nötig, die Fähigkeit hinzuzufügen.

+0

@ T.J. - Vertrauen Sie mir, ein * Viel * mehr meiner Zeit wird sehr bald in Anspruch genommen werden;) –

12

Antwort 2010: (unten für ein 2013-Update sehen)

Nein, Sie können nicht Eigenschaftsnamen Lookups auf Ihre eigene Funktion umleiten.

Jedoch, ab ECMAScript5 können Sie Eigenschaften mit "Getters" und "Setter" definieren. Dies ist ein neues Feature, das noch nicht weit verbreitet ist, aber wenn es ist, wird es etwas tun vage ähnlich. Dies ist in einigen Teilen von the spec abgedeckt. Wenn Sie also alle Ihre Eigenschaften auf diese Weise definiert haben und dann die eigentliche Anfrage an Ihre zentrale getValue-Funktion gesendet haben, würden Sie weitgehend das erreichen, was Sie wollten. Irgendwann mal. :-) Außer dass es nicht getValue für eine Eigenschaft aufrufen wird, die nicht existiert.


Antwort im Jahr 2013:

Das wird sich bald ändern (und es already has für up-to-date Firefox-Benutzer): ECMAScript 6. Auflage wird Proxies haben. Sie sind in der draft specification und auch auf this page definiert (aber die Spezifikationen Entwürfe haben Vorrang).

Mithilfe von Proxies können Sie Objekte erstellen, bei denen es sich um echte Proxies (Fassaden) für andere Objekte handelt. Hier ist ein einfaches Beispiel, das keinen Eigenschaftswert stellt sich die Strings für alle Kappen auf Abruf ist:

var original = {"foo": "bar"}; 
var proxy = new Proxy(original, { 
    get: function(target, name, receiver) { 
     var rv = target[name]; 
     if (typeof rv === "string") { 
      rv = rv.toUpperCase(); 
     } 
     return rv; 
    } 
}); 

console.log("original.foo = " + original.foo); // "bar" 
console.log("proxy.foo = " + proxy.foo);  // "BAR" 

Live Example | Source

Operationen, die Sie nicht überschreiben, haben ihr Standardverhalten. Im obigen Beispiel überschreiben wir nur get, aber es gibt eine ganze Liste von Operationen, in die Sie sich einklinken können.

In der get Argumente Liste der Handler-Funktion:

  • target ist das Objekt proxied wird (original, in unserem Fall).
  • name ist (natürlich) der Name der Eigenschaft, die abgerufen wird.
  • receiver ist entweder der Proxy selbst oder etwas, das davon erbt.In unserem Fall ist ===proxy, aber wenn proxy als Prototyp verwendet wurde, könnte ein nachkommendes Objekt sein, daher ist es auf der Funktionssignatur (aber am Ende, so können Sie es leicht auslassen, wenn, wie bei unseren Beispiel oben verwenden Sie es nicht wirklich).

Auf diese Weise können Sie ein Objekt mit dem Catch-All erstellen Getter und Setter-Funktion, die Sie wollen:

var obj = new Proxy({}, { 
    get: function(target, name) { 
     if (!(name in target)) { 
      console.log("Getting non-existant property '" + name + "'"); 
      return undefined; 
     } 
     return target[name]; 
    }, 
    set: function(target, name, value) { 
     if (!(name in target)) { 
      console.log("Setting non-existant property '" + name + "', initial value: " + value); 
     } 
     target[name] = value; 
    } 
}); 

console.log("[before] obj.foo = " + obj.foo); 
obj.foo = "bar"; 
console.log("[after] obj.foo = " + obj.foo); 

Live Example | Source(Beachten Sie, wie ich receiver von den Funktionen verlassen haben, da wir es nicht verwenden receiver auf set eine optionale vierte arg..)

Der Ausgang des oben ist:

Getting non-existant property 'foo' 
[before] obj.foo = undefined 
Setting non-existant property 'foo', initial value: bar 
[after] obj.foo = bar

Beachten Sie, wie wir die "nicht existierende" Nachricht erhalten, wenn wir versuchen, foo abzurufen, wenn es noch nicht existiert, und wieder, wenn wir es erstellen, aber nicht danach.

+0

Dieser Typ. Ich mag diesen Typen und seine Informationen. – wootscootinboogie

+0

@wootscootinboogie: Danke. Zu Ihrer Information, ich habe bemerkt, dass die Antwort veraltet war und sie gerade aktualisiert hat. –

+2

Dieser Typ. Und seine Updates. Ich mag diesen Typen und seine Updates. – jpaugh

1

Auf den letzten JS-Versionen gibt es tatsächlich etwas Ähnliches wie Pythons properties.

Siehe auch Frage Javascript getters and setters for dummies?

Es kann für Sie ausreichend sein, obwohl Python immer noch viel flexibler und kompakter ist.

+0

Dies sind nicht die gleichen, sie sind Getter und Setter * für eine Eigenschaft *, sie funktionieren nicht auf einer Eigenschaft. –

+0

+1, aber es ist sehr implementierungsspezifisch, und es ist durch die ECMAScript5-Spezifikation veraltet, was dies aber auf eine * komplett * andere Weise ermöglicht. So wurde die Unterstützung für diese Syntax (die * schrecklich * war) nie wirklich verbreitet, und jetzt wird es das sicher nicht. Aber für einige Browser ist es eine Möglichkeit. –

+0

@Nick: True, aber der Autor könnte dann auf die zentrale "getValue" -Funktion verschieben. Aber nur für * definierte * Eigenschaften, kein nettes Catch-All für undefinierte. –

0

Wie andere gesagt haben, ist dies unmöglich, da eine Überlastung des Operators in ECMAscript nicht möglich ist.

Wenn Sie wirklich dies tun müssen, dann würde ich einige Vorverarbeitung verwenden, um die Teile des Codes (und nur diejenigen, die wirklich so instrumentiert werden müssen) in instrumentierten Code.

Dies könnte leicht

var a= "var a = b.c['foo']" // get this via xhr or something 
var re = /(\[(.*)\])|(\.([\w\d]+)\b)/g; 

var b = a.replace(re, function(m){ 
    return ".get('" + m.replace(/[[\].'\"]/g,"") + "')"; 
}); 
b; // "var a = b.get('c').get('foo')" 

eval(b);