जावास्क्रिप्ट ओवरराइड विधियों


87

मान लें कि आपके पास निम्न कोड है:

function A() {
    function modify() {
       x = 300;
       y = 400;
    }

    var c = new C();
}

function B() {
    function modify(){
       x = 3000;
       y = 4000;
    }

    var c = new C();
}

C = function () {
   var x = 10;
   var y = 20;

   function modify() {
      x = 30;
      y = 40;
   };

   modify();
   alert("The sum is: " + (x+y));
}

अब सवाल यह है कि यदि कोई तरीका है जिसमें मैं उस विधि modifyसे ओवरराइड कर सकता हूं जो Cकि Aऔर में हैं B। जावा में आप super-keyword का उपयोग करेंगे , लेकिन आप जावास्क्रिप्ट में ऐसा कुछ कैसे प्राप्त कर सकते हैं?


6
modifyएक विधि नहीं है, लेकिन एक नेस्टेड फ़ंक्शन है - उन दोनों के बीच अंतर है ...
Julime Vidas

2
जावा में आप गैर-निजी क्षेत्रों और सुपर-क्लास के तरीकों का उपयोग करने के लिए superकीवर्ड का उपयोग करते हैं। आप उन्हें ओवरराइड करने के लिए इसका उपयोग नहीं करते हैं।
FK82

जवाबों:


138

संपादित करें: मूल उत्तर लिखे जाने के बाद अब छह साल हो गए हैं और बहुत कुछ बदल गया है!

  • यदि आप जावास्क्रिप्ट के एक नए संस्करण का उपयोग कर रहे हैं, संभवतः बाबेल जैसे उपकरण के साथ संकलित किया गया है , तो आप वास्तविक कक्षाओं का उपयोग कर सकते हैं
  • यदि आप कोणीय या रिएक्ट द्वारा प्रदान किए गए क्लास-जैसे घटक कंस्ट्रक्टर्स का उपयोग कर रहे हैं , तो आप उस फ्रेमवर्क के लिए डॉक्स में देखना चाहेंगे।
  • यदि आप ईएस 5 का उपयोग कर रहे हैं और प्रोटोटाइप का उपयोग करके "नकली" कक्षाएं बना रहे हैं, तो नीचे दिया गया उत्तर अभी भी उतना ही सही है जितना कभी था।

सौभाग्य!


जावास्क्रिप्ट उत्तराधिकार जावा से थोड़ा अलग दिखता है। यहां बताया गया है कि देशी जावास्क्रिप्ट ऑब्जेक्ट सिस्टम कैसा दिखता है:

// Create a class
function Vehicle(color){
  this.color = color;
}

// Add an instance method
Vehicle.prototype.go = function(){
  return "Underway in " + this.color;
}

// Add a second class
function Car(color){
  this.color = color;
}

// And declare it is a subclass of the first
Car.prototype = new Vehicle();

// Override the instance method
Car.prototype.go = function(){
  return Vehicle.prototype.go.call(this) + " car"
}

// Create some instances and see the overridden behavior.
var v = new Vehicle("blue");
v.go() // "Underway in blue"

var c = new Car("red");
c.go() // "Underway in red car"

दुर्भाग्य से यह थोड़ा बदसूरत है और इसमें "सुपर" का बहुत अच्छा तरीका शामिल नहीं है: आपको मैन्युअल रूप से निर्दिष्ट करना होगा कि आप किस माता-पिता की पद्धति को कॉल करना चाहते हैं। नतीजतन, कक्षाओं के अच्छे बनाने के लिए विभिन्न प्रकार के उपकरण हैं। Prototyp.js, Backbone.js, या इसी तरह की लाइब्रेरी को देखने की कोशिश करें जिसमें js में OOP करने के लिए एक अच्छे सिंटैक्स शामिल हों।


2
वैकल्पिक रूप से "कक्षाओं को अच्छा बनाने के लिए" बनाने के लिए एक उपकरण का उपयोग करने के लिए आप बिल्कुल भी कक्षाएं नहीं बना सकते हैं। Js में शास्त्रीय OO अनुकरण हमेशा गड़बड़ हो जाता है।
रेयानोस

1
(रचनात्मक टिप्पणी नहीं) ब्राउज़र की दुनिया में "निम्न स्तर" भाषा होने के लिए बिना किसी कारण के बहुत बदसूरत है। फिर भी इसे सीख रहे हैं, धन्यवाद!
dnuske

9
मैं Car.prototyp = नए वाहन () के बजाय विश्वास करता हूं; यह Car.prototype = Object.create (Vehicle.prototype) होना चाहिए; नहीं?
जॉर्डन

@ मर्टिन सही है, जावास्क्रिप्ट-विरासत
matoni

कारणों में से एक क्यों Car.prototype = new Vehicle (); वाहन को पास करने के लिए कुछ भी नहीं होने के कारण गलत है () जबकि यह एक रंग प्राप्त करता है।
तुषार अरोड़ा

62

चूंकि यह Google पर एक शीर्ष हिट है, मैं एक अद्यतन जवाब देना चाहूंगा।

ES6 वर्गों का उपयोग वंशानुक्रम और विधि को बहुत आसान बनाता है:

'use strict';

class A {
    speak() {
        console.log("I'm A");
    }
}

class B extends A {
    speak() {
        super.speak();

        console.log("I'm B");
    }
}

var a = new A();
a.speak();
// Output:
// I'm A

var b = new B();
b.speak();
// Output:
// I'm A
// I'm B

superकीवर्ड जब इनहेरिट वर्ग में इस्तेमाल किया माता-पिता वर्ग को दर्शाता है। इसके अलावा, अभिभावक वर्ग के सभी तरीके बच्चे के उदाहरण से बंधे हैं, इसलिए आपको लिखना नहीं है super.method.apply(this);

अनुकूलता के लिए: ES6 संगतता तालिका केवल प्रमुख खिलाड़ियों के सबसे हाल के संस्करणों का समर्थन करती है (अधिकतर)। V8 ब्राउज़रों ने उन्हें इस साल जनवरी (क्रोम और ओपेरा) के बाद से लिया है, और फ़ायरफ़ॉक्स, स्पाइडरमोंक जेएस इंजन का उपयोग करते हुए, अगले महीने अपने आधिकारिक फ़ायरफ़ॉक्स 45 रिलीज के साथ कक्षाएं देखेंगे। मोबाइल पक्ष पर, Android अभी भी इस सुविधा का समर्थन नहीं करता है, जबकि iOS 9, पांच महीने पहले जारी किया गया था, इसमें आंशिक समर्थन है।

सौभाग्य से, ईएस 5 कोड में हार्मनी कोड को फिर से संकलित करने के लिए जेएस लाइब्रेरी, बैबेल है । ईएस 6 में कक्षाएं, और कई अन्य शांत विशेषताएं आपके जावास्क्रिप्ट कोड को बहुत अधिक पठनीय और बनाए रखने योग्य बना सकती हैं।


10
यह उत्तर अधिक श्रेय का हकदार है और वर्तमान में सही उत्तर है।
क्लोम्पेन्रनर

6

एक बार शास्त्रीय OO के अनुकरण से बचना चाहिए और इसके बजाय प्रोटोटाइप OO का उपयोग करना चाहिए। प्रोटोटाइप OO के लिए एक अच्छी उपयोगिता पुस्तकालय लक्षण है

इसके बजाय, तरीकों को अधिलेखित करने और वंशानुक्रम श्रंखलाओं को स्थापित करने के लिए (किसी को हमेशा वस्तु संरचना पर वस्तु रचना का पक्ष लेना चाहिए) आपको पुन: प्रयोज्य कार्यों को लक्षणों में बांधना चाहिए और उन लोगों के साथ वस्तुओं का निर्माण करना चाहिए।

लाइव उदाहरण

var modifyA = {
    modify: function() {
        this.x = 300;
        this.y = 400;
    }
};

var modifyB = {
    modify: function() {
        this.x = 3000;
        this.y = 4000;
    }
};

C = function(trait) {
    var o = Object.create(Object.prototype, Trait(trait));

    o.modify();
    console.log("sum : " + (o.x + o.y));

    return o;
}

//C(modifyA);
C(modifyB);

10
आप सवाल का जवाब नहीं दे रहे हैं। अगर कुछ भी हो तो यह टिप्पणी होनी चाहिए।
FK82


3

आपके उदाहरण में संशोधित () एक निजी फ़ंक्शन है, जो कहीं से भी आपके ए, बी या सी परिभाषा के भीतर सुलभ नहीं होगा। आपको इसे घोषित करने की आवश्यकता होगी

this.modify = function(){}

C के पास अपने माता-पिता के लिए कोई संदर्भ नहीं है, जब तक कि आप इसे C को पास नहीं करते हैं। यदि C को A या B से उत्तराधिकार के लिए सेट किया गया है, तो यह उसके सार्वजनिक तरीकों (जैसे आपके निजी कार्यों को संशोधित () परिभाषित) नहीं करेगा। एक बार C अपने माता-पिता से विरासत में मिली विधियां, आप विरासत में मिली विधियों को ओवरराइड कर सकते हैं।


संशोधित एक स्थानीय कार्य है। जावास्क्रिप्ट में कोई निजी नहीं है
रेयोनोस

स्थानीय / निजी, एक ही बात नहीं है, बस एक अलग शब्द?
एलेक्स हेयड

2

विधि modify()है कि आप पिछले में कहा जाता है वैश्विक संदर्भ में कहा जाता है अगर आप ओवरराइड करना चाहते modify()आप पहली बार वारिस के लिए है Aया B

शायद आप ऐसा करने की कोशिश कर रहे हैं:

इस मामले में Cविरासत मेंA

function A() {
    this.modify = function() {
        alert("in A");
    }
}

function B() {
    this.modify = function() {
        alert("in B");
    }
}

C = function() {
    this.modify = function() {
        alert("in C");
    };

    C.prototype.modify(); // you can call this method where you need to call modify of the parent class
}

C.prototype = new A();

1
C.prototype.modify()गलत thisमान होगा। अर्थात् C.prototypeबजाय ग के कहने का। कृपया उपयोग करें .call(this)लेकिन फिर आपका उत्तर सिर्फ एक डुप्लिकेट है :)
रेयनोस

1

जब तक आप सभी चर "सार्वजनिक" नहीं बनाते हैं, यानी उन्हें Functionसीधे या prototypeसंपत्ति के माध्यम से सदस्य बनाते हैं।

var C = function( ) {
    this.x = 10 , this.y = 20 ;
    this.modify = function( ) {
        this.x = 30 , this.y = 40 ;
        console.log("(!) C >> " + (this.x + this.y) ) ;
    } ;
} ;

var A = function( ) {
    this.modify = function( ) {
       this.x = 300 , this.y = 400 ;
       console.log("(!) A >> " + (this.x + this.y) ) ;
    } ;
} ;
    A.prototype = new C ;

var B = function( ) {
    this.modify = function( ) {
       this.x = 3000 , this.y = 4000 ;
       console.log("(!) B >> " + (this.x + this.y) ) ;
    } ;
} ;


new C( ).modify( ) ;
new A( ).modify( ) ;
new B( ).modify( ) ; 

आप कुछ बदलाव देखेंगे।

सबसे महत्वपूर्ण माना जाता है कि "सुपर-क्लास" कंस्ट्रक्टर को कॉल अब इस पंक्ति में निहित है:

<name>.prototype = new C ;

दोनों Aऔर Bअब होगा व्यक्तिगत रूप से परिवर्तनीय सदस्यों xऔर yजो मामले अगर हम लिखा है | नहीं होगा ... = Cबजाय।

फिर, x, yऔर modifyसब "सार्वजनिक" के सदस्यों को तो एक अलग बताए जाते हैं कि Functionउन्हें

 <name>.prototype.modify = function( ) { /* ... */ }

Functionउस नाम से मूल को "ओवरराइड" करेगा ।

अंत में, कॉल को घोषणा modifyमें नहीं किया जा सकता है Functionक्योंकि "सुपर-क्लास" के लिए निहित कॉल तब फिर से निष्पादित की जाएगी जब हम prototype"उप-वर्ग" की संपत्ति को "सुपर-क्लास" माना जाएगा।

लेकिन ठीक है, यह कम या ज्यादा है कि आप जावास्क्रिप्ट में इस तरह का काम कैसे करेंगे।

HTH,

FK


<name>.prototype = new C;वैसे भी प्रोटोटाइप के सभी सदस्यों को आपकी
छाया

@ रेयानोस: हाँ वहाँ है। बुद्धि के लिए, सभी विरासत Objectsएक ही सदस्य को साझा करेंगे Cयदि आप किसी Cवस्तु को तुरंत नहीं करते हैं । इस प्रकार, बदलते xमें Aबदल जाएगा xमें Cहै और इस तरह बदलने xमें B। जो स्पष्ट रूप से अवांछनीय है।
FK82

तुम चूक गए। आप लाइन को हटा सकते हैं और कोड अभी भी कार्य करेगा
रेयनोस

@ रेयानोस: आपको अपनी ही बात याद आ रही है मुझे डर लग रहा है। ;-) हम चाहते हैं Aऔर Bविरासत से चाहते हैं C। अगर वह रेखा गायब होगी, तो ऐसा नहीं होगा। वास्तव में एकमात्र प्रोटोटाइप और Aसाथ ही B"छाया" दोनों का उपयोग उस मामले में होगा Object.prototype
FK82

कोड को देखो। A और B, C के किसी भी सदस्य के प्रोटोटाइप का उपयोग नहीं करते हैं। इसलिए सी से "विरासत" बेकार है। इसका कारण यह है ए और बी को फिर से परिभाषित x, yऔर modifyऔर इस तरह के सभी शैडो Cके सदस्य हैं। यदि आपके द्वारा इसका उपयोग नहीं किया जा रहा है तो सी को प्रोटोटाइप में डालने का क्या मतलब है? यह मृत कोड है।
रेयानोस

0

function A() {
    var c = new C();
	c.modify = function(){
		c.x = 123;
		c.y = 333;
	}
	c.sum();
}

function B() {
    var c = new C();
	c.modify = function(){
		c.x = 999;
		c.y = 333;
	}
	c.sum();
}


C = function () {
   this.x = 10;
   this.y = 20;

   this.modify = function() {
      this.x = 30;
      this.y = 40;
   };
   
   this.sum = function(){
	this.modify();
	console.log("The sum is: " + (this.x+this.y));
   }
}

A();
B();

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