जावास्क्रिप्ट में कक्षा बनाम स्थिर विधि


262

मुझे पता है कि यह काम करेगा:

function Foo() {};
Foo.prototype.talk = function () {
    alert('hello~\n');
};

var a = new Foo;
a.talk(); // 'hello~\n'

लेकिन अगर मैं बुलाना चाहता हूं

Foo.talk() // this will not work
Foo.prototype.talk() // this works correctly

मुझे Foo.talkकाम करने के कुछ तरीके मिलते हैं,

  1. Foo.__proto__ = Foo.prototype
  2. Foo.talk = Foo.prototype.talk

क्या ऐसा करने के अन्य तरीके हैं? मुझे नहीं पता कि ऐसा करना सही है या नहीं। क्या आप अपने जावास्क्रिप्ट कोड में वर्ग विधियों या स्थिर तरीकों का उपयोग करते हैं?



1
@downvoterstepintothelight Foo.walk = function() {}इसके उदाहरणों को प्रभावित नहीं करेगा, क्योंकि यह प्रोटोटाइप श्रृंखला पर नहीं है। क्या क्रॉस-ब्राउज़र एक फ़ंक्शन का [[prototype]]बिंदु बनाने के लिए एक विधि है prototype?
खो दिया है

3
शायद मुझे पता नहीं है कि आप क्या चाहते हैं, क्योंकि वर्ग विधियाँ परिभाषाओं को प्रभावित नहीं करती हैं
समयपूर्व अनुकूलन

@downvoterstepintothelight मुझे संदेह है कि, विधि , भाषा में अजगर की तरह, एक उदाहरण अपनी कक्षा विधि को कॉल करने में सक्षम है, अंतर thisसूचक है।
3

जवाबों:


410

सबसे पहले, याद रखें कि क्लास-आधारित भाषा 1 के बजाय जावास्क्रिप्ट मुख्य रूप से एक प्रोटोटाइप भाषा है । एक वर्ग नहीं है, यह एक कार्य है, जो एक वस्तु है। आप उस फ़ंक्शन से किसी ऑब्जेक्ट को कीवर्ड का उपयोग करके तुरंत कर सकते हैं जो आपको मानक ओओपी भाषा में कक्षा के समान कुछ बनाने की अनुमति देगा।Foonew

मैं __proto__ज्यादातर समय यह अनदेखा करने का सुझाव दूंगा क्योंकि इसमें खराब क्रॉस ब्राउज़र समर्थन है, और इसके बजाय यह सीखने पर ध्यान केंद्रित prototypeकरता है कि कैसे काम करता है।

यदि आपके पास किसी फ़ंक्शन 2 से बनाई गई किसी ऑब्जेक्ट का एक उदाहरण है और आप किसी भी तरह से उसके किसी सदस्य (तरीके, गुण, गुण, स्थिरांक आदि) तक पहुंचते हैं, तो पहुंच प्रोटोटाइप पदानुक्रम तक नीचे बह जाएगा, जब तक कि यह (ए) नहीं मिल जाता है सदस्य, या (बी) एक और प्रोटोटाइप नहीं ढूंढता है।

पदानुक्रम उस ऑब्जेक्ट पर शुरू होता है जिसे बुलाया गया था, और फिर अपनी प्रोटोटाइप ऑब्जेक्ट को खोजता है। यदि प्रोटोटाइप ऑब्जेक्ट का प्रोटोटाइप है, तो वह दोहराता है, अगर कोई प्रोटोटाइप मौजूद नहीं है, undefinedतो वापस लौटा दिया जाता है।

उदाहरण के लिए:

foo = {bar: 'baz'};
console.log(foo.bar); // logs "baz"

foo = {};
console.log(foo.bar); // logs undefined

function Foo(){}
Foo.prototype = {bar: 'baz'};
f = new Foo();
console.log(f.bar);
// logs "baz" because the object f doesn't have an attribute "bar"
// so it checks the prototype
f.bar = 'buzz';
console.log( f.bar ); // logs "buzz" because f has an attribute "bar" set

यह मुझे ऐसा लगता है कि आपने कम से कम इन "बुनियादी" भागों को पहले से ही समझ लिया है, लेकिन मुझे यह सुनिश्चित करने के लिए उन्हें स्पष्ट करने की आवश्यकता है।

जावास्क्रिप्ट में, सब कुछ एक वस्तु 3 है

सब कुछ एक वस्तु है।

function Foo(){}केवल एक नए फ़ंक्शन को परिभाषित नहीं करता है, यह एक नई फ़ंक्शन ऑब्जेक्ट को परिभाषित करता है जिसका उपयोग करके एक्सेस किया जा सकता है Foo

यही कारण है कि आप के Fooसाथ प्रोटोटाइप का उपयोग कर सकते हैं Foo.prototype

आप जो भी कर सकते हैं, उस पर अधिक कार्य सेट किए गए हैं Foo:

Foo.talk = function () {
  alert('hello world!');
};

इस नए फ़ंक्शन का उपयोग करके पहुँचा जा सकता है:

Foo.talk();

मुझे उम्मीद है कि अब तक आप एक फंक्शन ऑब्जेक्ट और स्टैटिक मेथड पर फंक्शन्स के बीच समानता नहीं दिखा रहे हैं।

f = new Foo();कक्षा के लिए Foo.prototype.bar = function(){...}एक साझा पद्धति Foo.baz = function(){...}को परिभाषित करने और वर्ग के लिए एक सार्वजनिक स्थैतिक विधि को परिभाषित करने के रूप में एक वर्ग उदाहरण बनाने के बारे में सोचें ।


ECMAScript 2015 ने इस प्रकार की घोषणाओं के लिए विभिन्न प्रकार की सिंथैटिक शुगर पेश की, जो कि उन्हें सरल बनाने के लिए लागू करने के लिए भी आसान थी। पिछले उदाहरण को इस प्रकार लिखा जा सकता है:

class Foo {
  bar() {...}

  static baz() {...}
}

जो के barरूप में बुलाया जा सकता है:

const f = new Foo()
f.bar()

और इस bazरूप में बुलाया जा सकता है:

Foo.baz()

1: classECMAScript 5 विनिर्देश में "फ्यूचर रिज़र्व्ड वर्ड" था , लेकिन ES6 classकीवर्ड का उपयोग करके कक्षाओं को परिभाषित करने की क्षमता का परिचय देता है ।

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

3: आदिम मूल्य -जिसमें शामिल हैं undefined, nullबूलियन, संख्या, और तार-तकनीकी रूप से ऑब्जेक्ट नहीं हैं क्योंकि वे निम्न-स्तर के अनुप्रयोग हैं। बूलियन, संख्या और तार अभी भी प्रोटोटाइप श्रृंखला के साथ बातचीत करते हैं जैसे कि वे ऑब्जेक्ट थे, इसलिए इस उत्तर के प्रयोजनों के लिए, उन्हें "ऑब्जेक्ट" पर विचार करना आसान है, भले ही वे काफी नहीं हैं।


1
@lostyzd - ठीक है, वे इसके माध्यम से पहुँच सकते हैं Foo.talk()। यदि आप चाहते हैं कि आप कंस्ट्रक्टर में असाइन कर सकते हैं: this.talk = Foo.talk- या, जैसा कि आप ध्यान दें, असाइन करके Foo.prototype.talk = Foo.talk। लेकिन मुझे यकीन नहीं है कि यह एक अच्छा विचार है - सिद्धांत पर, उदाहरण के तरीके उदाहरण के लिए विशिष्ट होना चाहिए।
nrabinowitz

2
@ डौग एवरी, Foo.talk()बस एक नामांकित फ़ंक्शन को बुला रहा है। आप इसका उपयोग स्थितियों में इसी तरह से करेंगे कि कैसे स्थैतिक तरीकों को OOP भाषाओं में जावा / C # कहा जाता है। एक उपयोग के मामले का एक अच्छा उदाहरण एक समारोह होगा Array.isArray()
zzzzBov

7
PS null ऑब्जेक्ट
टाइपोफ़

1
आपके द्वारा याद किए जा रहे मूल बिंदु यह है कि स्थिर तरीके विरासत में मिले हैं। Foo.talk = function ()...वहाँ वर्ग के नाम पर उपवर्गों के लिए उपलब्ध नहीं होगा। यह "विस्तार" उपवर्गों के आसपास काम कर सकता है, लेकिन मैं अभी भी अधिक सुरुचिपूर्ण तरीके की तलाश कर रहा हूं।

1
@ केवल, कुछ भाषाएँ ही स्थैतिक विधियों को विरासत में प्राप्त करने की अनुमति देती हैं। यदि वंशानुक्रम वांछित है, तो आपको शुरू करने के लिए स्थैतिक तरीकों का उपयोग नहीं करना चाहिए।
zzzzBov

67

आप इसे नीचे के रूप में प्राप्त कर सकते हैं:

function Foo() {};

Foo.talk = function() { alert('I am talking.'); };

अब आप "टॉक" फ़ंक्शन को नीचे के रूप में लागू कर सकते हैं:

Foo.talk();

आप ऐसा कर सकते हैं क्योंकि जावास्क्रिप्ट में, फ़ंक्शन भी ऑब्जेक्ट हैं।


37

किसी स्थिर विधि को उदाहरण से कॉल करें:

function Clazz() {};
Clazz.staticMethod = function() {
    alert('STATIC!!!');
};

Clazz.prototype.func = function() {
    this.constructor.staticMethod();
}

var obj = new Clazz();
obj.func(); // <- Alert's "STATIC!!!"

सरल जावास्क्रिप्ट क्लास प्रोजेक्ट: https://github.com/reduardo7/sjsClass


13
यह एक स्थिर कॉल नहीं है। var obj = new Clazz (); Clazz का एक नया उदाहरण बनाता है । हालाँकि, Clazz.staticMethod () उस अन्य सामान के बिना परिणाम प्राप्त करता है।
11

5
@ चैंपियन: एडुआर्डो भी अपने जवाब में सही है। वह जो आपको दिखा रहा है वह न केवल आप "बाहर" से स्थैतिक विधि को कॉल कर सकते हैं, Clazz.staticMethodबल्कि वह आपको दिखा रहा है कि इन स्थिर तरीकों से तात्कालिक वस्तु से कैसे लिंक किया जाए। यह विशेष रूप से Node.js जैसे वातावरण में उपयोगी है, जहां आवश्यकता का उपयोग करके, आपके पास मूल निर्माता तक सीधी पहुंच नहीं हो सकती है। केवल एक चीज जो मैं this.constructor.staticMethod.apply(this, arguments);
जोड़ूंगा

1
पूरी तरह से भयानक, यहां तक ​​कि एक कॉफी-स्क्रिप्ट निर्माता के अंदर भी काम करता है: constructor: (a) -> @constructor.add @(अच्छी तरह से लगभग, वैसे भी)
ऑरवेलोफाइल

31

यहाँ यह प्रदर्शित करने के लिए एक अच्छा उदाहरण है कि जावास्क्रिप्ट स्थिर / आवृत्ति चर और विधियों के साथ कैसे काम करता है।

function Animal(name) {
    Animal.count = Animal.count+1||1;// static variables, use function name "Animal"
    this.name = name; //instance variable, using "this"
}

Animal.showCount = function () {//static method
    alert(Animal.count)
}

Animal.prototype.showName=function(){//instance method
    alert(this.name);
}

var mouse = new Animal("Mickey");
var elephant = new Animal("Haddoop");

Animal.showCount();  // static method, count=2
mouse.showName();//instance method, alert "Mickey"
mouse.showCount();//Error!! mouse.showCount is not a function, which is different from  Java

अच्छा बिंदु: यह अजीब हो सकता है के माध्यम से स्थिर समारोह तक पहुँच नहीं है this
ट्रैप II

समाधान के लिए धन्यवाद यह वही है जो मैं देख रहा था कि किस स्थिति में thisकीवर्ड की पहुंच होगी
santhosh

30

परिवर्धन में, अब यह करना संभव है classऔरstatic

'use strict'

class Foo {
 static talk() {
     console.log('talk')
 };

 speak() {
     console.log('speak')
 };

};

दे देंगे

var a = new Foo();
Foo.talk();  // 'talk'
a.talk();    // err 'is not a function'
a.speak();   // 'speak'
Foo.speak(); // err 'is not a function'

यह सबसे अच्छा जवाब है, क्योंकि उदाहरण एक हजार शब्दों के लायक हैं। हालाँकि, यह नहीं समझाता है कि a.talk()काम क्यों नहीं करता है। स्वीकृत उत्तर कहता है कि प्रोटोटाइप की श्रृंखला को इसे ढूंढना चाहिए, है ना? लेकिन यह मामला नहीं है
Pynchia

11

मैं नामस्थान का उपयोग करता हूं:

var Foo = {
     element: document.getElementById("id-here"),

     Talk: function(message) {
            alert("talking..." + message);
     },

     ChangeElement: function() {
            this.element.style.color = "red";
     }
};

और इसका उपयोग करने के लिए:

Foo.Talk("Testing");

या

Foo.ChangeElement();

6

ES6 अब एक आकर्षण की तरह classऔर staticकीवर्ड का समर्थन करता है :

class Foo {
    constructor() {}

    talk() {
        console.log("i am not static");
    }

    static saying() {
        console.log(this.speech);
    }

    static get speech() {
        return "i am static method";
    }

}

मैं ऐसे ही उत्तर की तलाश में था। क्या स्थैतिक विधि गैर-स्थैतिक विधियों / चर को बुला सकती है?
टॉमाज़ मूलार्क

1
@ टॉमाज़ स्टैटिक विधियों में वर्ग के किसी भी उदाहरण के लिए सेट नहीं किया जाएगा, बल्कि स्वयं कक्षा। तो बेशक, एक स्थैतिक विधि एक इंस्टेंस विधि कह सकती है , लेकिन केवल अगर यह किसी तरह एक इंस्टेंस तक पहुंच है, जैसे कि ethstatic staticMethod () {new Foo ()। Talk ()। }}
JHH

3

यदि आपको ES5 में स्थिर तरीके लिखना है तो मुझे इसके लिए एक बढ़िया ट्यूटोरियल मिला:

//Constructor
var Person = function (name, age){
//private properties
var priv = {};

//Public properties
this.name = name;
this.age = age;

//Public methods
this.sayHi = function(){
    alert('hello');
}
}


// A static method; this method only 
// exists on the class and doesn't exist  
// on child objects
Person.sayName = function() {
   alert("I am a Person object ;)");  
};

देखें @ https://abdulapopoola.com/2013/03/30/static-and-instance-methods-in-javascript/


2

सिर्फ अतिरिक्त नोट्स। कक्षा 6 ईएस 6 का उपयोग करते हुए, जब हम स्थैतिक विधियाँ बनाते हैं..जवास्क्रीप्ट इंजन ने डिस्क्रिप्टर की विशेषता को पुराने-विद्यालय "स्टैटिक" विधि से अलग लिल बिट के रूप में निर्धारित किया है।

function Car() {

}

Car.brand = function() {
  console.log('Honda');
}

console.log(
  Object.getOwnPropertyDescriptors(Car)
);

यह ब्रांड () से () के लिए आंतरिक विशेषता (डिस्क्रिप्टर गुण) सेट करता है

..
brand: [object Object] {
    configurable: true,
    enumerable: true,
    value: ..
    writable: true

}
..

की तुलना में

class Car2 {
   static brand() {
     console.log('Honda');
   }
}

console.log(
  Object.getOwnPropertyDescriptors(Car2)
);

कि ब्रांड () के लिए आंतरिक विशेषता सेट करता है

..
brand: [object Object] {
    configurable: true,
    enumerable: false,
    value:..
    writable: true
  }

..

देखते हैं कि गणनीय पर सेट है झूठी ES6 में स्थिर विधि के लिए।

इसका मतलब है कि आप वस्तु की जांच के लिए फॉर-इन लूप का उपयोग नहीं कर सकते

for (let prop in Car) {
  console.log(prop); // brand
}

for (let prop in Car2) {
  console.log(prop); // nothing here
}

ईएस 6 में स्थैतिक विधि को अन्य श्रेणी की निजी संपत्ति (नाम, लंबाई, निर्माणकर्ता) की तरह माना जाता है, सिवाय इसके कि स्थिर विधि अभी भी लिखने योग्य है, इस प्रकार वर्णनात्मक लेखन सत्य पर सेट है{ writable: true } । इसका यह भी अर्थ है कि हम इसे ओवरराइड कर सकते हैं

Car2.brand = function() {
   console.log('Toyota');
};

console.log(
  Car2.brand() // is now changed to toyota
);

1

जब आप कॉल करने के लिए कोशिश Foo.talk, जे एस एक समारोह खोज करने के लिए कोशिश करता है talkके माध्यम से __proto__और, ज़ाहिर है, यह नहीं पाया जा सकता है।

Foo.__proto__है Function.prototype


1

स्टेटिक मेथड कॉल सीधे क्लास पर किए जाते हैं और क्लास के इंस्टेंस पर कॉल करने योग्य नहीं होते हैं। यूटिलिटी फंक्शन बनाने के लिए स्टैटिक तरीकों का इस्तेमाल अक्सर किया जाता है

बहुत स्पष्ट वर्णन

सीधे mozilla.org से लिया गया

फू को अपनी कक्षा के लिए बाध्य करने की आवश्यकता है तब जब आप एक नया उदाहरण बनाते हैं तो आप myNewInstance.foo () को कॉल कर सकते हैं यदि आप अपनी कक्षा को आयात करते हैं तो आप एक स्थैतिक विधि को कॉल कर सकते हैं


0

जब मैंने ऐसी स्थिति का सामना किया, तो मैंने कुछ ऐसा किया है:

Logger = {
    info: function (message, tag) {
        var fullMessage = '';        
        fullMessage = this._getFormatedMessage(message, tag);
        if (loggerEnabled) {
            console.log(fullMessage);
        }
    },
    warning: function (message, tag) {
        var fullMessage = '';
        fullMessage = this._getFormatedMessage(message, tag);
        if (loggerEnabled) {
            console.warn(fullMessage);`enter code here`
        }
    },
    _getFormatedMessage: function () {}
};

तो अब मैं जानकारी विधि के रूप में कॉल कर सकते हैं Logger.info("my Msg", "Tag");


मैं यह हर समय करता हूं, लेकिन यह मूल रूप से केवल नामस्थान है। यह आपको उदाहरण var के साथ उदाहरण बनाने की अनुमति नहीं देता है?
dcsan

0

आपके मामले में, यदि आप चाहते हैं Foo.talk():

function Foo() {};
// But use Foo.talk would be inefficient
Foo.talk = function () {
    alert('hello~\n');
};

Foo.talk(); // 'hello~\n'

लेकिन इसे लागू करने का एक अक्षम तरीका prototypeबेहतर है।


एक और तरीका, मेरा रास्ता स्थिर वर्ग के रूप में परिभाषित किया गया है:

var Foo = new function() {
  this.talk = function () {
    alert('hello~\n');
    };
};

Foo.talk(); // 'hello~\n'

ऊपर स्थिर वर्ग का उपयोग करने की आवश्यकता नहीं है prototypeक्योंकि यह केवल एक बार स्थिर उपयोग के रूप में निर्मित किया जाएगा।

https://github.com/yidas/js-design-patterns/tree/master/class


@jvitoroc धन्यवाद!
निक

0

जावास्क्रिप्ट में कोई वास्तविक वर्ग नहीं है, बल्कि यह प्रोटोटाइप वंशानुक्रम की एक प्रणाली का उपयोग करता है जिसमें ऑब्जेक्ट अपनी प्रोटोटाइप श्रृंखला के माध्यम से अन्य वस्तुओं से 'विरासत' लेते हैं। यह सबसे अच्छा कोड के माध्यम से ही समझाया गया है:

function Foo() {};
// creates a new function object

Foo.prototype.talk = function () {
    console.log('hello~\n');
};
// put a new function (object) on the prototype (object) of the Foo function object

var a = new Foo;
// When foo is created using the new keyword it automatically has a reference 
// to the prototype property of the Foo function

// We can show this with the following code
console.log(Object.getPrototypeOf(a) === Foo.prototype); 

a.talk(); // 'hello~\n'
// When the talk method is invoked it will first look on the object a for the talk method,
// when this is not present it will look on the prototype of a (i.e. Foo.prototype)

// When you want to call
// Foo.talk();
// this will not work because you haven't put the talk() property on the Foo
// function object. Rather it is located on the prototype property of Foo.

// We could make it work like this:
Foo.sayhi = function () {
    console.log('hello there');
};

Foo.sayhi();
// This works now. However it will not be present on the prototype chain 
// of objects we create out of Foo

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