6

Stellen Sie sich den folgenden Code ein:Javascript: Add-Methode für alle Objekte im Array

$.get("ajax/getColorData.php", function(data) { 
    this.colorData = data; 
}); 

nun vorstellen, dass der Wert von 'Daten' ist:

this.colorData = [ 
    { 
     colorName: 'Red', 
     colorIsInRainbow:true 
    }, 
    { 
     colorName: 'Orange', 
     colorIsInRainbow: true 
    }, 
    { 
     colorName: 'Magenta', 
     colorIsInRainbow: false 
    } 
]; 

Frage 1

Nachdem ich nun die Daten heruntergeladen habe, möchte ich sagen, dass ich jedem Eintrag im Array eine Methode "colorStartsWithR" hinzufügen möchte. Ich "denke" das, anstatt es auf jedem einzelnen Mitglied des Arrays zu definieren, könnte ich irgendwie diese Methode auf dem Prototyp definieren. Aber ich bin mir nicht sicher, ob ich das tun kann, weil diese Objekte nicht von mir erstellt wurden, sondern von $ .get zurückgegeben wurden, daher ist es für mich nicht klar, ob ich in die richtige Richtung denke.

Frage 2

Und ein bisschen weiter zu nehmen, was passiert, wenn ich eine Eigenschaft an jedes Mitglied des Arrays, speziell hinzufügen wollte:

{ 
     colorName: 'Magenta', 
     colorIsInRainbow: false, 
     userClickedThisColor:ko.observable() 
    } 

Auf diese Weise kann ich binden (über knockoutjs) die Liste und ein Kontrollkästchen enthalten. In diesem Fall stelle ich die Frage, ob der Prototyp nützlich sein könnte oder nicht, da jedes Mitglied eine eigene koobservable Eigenschaft erhalten sollte. Ein kurzer Instinkt ist wie etwas zu tun:

for (var i=0;i<this.colorData.length;i++) 
{ 
this.colorData[i].userClickedThisColor=ko.observable() 
} 

und das funktioniert gut, aber vorstellen, dass es mehr als einen Weg, um eine Liste der Farben abzurufen, oder dass ein Benutzer neue Farb Instanzen erstellen können, und dass die Anpassung, die ich oben gemacht habe, ist komplizierter. Ich müsste jetzt die obige "Add-on" -Logik duplizieren. Gibt es einen klügeren Weg? in stark typisierte Sprachen die meiste Zeit verbracht, manchmal diese Dinge sind nicht so offensichtlich für mich

hat. Vielen Dank für alle Anregungen ...

-Ben

+0

Warum für jedes Objekt die Funktion hinzufügen? Machen Sie einfach eine Funktion, die die Objekte als Parameter akzeptiert. –

Antwort

2

Nun, diese Objekte haben keinen speziellen Prototyp, so dass Sie nicht Mitglieder hinzufügen können. Ich denke, das sind die Alternativen:

1) Fügen Sie die Mitglieder zu jeder Instanz (Ich weiß, Sie mögen es nicht, aber es ist eine Option). Ich würde für diese Option gehen

2) Erstellen Sie einfach eine Methode, und jedes Objekt als Parameter übergeben oder als this mit fn.call()

3) Erstellen Sie eine „Klasse“ mit den zusätzlichen Mitgliedern, dann erstellen Instanzen Er übergibt das ursprüngliche Objekt im Konstruktor. Nicht ideal, aber vielleicht musst du es tun.

function Color(plainObj){ 
    this.colorName: plainObj.colorName; 
    this.colorIsInRainbow: plainObj.colorIsInRainbow; 

    //if you want all properties to be copied dynamically, uncomment the following: 
    //for(var key in plainObj) this[key] = plainObj[key];     

    this.userClickedThisColor = ko.observable() 
    ... 
} 
Color.prototype.colorStartsWithR = function() { 
    return this.colorName.charAt(0) == "R"; 
}; 

//etc 

Dann wird das hilft

for(var i=0; i<colorData.length; i++){ 
    colorData[i] = new Color(colorData[i]); //Overwrites original colorData array 
} 

Hoffnung anzuwenden. Prost

+0

Danke Edgar! Ich bin nur in der Lage, einen Beitrag als eine Antwort zu markieren, es scheint, obwohl deins auch hilfreich ist. – BenjiFB

+0

Willkommen. Ich habe meine Antwort aktualisiert, bitte überprüfen Sie sie –

+0

Danke! Also, nur um diese Zeile zu bestätigen: Color.prototype.userClickedThisColor = ko.observable(); bin ich richtig, dass trotz der Definition im Prototyp, jede Instanz wird in der Tat eine eigene separate Kopie bekommen? – BenjiFB

1

Die Objekte in Ihrem Array sind einfache Objekte des Typs Object.So fügen Sie Methoden zum Prototyp dieser Objekte, dann würden Sie die Methoden zur Object Art wie diese hinzufügen:

Object.prototype.colorStartsWithR = function() { 
    return this.colorName.substr(0,1) == "R"; 
} 

Das wäre in diesem Fall arbeiten, aber es ist wirklich nicht zu empfehlen. Die besseren Lösungen sind, entweder die Objekte im Array zu einem anderen Objekttyp zu machen, der seinen eigenen Prototyp hat, zu dem man colorStartsWithR() hinzufügen kann ODER einfach eine Dienstprogrammfunktion verwenden, um einen Namen zu testen, um zu sehen, ob er mit "R" beginnt .

Hier sind einige Beispiele:

function colorObj(color, inRainbow) { 
    this.colorName = color; 
    this.colorIsInRainbow = inRainbow; 
} 

colorObj.prototype.colorStartsWithR = function() { 
     return this.colorName.substr(0,1) == "R"; 
} 

this.colorData = [ 
    new colorObj('Red', true), 
    new colorObj('Orange, true), 
    new colorObj('Magenta, false) 
}; 

Dann könnten Sie tun:

this.colorData[1].colorStartsWithR(); 

Oder nur eine Hilfsfunktion:

var colorData = [ 
    { 
     colorName: 'Red', 
     colorIsInRainbow:true 
    }, 
    { 
     colorName: 'Orange', 
     colorIsInRainbow: true 
    }, 
    { 
     colorName: 'Magenta', 
     colorIsInRainbow: false 
    } 
]; 

function startsWithR(str) { 
    return str.substr(0,1) == "R"; 

} 

startsWithR(colorData[1].colorName); 
+0

Thanks jfriend00! Ich bin nur in der Lage, einen Beitrag als eine Antwort zu markieren, es scheint, obwohl deins auch hilfreich ist, und ich schätze die ausführlichen Beispiele wirklich. – BenjiFB

2

Eine Möglichkeit ist, zu erstellen ein Wrapper-Objekt und füge die neue Methode dem w hinzu Rappern Prototyp:

var colorData = [ 
    { 
     colorName: 'Red', 
     colorIsInRainbow:true 
    }, 
    { 
     colorName: 'Orange', 
     colorIsInRainbow: true 
    }, 
    { 
     colorName: 'Magenta', 
     colorIsInRainbow: false 
    } 
]; 

function ColorDataWrapper(colorData){ 
    this.colorData = colorData; 
} 

ColorDataWrapper.prototype.colorStartsWithR = function(){ 
    return this.colorData.colorName.substring(0,1) == "R"; 
}; 

for(var i = 0; i < colorData.length; i++){ 
    colorData[i] = new ColorDataWrapper(colorData[i]); 
} 

alert(colorData[0].colorStartsWithR()); 
alert(colorData[1].colorStartsWithR()); 

JS Fiddle:http://jsfiddle.net/ywrK6/1/

Eine weitere Möglichkeit ist nur eine Funktion zu erstellen, die das Objekt als Argument akzeptiert:

function colorStartsWithR(obj){ 
    return obj.colorData.colorName.substring(0,1) == "R"; 
} 
+0

Danke, Kevin! – BenjiFB

+0

Hinzufügen eines Kommentars hauptsächlich für meine Notizen: Es sieht so aus, als ob die ColorDataWrapper-Funktion den Wrapper auf einer höheren Ebene als die anderen Lösungen erstellt, was bedeutet, dass kein Parameter für jedes Mitglied akzeptiert werden muss (Beispiel jfriand00) oder führen Sie die dynamische Eigenschaftenzählung durch (Edgars Beispiel). Das ist nett, weil es einfach ist, aber in der Methode haben Sie eine zusätzliche Ebene der indirect in der Methode colorStartsWithR (das scheint wie ein kleiner Preis für die Einfachheit zu bezahlen). Wollte nur darauf hinweisen (wenn ich das richtig verstehe). – BenjiFB

+0

Wenn man alle Elemente im Array durchlaufen will, kann man einfach die Methode 'colorStartsWithR()' direkt zu jedem Objekt im Array hinzufügen. Die Methode muss nicht auf dem Prototyp sein - sie kann direkt zu einem Objekt hinzugefügt werden. Es besteht keine Notwendigkeit, dieses Objekt durch ein anderes Objekt zu ersetzen. – jfriend00