2011-01-15 13 views
26

Czy można zdefiniować operatorów niestandardowych między instancjami typu w kodzie JavaScript?Czy mogę zdefiniować własne przeciążenia operatora w JavaScript?

Na przykład, biorąc pod uwagę, że mam niestandardową klasę wektor, jest to możliwe do wykorzystania

vect1 == vect2 

do sprawdzania równości, natomiast kod bazowego byłoby coś takiego?

operator ==(a, b) { 
    return a.x == b.x && a.y == b.y && a.z == b.z; 
} 

(To oczywiście nonsens.)

Odpowiedz

9

Zgadzam się, że równy funkcja na prototypie wektora jest najlepszym rozwiązaniem. Zauważ, że możesz także budować inne operatory typu infix za pomocą łączenia.

function Vector(x, y, z) { 
    this.x = x; 
    this.y = y; 
    this.z = z; 
} 

Vector.prototype.add = function (v2) { 
    var v = new Vector(this.x + v2.x, 
         this.y + v2.y, 
         this.z + v2.z); 
    return v; 
} 

Vector.prototype.equal = function (v2) { 
    return this.x == v2.x && this.y == v2.y && this.z == v2.z; 
} 

Możesz zobaczyć online sample here.

Aktualizacja: Oto szersza próbka utworzenia Factory function, która obsługuje łańcuch.

+1

Niedawno odkryłem łańcuchowanie za pomocą JQuery.Jest bardzo przydatne w niektórych przypadkach.Dzięki bardzo za próbkę! – pimvdb

8

Nie, JavaScript nie obsługuje przeciążanie operatorów. trzeba będzie napisać metodę, która wykonuje to:

Vector.prototype.equalTo = function(other) { 
    if (!(other instanceof Vector)) return false; 
    return a.x == b.x && a.y == b.y && a.z == b.z; 
} 

Następnie można użyć tej metody jak:

vect1.equalTo(vect2) 
+0

Tak, obecnie mam funkcję również w prototypie. Jednak jestem przyzwyczajony do używania == do sprawdzania równości. Ale jeśli nie jest to możliwe, to po prostu zapomnę o tym – pimvdb

4

Nie, to nie jest częścią specyfikacji (co nie znaczy, że nie aren 't some hacks).

+0

To ładnie znalezione, ale operator == nie wydaje się być "hackable". – pimvdb

+3

Naprawdę chciałbym, aby ten link działał. – jedmao

8

Najlepsze co możesz zrobić, jeśli chcesz, aby trzymać się z operatorem ==:

function Vector(x, y, z) { 
    this.x = x; 
    this.y = y; 
    this.z = z; 
} 

Vector.prototype.toString = function() { 
    return this.x + ";" + this.y + ";" + this.z; 
}; 

var a = new Vector(1, 2, 3); 
var b = new Vector(1, 2, 3); 
var c = new Vector(4, 5, 6); 


alert(String(a) == b); // true 
alert(String(a) == c); // false 
alert(a == b + ""); // true again (no object wrapper but a bit more ugly) 
+0

To również jest możliwe, ale trochę brzydkie, żeby być szczerym. Myślę, że lepiej będzie użyć funkcji równości. – pimvdb

+0

To nie jest tak brzydkie, jak mogłoby się wydawać, ponieważ możesz już mieć funkcję 'toString' na swoim obiekcie, aby ułatwić debugowanie. Ale potem znowu napisałem tę odpowiedź tylko dlatego, że powiedziałeś, że wolisz operatora '==' do eq. Funkcje. Użyj tego, co lubisz najbardziej. Twoje zdrowie! :) – galambalazs

+0

Naprawdę mam funkcję toString, ale do sprawdzania równości łatwiej jest zrobić v1.equalsTo (v2) niż pamiętać, że trzeba ją przekonwertować na ciąg, ponieważ nie jest to zwykły sposób robienia tego - dziękuję za dużo tak czy owak! – pimvdb

1

Oto prosty emulacji testujący równości pomocą guard operator:

function operator(node) 
    { 
    // Abstract the guard operator 
    var guard = " && "; 
    // Abstract the return statement 
    var action = "return "; 
    // return a function which compares two vector arguments 
    return Function("a,b", action + "a.x" + node + "b.x" + guard + "a.y" + node + "b.y" + guard + "a.z" + node + "a.z"); 
    } 

//Pass equals to operator; pass vectors to returned Function 
var foo = operator("==")({"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3}); 
var bar = operator("==")({"x":1,"y":2,"z":3},{"x":4,"y":5,"z":6}); 

//Result 
console.log(["foo",foo,"bar",bar]); 

Dla nie-ścisłych funkcji trybu indeksu tablicy (zdefiniowaną w 15,4) wymienione właściwości danych o argumentach obiekt, którego numeryczny Nazwa wartości są mniejsze niż liczba formalnych parametrów odpowiedniego obiektu funkcji początkowo dzielą swoje wartości z odpowiednimi powiązaniami argumentów w kontekście wykonania funkcji. Oznacza to, że zmiana właściwości zmienia odpowiednią wartość powiązania argumentu i odwrotnie. Ta korespondencja jest zepsuta, jeśli taka właściwość zostanie usunięta, a następnie przedefiniowana lub jeśli właściwość zostanie zmieniona na właściwość akcesor. W funkcjach trybu ścisłego wartości właściwości obiektu arguments są po prostu kopią argumentów przekazywanych do funkcji i nie ma dynamicznego powiązania między wartościami właściwości a formalnymi wartościami parametrów.

Odniesienia

0

Nie jest to bezpośrednia odpowiedź na Twoje pytanie, ale warto o tym pamiętać.

PaperScript to proste rozszerzenie JavaScriptu, które dodaje obsługę przeciążania operatora do dowolnego obiektu.

Służy do tworzenia grafiki wektorowej na płótnie HTML5.

To analizowania PaperScript do skryptu JavaScript w tagu z type = "text/paperscript":

<!DOCTYPE html> 
<html> 
<head> 
<!-- Load the Paper.js library --> 
<script type="text/javascript" src="js/paper.js"></script> 
<!-- Define inlined PaperScript associate it with myCanvas --> 
<script type="text/paperscript" canvas="myCanvas"> 
    // Define a point to start with 
    var point1 = new Point(10, 20); 

    // Create a second point that is 4 times the first one. 
    // This is the same as creating a new point with x and y 
    // of point1 multiplied by 4: 
    var point2 = point1 * 4; 
    console.log(point2); // { x: 40, y: 80 } 

    // Now we calculate the difference between the two. 
    var point3 = point2 - point1; 
    console.log(point3); // { x: 30, y: 60 } 

    // Create yet another point, with a numeric value added to point3: 
    var point4 = point3 + 30; 
    console.log(point4); // { x: 60, y: 90 } 

    // How about a third of that? 
    var point5 = point4/3; 
    console.log(point5); // { x: 20, y: 30 } 

    // Multiplying two points with each other multiplies each 
    // coordinate seperately 
    var point6 = point5 * new Point(3, 2); 
    console.log(point6); // { x: 60, y: 60 } 

    var point7 = new Point(10, 20); 
    var point8 = point7 + { x: 100, y: 100 }; 
    console.log(point8); // { x: 110, y: 120 } 

    // Adding size objects to points work too, 
    // forcing them to be converted to a point first 
    var point9 = point8 + new Size(50, 100); 
    console.log(point9); // { x: 160, y: 220 } 

    // And using the object notation for size works just as well: 
    var point10 = point9 + { width: 40, height: 80 }; 
    console.log(point10); // { x: 200, y: 300 } 

    // How about adding a point in array notation instead? 
    var point5 = point10 + [100, 0]; 
    console.log(point5); // { x: 300, y: 300 } 
</script> 
</head> 
<body> 
    <canvas id="myCanvas" resize></canvas> 
</body> 
</html> 
+0

Zdaję sobie sprawę, że to jest starą odpowiedzią - nie jestem pewny, jak to ma znaczenie dla pytania PO? – brandonscript

+0

Chociaż może to być przydatna wiedza, to w rzeczywistości nie odpowiada na pytanie. –

3

można zmienić wbudowanych metod obiektów w JavaScript, takie jak valueOf() metoda. Dla dowolnych dwóch obiektów, które mają zastosować następujące operatory: >, <, <=, >=, -, + JavaScript przyjmuje właściwość valueOf() każdego obiektu, więc operatory są obsługiwane w następujący sposób: obj1.valueOf() == obj2.valueOf() (dzieje się tak za kulisami). Można nadpisać metodę valueOf() w zależności od potrzeb. Tak więc na przykład:

var Person = function(age, name){ 
    this.age = age; 
    this.name = name; 
} 

Person.prototype.valueOf(){ 
    return this.age; 
} 

var p1 = new Person(20, "Bob"), 
    p2 = new Person(30, "Bony"); 

console.log(p1 > p2); //false 
console.log(p1 < p2); //true 
console.log(p2 - p1); //10 
console.log(p2 + p1); //40 

//for == you should the following 
console.log(p2 >= p1 && p2 <= p1); // false 

więc nie jest to dokładna odpowiedź na swoje pytanie, ale myślę, że może to być przydatne rzeczy dla tego rodzaju spraw.

Powiązane problemy