Javascript: operator overloading

I've telah bekerja dengan JavaScript untuk beberapa hari sekarang dan telah sampai ke titik di mana saya ingin membebani operator untuk mendefinisikan objek.

Setelah bertugas di google mencari ini tampaknya anda dapat't secara resmi melakukan hal ini, namun ada beberapa orang di luar sana yang mengklaim beberapa bertele-tele cara melakukan tindakan ini.

Pada dasarnya saya've membuat Vector2 kelas dan ingin dapat melakukan hal-hal berikut:

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.

Bukannya aku'm harus melakukan ini:

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. 

Ada sebuah pendekatan yang dapat saya ambil untuk overload operator di Vector2 kelas? Saat ini hanya terlihat biasa jelek.

Mengomentari pertanyaan (2)
Larutan

Seperti yang anda've ditemukan, JavaScript doesn't dukungan operator overloading. Yang paling dekat anda bisa datang untuk melaksanakan toString (yang akan dipanggil ketika misalnya harus dipaksa untuk menjadi string) dan valueOf (yang akan dipanggil untuk memaksa itu ke nomor, misalnya ketika menggunakan + untuk penambahan, atau dalam banyak kasus ketika menggunakannya untuk rangkaian karena + mencoba untuk melakukan itu sebelum rangkaian), yang ini cukup terbatas. Tidak memungkinkan anda membuat Vector2 objek sebagai hasil.


Untuk orang-orang yang datang untuk pertanyaan ini yang ingin string atau angka sebagai hasil (bukan Vector2), meskipun, berikut ini adalah contoh dari valueOf dan toString. Contoh-contoh ini tidak menunjukkan operator overloading, hanya mengambil keuntungan dari JavaScript's built-in penanganan mengkonversi ke primitif:

valueOf

Ini contoh menggandakan nilai dari sebuah objek's val properti dalam menanggapi dipaksa untuk primitif, misalnya melalui +:

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)

Atau dengan ES2015's kelas:

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)

Atau hanya dengan benda-benda, tidak konstruktor:

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

Ini contoh mengkonversi nilai suatu obyek's val properti untuk atas kasus dalam menanggapi dipaksa untuk primitif, misalnya melalui +:

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

Atau dengan ES2015's kelas:

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

Atau hanya dengan benda-benda, tidak konstruktor:

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
Komentar (3)

Sebagai T. J. berkata, anda tidak overload operator pada JavaScript. Namun, anda dapat mengambil keuntungan dari valueOf fungsi untuk menulis sebuah hack yang terlihat lebih baik daripada menggunakan fungsi-fungsi seperti add setiap waktu, tapi memaksakan kendala pada vektor x dan y adalah antara 0 dan MAX_VALUE. Berikut ini adalah kode:

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

Kemudian anda dapat menulis persamaan seperti ini:

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]
Komentar (5)

FYI paper.js memecahkan masalah ini dengan menciptakan PaperScript, mandiri, cakupan javascript dengan operator overloading vektor, yang kemudian diproses kembali ke dalam javascript.

Tapi paperscript file harus secara khusus ditentukan dan diproses seperti itu.

Komentar (0)

It's mungkin untuk dilakukan vektor matematika dengan dua angka yang dikemas menjadi satu. Pertama saya akan menunjukkan contoh sebelum saya menjelaskan bagaimana cara kerjanya:

let a = vec_pack([2,4]);
let b = vec_pack([1,2]);

let c = a+b; // Vector addition
let d = c-b; // Vector subtraction
let e = d*2; // Scalar multiplication
let f = e/2; // Scalar division

console.log(vec_unpack(c)); // [3, 6]
console.log(vec_unpack(d)); // [2, 4]
console.log(vec_unpack(e)); // [4, 8]
console.log(vec_unpack(f)); // [2, 4]

if(a === f) console.log("Equality works");
if(a > b) console.log("Y value takes priority");

Saya menggunakan fakta bahwa jika anda sedikit pergeseran dua angka X kali dan kemudian menambahkan atau mengurangi mereka sebelum menggeser mereka kembali, anda akan mendapatkan hasil yang sama seperti jika anda tidak't bergeser mereka untuk memulai dengan. Demikian pula skalar perkalian dan pembagian karya simetris untuk bergeser nilai-nilai.

JavaScript nomor 52 bit integer presisi (64 bit mengapung), jadi aku akan berkemas satu nomor ke dia lebih tinggi tersedia 26 bit, dan satu ke yang lebih rendah. Kode ini dibuat sedikit lebih berantakan karena saya ingin dukungan yang ditandatangani angka.

vec_unpack = function(number){
    switch(((number & 33554432) !== 0) * 1 + (number < 0) * 2){
        case(0):
            return [(number % 33554432),Math.trunc(number / 67108864)];
        break;
        case(1):
            return [(number % 33554432)-33554432,Math.trunc(number / 67108864)+1];
        break;
        case(2):
            return [(((number+33554432) % 33554432) + 33554432) % 33554432,Math.round(number / 67108864)];
        break;
        case(3):
            return [(number % 33554432),Math.trunc(number / 67108864)];
        break;
    }
}

Satu-satunya downside dapat saya lihat dengan ini adalah bahwa x dan y harus berada dalam kisaran +-33 juta, karena mereka harus masuk dalam 26 bit masing-masing.

Komentar (0)

Sebenarnya, ada satu varian dari JavaScript yang does dukungan operator overloading. ExtendScript, bahasa scripting yang digunakan oleh aplikasi Adobe seperti Photoshop dan Illustrator, tidak memiliki operator overloading. Di dalamnya, anda dapat menulis: `` Vector2.prototipe["+"] = function( b ) { kembali new Vector2( ini.x + b.x ini.y + b.y ); }

var a = new Vector2(1,1); var b = new Vector2(2,2); var c = a + b; `` Hal ini dijelaskan secara lebih rinci dalam "Adobe Extendscript JavaScript alat panduan" (saat ini link di sini). Sintaks tampaknya didasarkan pada (sekarang lama ditinggalkan) rancangan ECMAScript standar.

Komentar (1)