2011-01-15 12 views
26

¿Es posible definir operadores personalizados entre instancias de un tipo en JavaScript?¿Puedo definir sobrecargas de operador personalizadas en Javascript?

Por ejemplo, dado que tengo una clase de vectores personalizada, es posible utilizar

vect1 == vect2 

para comprobar la igualdad, mientras que el código subyacente sería algo como esto?

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

(Esto no tiene sentido, por supuesto.)

Respuesta

9

Estoy de acuerdo que la función de la igualdad en el prototipo vector es la mejor solución. Tenga en cuenta que también puede construir otros operadores similares a infix mediante el encadenamiento.

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; 
} 

Puedes ver online sample here.

Actualización: Aquí hay una muestra más extensa de la creación de un Factory function que admite el encadenamiento.

+1

Recientemente descubrí el encadenamiento usando JQuery. Es extremadamente útil en ciertos casos. Muchas gracias por la muestra! – pimvdb

8

No, JavaScript no soporta la sobrecarga de operadores. Usted tendrá que escribir un método que hace esto:

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

A continuación, puede utilizar este método como:

vect1.equalTo(vect2) 
+0

Sí, actualmente tengo una función en el prototipo también. Sin embargo, estoy acostumbrado a usar == para verificar la igualdad. Pero si no es posible, entonces lo olvidaré – pimvdb

4

No, no es parte de la especificación (lo que no quiere decir que no aren 't some hacks).

+0

Está bien encontrado, pero el operador == no parece ser "pirateable". – pimvdb

+3

realmente me gustaría que este enlace todavía funcionara – jedmao

8

Lo mejor que puede hacer si desea seguir con el operador ==:

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

Eso también es una posibilidad, pero un poco feo para ser sincero. Creo que seré mejor que usar una función de igualdad. – pimvdb

+0

No es tan feo como podría pensar, porque es posible que ya tenga una función 'toString' en su objeto para una depuración más fácil. Pero, de nuevo, escribí esta respuesta solo porque dijiste que preferías el operador '==' a eq. funciones. Usa lo que más te guste. ¡Aclamaciones! :) – galambalazs

+0

Tengo una función toString de hecho, pero para la comprobación de la igualdad es más fácil hacer v1.equalsTo (v2) que recordar que tiene que convertirlo a una cadena, ya que no es la forma habitual de hacerlo - muchas gracias de todos modos! – pimvdb

1

Aquí es una emulación sencilla que pone a prueba por la igualdad mediante el 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]); 

Para funciones del modo no estrictas el índice de matriz (definida en 15.4) propiedades de datos con nombre de un argumentos objeto cuyo nombre numérico los valores son menores que el número de parámetros formales del objeto de función correspondiente que inicialmente comparten sus valores con los enlaces de argumento correspondientes en el contexto de ejecución de la función. Esto significa que cambiar la propiedad cambia el valor correspondiente de la vinculación del argumento y viceversa. Esta correspondencia se rompe si dicha propiedad se elimina y luego se redefine o si la propiedad se cambia a una propiedad de acceso. Para las funciones de modo estrictas, los valores de las propiedades del objeto de argumentos son simplemente una copia de los argumentos pasados ​​a la función y no hay un vínculo dinámico entre los valores de propiedad y los valores de parámetros formales.

Referencias

0

No es una respuesta directa para su pregunta, pero vale la pena tener en cuenta.

PaperScript es una extensión simple de JavaScript que agrega compatibilidad para la sobrecarga del operador a cualquier objeto.

Se utiliza para hacer gráficos vectoriales encima de HTML5 Canvas.

Se analiza PaperScript tener JavaScript en la etiqueta de script con 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

Me doy cuenta de esto es una respuesta antigua, aunque no estoy seguro de cómo esto es relevante para la pregunta del OP? – brandonscript

+0

Si bien esto podría ser un conocimiento útil, esto en realidad no responde la pregunta. –

3

Puede cambiar métodos incorporados de objetos en JavaScript, como valueOf() método. Para cualquier dos objetos para aplicar los siguientes operadores >, <, <=, >=, -, + JavaScript toma la propiedad valueOf() de cada objeto, por lo que se trata de operadores como este: obj1.valueOf() == obj2.valueOf() (esto lo hace entre bastidores). Puede sobrescribir el método valueOf() según sus necesidades. Así, por ejemplo:

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 

Así que esto no es la respuesta exacta a su pregunta, pero creo que esto puede ser un material útil para ese tipo de cuestiones.

Cuestiones relacionadas