ここ数日、JavaScriptを使用していて、定義されたオブジェクトに対して演算子をオーバーロードしたいポイントにたどり着きました。
Googleで検索してみたところ、公式にはできないようですが、このアクションを実行するための長ったらしい方法を主張している人が何人かいます。
基本的には、私はVector2クラスを作成し、以下のことをできるようにしたいと思っています。
var x = new Vector2(10,10);
var y = new Vector2(10,10);
x += y; //This does not result in x being a vector with 20,20 as its x & y values.
その代わり、こんなことをしなければならない。
var x = new Vector2(10,10);
var y = new Vector2(10,10);
x = x.add(y); //This results in x being a vector with 20,20 as its x & y values.
Vector2クラスで演算子をオーバーロードするために、何か良い方法はありませんか?これは単に醜く見えるだけなので。
お分かりのように、JavaScript は演算子のオーバーロードをサポートしていません。最も近いのは toString
(インスタンスを文字列に強制するときに呼び出される) と valueOf
(数値に強制するときに呼び出される。例えば +
で加算するときや、多くの場合 +
で連結する前に加算しようとするから) の実装ですが、かなり制限されています。どちらも、結果として Vector2
オブジェクトを作成することはできません。
この質問に来た人の中で、(Vector2
ではなく)文字列や数値を結果にしたい人のために、 valueOf
と toString
の例を挙げます。これらの例は、演算子のオーバーロードを示すものではなく、JavaScriptに組み込まれたプリミティブへの変換処理を利用したものです。
valueOf
この例では、例えば +
によってプリミティブに変換されたオブジェクトの val
プロパティの値を 2 倍にします。
function Thing(val) {
this.val = val;
}
Thing.prototype.valueOf = function() {
// Here I'm just doubling it; you'd actually do your longAdd thing
return this.val * 2;
};
var a = new Thing(1);
var b = new Thing(2);
console.log(a + b); // 6 (1 * 2 + 2 * 2)
またはES2015'のclass
で。
class Thing {
constructor(val) {
this.val = val;
}
valueOf() {
return this.val * 2;
}
}
const a = new Thing(1);
const b = new Thing(2);
console.log(a + b); // 6 (1 * 2 + 2 * 2)
あるいは、オブジェクトだけで、コンストラクタがない。
var thingPrototype = {
valueOf: function() {
return this.val * 2;
}
};
var a = Object.create(thingPrototype);
a.val = 1;
var b = Object.create(thingPrototype);
b.val = 2;
console.log(a + b); // 6 (1 * 2 + 2 * 2)
toString
この例では、オブジェクトの val
プロパティの値を、例えば +
を介してプリミティブに強制された場合に、大文字に変換します。
function Thing(val) {
this.val = val;
}
Thing.prototype.toString = function() {
return this.val.toUpperCase();
};
var a = new Thing("a");
var b = new Thing("b");
console.log(a + b); // AB
またはES2015'のclass
で。
class Thing {
constructor(val) {
this.val = val;
}
toString() {
return this.val.toUpperCase();
}
}
const a = new Thing("a");
const b = new Thing("b");
console.log(a + b); // AB
あるいは、オブジェクトだけで、コンストラクタはありません。
var thingPrototype = {
toString: function() {
return this.val.toUpperCase();
}
};
var a = Object.create(thingPrototype);
a.val = "a";
var b = Object.create(thingPrototype);
b.val = "b";
console.log(a + b); // AB
T.J.が言ったように、JavaScriptでは演算子をオーバーロードすることはできません。しかし、 valueOf
関数を利用して、毎回 add
のような関数を使うよりも見栄えのするハックを書くことができます。ただし、ベクトルに対して x と y が 0 から MAX_VALUE の間であるという制約を課しています。以下はそのコードです。
var MAX_VALUE = 1000000;
var Vector = function(a, b) {
var self = this;
//initialize the vector based on parameters
if (typeof(b) == "undefined") {
//if the b value is not passed in, assume a is the hash of a vector
self.y = a % MAX_VALUE;
self.x = (a - self.y) / MAX_VALUE;
} else {
//if b value is passed in, assume the x and the y coordinates are the constructors
self.x = a;
self.y = b;
}
//return a hash of the vector
this.valueOf = function() {
return self.x * MAX_VALUE + self.y;
};
};
var V = function(a, b) {
return new Vector(a, b);
};
そうすると、次のような方程式を書くことができます。
var a = V(1, 2); //a -> [1, 2]
var b = V(2, 4); //b -> [2, 4]
var c = V((2 * a + b) / 2); //c -> [2, 4]