UFO ET IT

JavaScript에서 산술 연산자 오버로딩?

ufoet 2020. 11. 11. 21:01
반응형

JavaScript에서 산술 연산자 오버로딩?


이 자바 스크립트 "클래스"정의를 고려할 때 이것이 제가이 질문을 표현할 수있는 가장 좋은 방법입니다.

var Quota = function(hours, minutes, seconds){
    if (arguments.length === 3) {
        this.hours = hours;
        this.minutes = minutes;
        this.seconds = seconds;

        this.totalMilliseconds = Math.floor((hours * 3600000)) + Math.floor((minutes * 60000)) + Math.floor((seconds * 1000));
    }
    else if (arguments.length === 1) {
        this.totalMilliseconds = hours;

        this.hours = Math.floor(this.totalMilliseconds / 3600000);
        this.minutes = Math.floor((this.totalMilliseconds % 3600000) / 60000);
        this.seconds = Math.floor(((this.totalMilliseconds % 3600000) % 60000) / 1000);
    }

    this.padL = function(val){
        return (val.toString().length === 1) ? "0" + val : val;
    };

    this.toString = function(){
        return this.padL(this.hours) + ":" + this.padL(this.minutes) + ":" + this.padL(this.seconds);
    };

    this.valueOf = function(){
        return this.totalMilliseconds;
    };
};

및 다음 테스트 설정 코드 :

var q1 = new Quota(23, 58, 50);
var q2 = new Quota(0, 1, 0);
var q3 = new Quota(0, 0, 10);

console.log("Quota 01 is " + q1.toString());    // Prints "Quota 01 is 23:58:50"
console.log("Quota 02 is " + q2.toString());    // Prints "Quota 02 is 00:01:00"
console.log("Quota 03 is " + q3.toString());    // Prints "Quota 03 is 00:00:10"

다음과 같이 더하기 연산자를 사용하여 암시 적 q4으로 Quota객체 생성하는 방법이 있습니까?

var q4 = q1 + q2 + q3;
console.log("Quota 04 is " + q4.toString());    // Prints "Quota 04 is 86400000"

의지하기보다는 ...

var q4 = new Quota(q1 + q2 + q3);
console.log("Quota 04 is " + q4.toString());    // Prints "Quota 04 is 24:00:00"

산술 연산자를 통해 사용자 지정 숫자 JavaScript 개체를 구성 할 수 있도록이 영역에서 권장되는 모범 사례는 무엇입니까?


내가 아는 한 Javascript (적어도 현재 존재하는 경우)는 연산자 오버로딩을 지원하지 않습니다.

내가 제안 할 수있는 최선의 방법은 다른 여러 개체에서 새 할당량 개체를 만드는 클래스 메서드입니다. 다음은 내가 의미하는 바에 대한 간단한 예입니다.

// define an example "class"
var NumClass = function(value){
    this.value = value;
}
NumClass.prototype.toInteger = function(){
    return this.value;
}

// Add a static method that creates a new object from several others
NumClass.createFromObjects = function(){
    var newValue = 0;
    for (var i=0; i<arguments.length; i++){
        newValue += arguments[i].toInteger();
    }
    return new this(newValue)
}

다음과 같이 사용하십시오.

var n1 = new NumClass(1);
var n2 = new NumClass(2);
var n3 = new NumClass(3);

var combined = NumClass.createFromObjects(n1, n2, n3);

불행하게도.

폴 백의 경우 반환 값을 정렬하면 메서드 체인을 사용할 수 있습니다.

var q4 = q1.plus(p2).plus(q3);

모두가 내 다른 답변에 투표했기 때문에 실제로 의도 한대로 작동하는 개념 증명 코드를 게시하고 싶었습니다.

이것은 크롬과 IE에서 테스트되었습니다.

//Operator Overloading

var myClass = function () {

//Privates

var intValue = Number(0),
    stringValue = String('');

//Publics
this.valueOf = function () {
    if (this instanceof myClass) return intValue;
    return stringValue;
}

this.cast = function (type, call) {
    if (!type) return;
    if (!call) return type.bind(this);
    return call.bind(new type(this)).call(this);
}

}

//Derived class
var anotherClass = function () {

//Store the base reference
this.constructor = myClass.apply(this);

var myString = 'Test',
    myInt = 1;

this.valueOf = function () {
    if (this instanceof myClass) return myInt;
    return myString;
}

}


//Tests

var test = new myClass(),
anotherTest = new anotherClass(),
composed = test + anotherTest,
yaComposed = test.cast(Number, function () {
    return this + anotherTest
}),
yaCComposed = anotherTest.cast(Number, function () {
    return this + test;
}),
t = test.cast(anotherClass, function () {
    return this + anotherTest
}),
tt = anotherTest.cast(myClass, function () {
    return this + test;
});

debugger;

누군가가 기술적 인 설명을 할 정도로 친절하다면 왜 이것이 충분하지 않은지 듣고 기뻐할 것입니다!


두 번째 제안 :

var q4 = Quota.add(q1, q2, q3);

나는 최근에 http://www.2ality.com/2011/12/fake-operator-overloading.html 기사를 보았습니다 .

자바 스크립트에서 연산자 오버로딩과 같은 작업을 수행하기 위해 객체에서 valueOf 메서드를 재정의하는 방법을 설명합니다. 실제로 작동되는 객체에 대해서만 mutator 작업을 수행 할 수있는 것처럼 보이므로 원하는 작업을 수행하지 않습니다. 그럼에도 불구하고 흥미 롭습니다.


Paper.js는 예를 들어 포인트 추가 ( docs ) 와 같이이를 수행합니다 .

var point = new Point(5, 10);
var result = point + 20;
console.log(result); // {x: 25, y: 30}

하지만 자체 사용자 정의 스크립트 파서를 사용하여 수행합니다 .


객체 인 정수 또는 문자열로 암시 적으로 변환 할 수 있습니다.

객체는 JavaScript가 숫자 또는 문자열을 예상하는 경우에만 암시 적으로 변환됩니다. 전자의 경우 변환에는 세 단계가 필요합니다.

1.- 전화 valueOf(). 결과가 원시 (객체가 아님)이면이를 사용하고 숫자로 변환합니다.

2.- 그렇지 않으면을 호출하십시오 toString(). 결과가 원시적이면이를 사용하고 숫자로 변환하십시오.

3.- 그렇지 않으면 TypeError. 1 단계의 예 :

3 * { valueOf: function () { return 5 } }

JavaScript가 문자열로 변환되면 1 단계와 2 단계가 바뀝니다. toString ()이 먼저 시도되고 valueOf ()가 두 번째로 시도됩니다.

http://www.2ality.com/2013/04/quirk-implicit-conversion.html


JavaScript에서 연산자 오버로딩을 수행하는 스크립트를 만들었습니다. 일을 만드는 것은 간단하지 않았기 때문에 몇 가지 단점이 있습니다. 프로젝트 페이지에서 여기에주의 사항을 교차 게시하겠습니다. 그렇지 않으면 하단에서 링크를 찾을 수 있습니다.

  • 계산 결과는 새 개체에 전달되어야하므로 (p1 + p2 + p3) 대신 새 점 (p1 + p2 + p3)을 수행해야합니다 (사용자 정의 개체의 이름이 "점"인 경우).

  • +,-, * 및 / 만 지원되며 다섯 번째 산술 연산자 %는 지원되지 않습니다. 문자열 ( ""+ p1) 및 비교 (p1 == p2)에 대한 강제 변환이 예상대로 작동하지 않습니다. 필요한 경우 (p1.val == p2.val)과 같이 이러한 목적을 위해 새 함수를 빌드해야합니다.

  • 마지막으로 답을 계산하는 데 필요한 계산 리소스는 항의 수에 따라 2 차적으로 증가합니다. 따라서 기본값 당 하나의 계산 체인에 6 개의 용어 만 허용됩니다 (이를 늘릴 수 있음). 그보다 긴 계산 체인의 경우 다음과 같이 계산을 분할합니다. new point (new point (p1 + p2 + p3 + p4 + p5 + p6) + new point (p7 + p8 + p9 + p10 + p11 + p12))

Github의 페이지 .


사람들이 왜이 질문에 계속해서 대답하지 않는지 잘 모르겠습니다!

이해하기 위해 John Resig가 아니어도되는 아주 작은 스크립트로 설명 할 방법이 절대적으로 있습니다.

그렇게하기 전에 JavaScript에서 생성자가 작동하는 방식은 배열을 확인하거나 '인수'리터럴을 반복하는 것입니다.

예를 들어 내 '클래스'의 생성자에서 나는 arugment를 반복하고 기본 arugment의 유형을 결정하고 지능적으로 처리합니다.

즉, 배열을 전달하면 arugments를 반복하여 배열을 찾은 다음 배열의 요소 유형에 따라 추가 처리를 수행하도록 배열을 반복합니다.

예 :-> new someClass ([instanceA, instanceB, instanceC])

그러나 여러분은 연산자 오버로딩에 대한보다 "C"스타일의 접근 방식을 찾고 있습니다. 이는 실제로 대중의 믿음과는 반대로 달성 될 수 있습니다.

다음은 연산자 오버로딩을 존중하는 MooTools를 사용하여 만든 클래스입니다. 평범한 오래된 JavaScript에서는 동일한 toString 메서드를 사용하여 인스턴스의 프로토 타입에만 직접 연결합니다.

My main reason for displaying this approach is because of the text I continually read which states this functionality is "impossible" to emulate. Nothing is impossible only sufficently difficult and I will display this below...

 //////

debugger;

//Make a counter to prove I am overloading operators
var counter = 0;

//A test class with a overriden operator
var TestClass = new Class({
    Implements: [Options, Events],
    stringValue: 'test',
    intValue: 0,
    initialize: function (options) {
        if (options && options instanceof TestClass) {
            //Copy or compose
            this.intValue += options.intValue;
            this.stringValue += options.stringValue;
        } else {
            this.intValue = counter++;
        }
    },
    toString: function () {
        debugger;
        //Make a reference to myself
        var self = this;
        //Determine the logic which will handle overloads for like instances
        if (self instanceof TestClass) return self.intValue;
        //If this is not a like instance or we do not want to overload return the string value or a default.
        return self.stringValue;
    }
});

//Export the class
window.TestClass = TestClass;

//make an instance
var myTest = new TestClass();

//make another instance
var other = new TestClass();

//Make a value which is composed of the two utilizing the operator overload
var composed = myTest + other;

//Make a value which is composed of a string and a single value
var stringTest = '' + myTest;

//////

The most recent display of this nomenclature was observed at XDate's documentation page: http://arshaw.com/xdate/

In this case I believe it was actually even easer, he could have used the prototype of the Date object to achive the same.

None the less the method I have given as an example which should portray this style of utilization for others.

Edit:

I have a complete implementation here:

http://netjs.codeplex.com/

Along with other goodies.


In addition to what already have been said: overriding .valueOf() may help to produce quite powerful operator overloading. In proof-of-concept Fingers.js lib you can add event listeners in .NET style:

function hi() { console.log("hi") }
function stackoverflow() { console.log("stackoverflow") }
function bye() { console.log("bye") }

on(yourButton).click += hi + stackoverflow;
on(yourButton).click -= hi - bye;

Core idea is to replace temporarily valueOf when on() is called:

const extendedValueOf = function () {
    if (handlers.length >= 16) {
        throw new Error("Max 16 functions can be added/removed at once using on(..) syntax");
    }

    handlers.push(this); // save current function

    return 1 << ((handlers.length - 1) * 2); // serialize it as a number.
};

Number returned can be then de-serialized back into function using handlers array. What's more it's possible extract bit values from final value (func1 + func2 - func3) so effectively you can understand what functions where added, and what functions were removed.

You can check out source on github and play with demo here.

Complete explanation exists in this article (it's for AS3, tough since it's ecmascript it will work for JS either).


For some limited use cases you can have operator "overloading" effects:

function MyIntyClass() {
    this.valueOf = function() { return Math.random(); }
}
var a = new MyIntyClass();
var b = new MyIntyClass();
a < b
false

a + b
0.6169137847609818

[a, b].sort() // O(n^2) ?
[myClass, myClass]

function MyStringyClass() {
    this.valueOf = function() { return 'abcdefg'[Math.floor(Math.random()*7)]; }
}
c = new MyStringyClass();
'Hello, ' + c + '!'
Hello, f!

The above code is free to use under the MIT license. YMMV.

참고URL : https://stackoverflow.com/questions/1634341/overloading-arithmetic-operators-in-javascript

반응형