जावास्क्रिप्ट: ऑपरेटर ओवरलोडिंग


93

मैं अब कुछ दिनों के लिए जावास्क्रिप्ट के साथ काम कर रहा हूं और एक ऐसे बिंदु पर पहुंच गया हूं जहां मैं अपने परिभाषित वस्तुओं के लिए ऑपरेटरों को अधिभार देना चाहता हूं।

गूगल पर एक खोज के बाद यह लगता है कि आप आधिकारिक तौर पर ऐसा नहीं कर सकते, फिर भी कुछ लोग हैं जो इस कार्रवाई को करने के कुछ लंबे घुमावदार तरीके का दावा कर रहे हैं।

मूल रूप से मैंने एक वेक्टर 2 वर्ग बनाया है और निम्नलिखित कार्य करने में सक्षम होना चाहता हूं:

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. 

क्या कोई तरीका है जो मैं अपने वेक्टर 2 वर्ग में ऑपरेटरों को अधिभार ले सकता हूं? के रूप में यह सिर्फ सादा बदसूरत लग रहा है।



1
बस एक ऑपरेटर ओवरलोडिंग पुस्तकालय में आया था। यह कोशिश नहीं की और पता नहीं कितनी अच्छी तरह से काम करता है, हालांकि: google.com/…
fishinear

जवाबों:


102

जैसा कि आपने पाया है, जावास्क्रिप्ट ऑपरेटर ओवरलोडिंग का समर्थन नहीं करता है। आप जो सबसे करीब आ सकते हैं, उसे लागू करना है toString(जिसे तब बुलाया जाएगा जब उदाहरण को स्ट्रिंग होने के लिए ज़बर्दस्त करने की आवश्यकता होती है) और valueOf(जो इसे संख्या के लिए उपयोग करने के लिए कहा जाएगा, उदाहरण के लिए जब +इसके अलावा का उपयोग करते हुए , या कई मामलों में जब इसे संघनन के लिए उपयोग करना क्योंकि +संघनन से पहले इसके अलावा करने की कोशिश करता है), जो बहुत सीमित है। Vector2परिणामस्वरूप न तो आपको कोई ऑब्जेक्ट बनाने देता है ।


इस सवाल पर आने वाले लोगों के लिए, जो एक स्ट्रिंग (संख्या) को परिणामस्वरूप (इसके बजाय Vector2) चाहते हैं, हालांकि, यहां valueOfऔर इसके उदाहरण हैं toString। ये उदाहरण ऑपरेटर ओवरलोडिंग को प्रदर्शित नहीं करते हैं , बस जावास्क्रिप्ट का अंतर्निहित लाभ उठाते हुए प्राइमेटिंग में परिवर्तित होते हैं:

valueOf

उदाहरण के valलिए, उदाहरण के लिए, किसी आदिम के लिए मजबूर होने के जवाब में यह वस्तु की संपत्ति के मूल्य को दोगुना कर देता है +:

या ES2015 के साथ class:

या सिर्फ वस्तुओं के साथ, कोई निर्माता नहीं:

toString

यह उदाहरण किसी वस्तु की valसंपत्ति के मूल्य को एक आदिम के लिए ज़ब्त होने के जवाब में ऊपरी मामले में परिवर्तित करता है , उदाहरण के लिए +:

या ES2015 के साथ class:

या सिर्फ वस्तुओं के साथ, कोई निर्माता नहीं:


1
हालांकि जेएस उचित के भीतर इसका समर्थन नहीं किया गया है, लेकिन जेएस को कस्टम फीचर्स के साथ विस्तारित करना और सादे जेएस को ट्रांसपाइल वापस करना इन दिनों काफी आम है, उदाहरण के लिए, स्वीटजेस का लक्ष्य इस समस्या का समाधान करना है।
दिमित्री ज़ैतसेव

1
क्या Dateकक्षा में तुलना करने वाले ऑपरेटर निहित रूप से दिनांक का उपयोग करके संख्याओं में परिवर्तित करते हैं valueOf? उदाहरण के लिए आप कर सकते हैं date2 > date1और यह सच होगा यदि date2बाद में बनाया गया था date1
सीन लेटेंड्रे

1
@ सीनलेन्ट्रे: हाँ। >, <, >=, और <=(लेकिन नहीं ==, ===, !=, या !==) का उपयोग सार संबंधपरक तुलना ऑपरेशन है, जो का उपयोग करता है ToPrimitiveसंकेत "संख्या" के साथ। किसी Dateऑब्जेक्ट पर, वह संख्या जो getTimeरिटर्न करती है (मिलीसेकंड-चूंकि-द-एपोच मूल्य)।
टीजे क्राउडर

23

जैसा कि टीजे ने कहा, आप ऑपरेटरों को जावास्क्रिप्ट में अधिभार नहीं दे सकते। हालाँकि आप 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]

7
आपने मूल रूप से केवल ओपी की addविधि के लिए कोड लिखा है ... कुछ वे करना नहीं चाहते थे।
इयान ब्रिंडले

15
@IanBrindley ओपी एक ऑपरेटर को ओवरलोड करना चाहता था, जिसका स्पष्ट अर्थ है कि उसने इस तरह के एक समारोह को लिखने की योजना बनाई थी। ओपी की चिंता "जोड़ने" के साथ थी, जो अप्राकृतिक है; गणितीय रूप से, हम एक +चिन्ह के साथ वेक्टर जोड़ का प्रतिनिधित्व करते हैं । यह एक बहुत अच्छा जवाब है जो दिखा रहा है कि कैसे अर्ध-संख्यात्मक वस्तुओं के लिए एक अप्राकृतिक फ़ंक्शन नाम को कॉल करने से बचें।
किट्सटिल

1
@Kittsil प्रश्न दिखाता है कि मैं पहले से ही एक ऐड फ़ंक्शन का उपयोग कर रहा हूं। हालांकि ऊपर का फ़ंक्शन खराब कार्य नहीं है, लेकिन यह प्रश्न को संबोधित नहीं करता है, इसलिए मैं इयान के साथ सहमत हूं।
ली ब्रिंडले

अभी तक यह एकमात्र संभव तरीका है। +ऑपरेटर के पास हमारे पास एकमात्र लचीलापन है जो किसी Numberएक ऑपरेंड के प्रतिस्थापन के रूप में वापस आने की क्षमता है। इसलिए कोई भी कार्यशीलता जो Objectइंस्टेंस काम करती है उसे हमेशा ऑब्जेक्ट को एक के रूप में एन्कोड करना चाहिए Number, और अंततः इसे डीकोड करना चाहिए।
गेरशोम

ध्यान दें कि यह दो वेक्टर को गुणा करते समय एक अप्रत्याशित परिणाम (एक त्रुटि देने के बजाय) वापस करेगा। साथ ही निर्देशांक पूर्णांक होना चाहिए।
user202729

8

FYI करें paper.js इस मुद्दे को हल करता है कागज़ की रचना, एक स्व-निहित, स्कोप्ड जावास्क्रिप्ट को संचालकों के ओवरलोडिंग वाले वैक्टर के साथ, जो तब इसे जावास्क्रिप्ट में वापस संसाधित करता है।

लेकिन कागजी फाइलों को विशेष रूप से निर्दिष्ट और संसाधित करने की आवश्यकता होती है।


6

दरअसल, जावास्क्रिप्ट का एक संस्करण है जो ऑपरेटर को ओवरलोडिंग का समर्थन करता है । एक्स्टेंडस्क्रिप्ट, एडोब एप्लिकेशन जैसे फोटोशॉप और इलस्ट्रेटर द्वारा उपयोग की जाने वाली स्क्रिप्टिंग भाषा में ऑपरेटर ओवरलोडिंग है। इसमें आप लिख सकते हैं:

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;

यह "एडोब एक्सटेंडस्क्रिप्ट जावास्क्रिप्ट टूल गाइड" ( यहां वर्तमान लिंक ) में अधिक विस्तार से वर्णित है । सिंटैक्स जाहिरा तौर पर ECMAScript मानक के एक (अब लंबे समय तक परित्यक्त) मसौदे पर आधारित था।


9
एक्सटेंडस्क्रिप्ट्स! = जावास्क्रिप्ट
एंड्रियो स्कुर

1
पेपरस्क्रिप्ट उत्तर को अपवोट किए जाने पर एक्स्टेंडस्क्रिप्ट उत्तर को क्यों डाउनवोट किया गया है? IMHO यह उत्तर भी अच्छा है।
xmedeko

4

वेक्टर गणित दो नंबरों के साथ करना संभव है। इससे पहले कि मैं यह बताऊं कि यह कैसे काम करता है:

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

मैं इस तथ्य का उपयोग कर रहा हूं कि यदि आप दो बार एक्स संख्या को शिफ्ट करते हैं और फिर उन्हें वापस शिफ्ट करने से पहले उन्हें जोड़ते या घटाते हैं, तो आपको वही परिणाम मिलेगा जैसे कि आपने उन्हें शुरू करने के लिए स्थानांतरित नहीं किया था। इसी तरह स्केलर गुणन और विभाजन शिफ्ट किए गए मूल्यों के लिए सममित रूप से काम करता है।

एक जावास्क्रिप्ट संख्या में पूर्णांक सटीकता (64 बिट फ़्लोट्स) के 52 बिट्स हैं, इसलिए मैं एक संख्या को 26 उपलब्ध बिट्स, और एक निचले हिस्से में पैक करूँगा। कोड को थोड़ा अधिक गड़बड़ कर दिया गया है क्योंकि मैं हस्ताक्षरित संख्याओं का समर्थन करना चाहता था।

function vec_pack(vec){
    return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);
}

function vec_unpack(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;
    }
}

इसके साथ मैं केवल यह देख सकता हूं कि x और y की सीमा + -33 मिलियन में है, क्योंकि उन्हें प्रत्येक 26 बिट के भीतर फिट होना है।


Vec_pack की परिभाषा कहाँ है?
घृणित

1
@Disgusting हम्म सॉरी, ऐसा लग रहा है कि मैं इसे जोड़ना भूल गया हूँ ... जो अब तय हो गया है :)
Stuffe

3

प्रश्न का सटीक उत्तर न देते हुए, ESP सिम्पटम्स का उपयोग करते हुए कुछ अजगर __magic__ विधियों को लागू करना संभव है

एक [Symbol.toPrimitive]()विधि आपको कॉल करने की अनुमति नहीं देती है Vector.add(), लेकिन आपको सिंटैक्स का उपयोग करने देगी Decimal() + int

class AnswerToLifeAndUniverseAndEverything {
    [Symbol.toPrimitive](hint) {
        if (hint === 'string') {
            return 'Like, 42, man';
        } else if (hint === 'number') {
            return 42;
        } else {
            // when pushed, most classes (except Date)
            // default to returning a number primitive
            return 42;
        }
    }
}


2

हम valueOfप्रत्येक पुनरावृत्ति पर विधि से विभिन्न मानों के साथ तीर फ़ंक्शन का मूल्यांकन करने के लिए रिएक्ट-जैसे हुक का उपयोग कर सकते हैं ।

const a = Vector2(1, 2) // [1, 2]
const b = Vector2(2, 4) // [2, 4]    
const c = Vector2(() => (2 * a + b) / 2) // [2, 4]
// There arrow function will iterate twice
// 1 iteration: method valueOf return X component
// 2 iteration: method valueOf return Y component

लाइब्रेरी @ js- मूल / वेक्टर वेक्टर 3 के लिए एक ही विचार का उपयोग करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.