Programing

자바 스크립트 : 연산자 오버로딩

lottogame 2020. 11. 2. 07:37
반응형

자바 스크립트 : 연산자 오버로딩


저는 며칠 동안 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결과적 으로 개체 를 만들 수 없습니다 .


결과로 (a 대신) 문자열이나 숫자를 원하는이 질문에 오는 사람들을 위해 다음 Vector2valueOf및의 예입니다 toString. 이 예제 연산자 오버로딩을 보여 주지 않고 기본으로 변환하는 JavaScript의 내장 처리를 활용합니다.

valueOf

이 예제는 예 val를 들어 다음을 통해 기본 요소로 강제 변환되는 것에 대한 응답으로 객체의 속성 값을 두 배로 늘립니다 +.

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


As T.J. said, you cannot overload operators in JavaScript. However you can take advantage of the valueOf function to write a hack which looks better than using functions like add every time, but imposes the constraints on the vector that the x and y are between 0 and MAX_VALUE. Here is the code:

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

Then you can write equations like this:

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]

FYI paper.js solves this issue by creating PaperScript, a self-contained, scoped javascript with operator overloading of vectors, which it then processing back into javascript.

But the paperscript files need to be specifically specified and processed as such.


It's possible to do vector math with two numbers packed into one. Let me first show an example before I explain how it works:

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

I am using the fact that if you bit shift two numbers X times and then add or subtract them before shifting them back, you will get the same result as if you hadn't shifted them to begin with. Similarly scalar multiplication and division works symmetrically for shifted values.

A JavaScript number has 52 bits of integer precision (64 bit floats), so I will pack one number into he higher available 26 bits, and one into the lower. The code is made a bit more messy because I wanted to support signed numbers.

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

The only downside I can see with this is that the x and y has to be in the range +-33 million, since they have to fit within 26 bits each.


Actually, there is one variant of JavaScript that does support operator overloading. ExtendScript, the scripting language used by Adobe applications such as Photoshop and Illustrator, does have operator overloading. In it, you can write:

Vector2.prototype["+"] = function( b )
{
  return new Vector2( this.x + b.x, this.y + b.y );
}

var a = new Vector2(1,1);
var b = new Vector2(2,2);
var c = a + b;

This is described in more detail in the "Adobe Extendscript JavaScript tools guide" (current link here). The syntax was apparently based on a (now long abandoned) draft of the ECMAScript standard.

참고URL : https://stackoverflow.com/questions/19620667/javascript-operator-overloading

반응형