कॉलबैक के अंदर सही `this` को कैसे एक्सेस करें?


1425

मेरे पास एक निर्माण कार्य है जो एक घटना हैंडलर को पंजीकृत करता है:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', function () {
        alert(this.data);
    });
}

// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};

// called as
var obj = new MyConstructor('foo', transport);

हालांकि, मैं dataकॉलबैक के अंदर बनाई गई ऑब्जेक्ट की संपत्ति तक पहुंचने में सक्षम नहीं हूं । ऐसा लगता है thisकि उस ऑब्जेक्ट को संदर्भित नहीं करता है जिसे बनाया गया था लेकिन एक दूसरे को।

मैंने एक अनाम फ़ंक्शन के बजाय ऑब्जेक्ट विधि का उपयोग करने का प्रयास किया:

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', this.alert);
}

MyConstructor.prototype.alert = function() {
    alert(this.name);
};

लेकिन यह उन्हीं समस्याओं को प्रदर्शित करता है।

मैं सही वस्तु तक कैसे पहुँच सकता हूँ?


95
मैं समय-समय पर एक निश्चित प्रकार के प्रश्न से इतना तंग आ चुका हूं, कि मैं एक विहित उत्तर लिखने का फैसला करता हूं। भले ही इन सवालों का जवाब एक लाख बार की तरह दिया गया हो, लेकिन यह हमेशा एक अच्छा सवाल + उत्तर जोड़ी खोजने के लिए संभव नहीं है जो अप्रासंगिक जानकारी द्वारा "प्रदूषित" नहीं है। यह उन क्षणों में से एक है और उन सवालों में से एक है (और मैं ऊब गया हूं)। यदि आपको लगता है कि वास्तव में इस प्रकार के प्रश्न के लिए एक अच्छा मौजूदा विहित प्रश्न / उत्तर है, तो मुझे बताएं और मैं इसे हटा दूंगा। सुधार के सुझावों का स्वागत है!
फेलिक्स क्लिंग



3
इस बारे में उपयोगी टाइपस्क्रिप्ट पेज , ज्यादातर जेएस पर भी लागू होता है।
ओंद्रा kaižka

जवाबों:


1790

आपको किस बारे में जानना चाहिए this

this(उर्फ "संदर्भ") प्रत्येक फ़ंक्शन के अंदर एक विशेष कीवर्ड है और इसका मान केवल इस बात पर निर्भर करता है कि फ़ंक्शन को कैसे बुलाया गया था, न कि कैसे / कब / जहां इसे परिभाषित किया गया था। यह अन्य चरों (जैसे तीर के कार्यों को छोड़कर, नीचे देखें) जैसे लेक्सिकल स्कोप से प्रभावित नहीं होता है। यहाँ कुछ उदाहरण हैं:

function foo() {
    console.log(this);
}

// normal function call
foo(); // `this` will refer to `window`

// as object method
var obj = {bar: foo};
obj.bar(); // `this` will refer to `obj`

// as constructor function
new foo(); // `this` will refer to an object that inherits from `foo.prototype`

अधिक जानने के लिए this, MDN प्रलेखन पर एक नज़र डालें ।


सही का संदर्भ कैसे दें this

उपयोग न करें this

आप वास्तव thisमें विशेष रूप से उपयोग नहीं करना चाहते हैं , लेकिन यह जिस वस्तु को संदर्भित करता है । इसलिए एक आसान उपाय यह है कि बस एक नया वैरिएबल बनाया जाए जो उस ऑब्जेक्ट को भी संदर्भित करता है। चर का कोई भी नाम हो सकता है, लेकिन आम हैं selfऔर that

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function() {
        alert(self.data);
    });
}

चूंकि selfयह एक सामान्य चर है, यह लेक्सिकल स्कोप नियमों का पालन करता है और कॉलबैक के अंदर पहुंच योग्य है। इसका यह भी फायदा है कि आप thisकॉलबैक के मूल्य तक पहुँच सकते हैं ।

स्पष्ट रूप thisसे कॉलबैक का सेट - भाग 1

ऐसा लग सकता है कि आपके मूल्य पर कोई नियंत्रण नहीं है thisक्योंकि इसका मूल्य स्वचालित रूप से सेट है, लेकिन वास्तव में ऐसा नहीं है।

प्रत्येक फ़ंक्शन में विधि .bind [डॉक्स] होती है , जो thisएक मान के साथ एक नया फ़ंक्शन लौटाती है । फ़ंक्शन का ठीक वैसा ही व्यवहार होता है जैसा कि आपने कॉल .bindकिया था, केवल वही thisआपके द्वारा सेट किया गया था। कोई फर्क नहीं पड़ता कि कैसे या जब उस फ़ंक्शन को कहा जाता है, thisहमेशा पारित मूल्य को संदर्भित करेगा।

function MyConstructor(data, transport) {
    this.data = data;
    var boundFunction = (function() { // parenthesis are not necessary
        alert(this.data);             // but might improve readability
    }).bind(this); // <- here we are calling `.bind()` 
    transport.on('data', boundFunction);
}

इस मामले में, हम कॉलबैक के लिए बाध्यकारी हैं thisके मूल्य के MyConstructorके this

नोट: जब jQuery के लिए बाध्यकारी संदर्भ, इसके बजाय jQuery.proxy [डॉक्स] का उपयोग करें। ऐसा करने का कारण यह है कि आपको इवेंट कॉलबैक को अनबाइंड करने पर फ़ंक्शन के संदर्भ को संग्रहीत करने की आवश्यकता नहीं है। jQuery कि आंतरिक रूप से संभालता है।

ECMAScript 6: एरो फ़ंक्शंस का उपयोग करें

ECMAScript 6 में तीर के कार्यों का परिचय दिया गया है , जिसे लंबोदर कार्यों के रूप में माना जा सकता है। उनका अपना thisबंधन नहीं है । इसके बजाय, thisएक सामान्य चर की तरह दायरे में देखा जाता है। इसका मतलब है कि आपको कॉल नहीं करना है .bind। उनके पास केवल यही विशेष व्यवहार नहीं है, कृपया अधिक जानकारी के लिए MDN प्रलेखन देखें।

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', () => alert(this.data));
}

thisकॉलबैक का सेट - भाग 2

कॉलबैक को स्वीकार करने वाले कुछ कार्य / तरीके भी एक मूल्य को स्वीकार करते हैं जिसके लिए कॉलबैक thisको संदर्भित करना चाहिए। यह मूल रूप से इसे खुद को बांधने के समान है, लेकिन फ़ंक्शन / विधि यह आपके लिए करता है। Array#map [डॉक्स] एक ऐसी विधि है। इसके हस्ताक्षर हैं:

array.map(callback[, thisArg])

पहला तर्क कॉलबैक है और दूसरा तर्क मूल्य thisको संदर्भित करना चाहिए। यहाँ एक उदाहरण दिया गया है:

var arr = [1, 2, 3];
var obj = {multiplier: 42};

var new_arr = arr.map(function(v) {
    return v * this.multiplier;
}, obj); // <- here we are passing `obj` as second argument

नोट: आप thisउस फ़ंक्शन / विधि के दस्तावेज़ीकरण में आमतौर पर उल्लेखित मूल्य को पास कर सकते हैं या नहीं । उदाहरण के लिए, jQuery की $.ajaxविधि [डॉक्स] नामक एक विकल्प का वर्णन करती है context:

इस ऑब्जेक्ट को सभी अजाक्स-संबंधित कॉलबैक के संदर्भ में बनाया जाएगा।


सामान्य समस्या: कॉलबैक / ईवेंट हैंडलर के रूप में ऑब्जेक्ट विधियों का उपयोग करना

इस समस्या का एक अन्य सामान्य प्रकटीकरण तब होता है जब किसी ऑब्जेक्ट विधि का उपयोग कॉलबैक / ईवेंट हैंडलर के रूप में किया जाता है। फ़ंक्शंस जावास्क्रिप्ट में प्रथम श्रेणी के नागरिक हैं और "विधि" शब्द केवल एक फ़ंक्शन के लिए बोलचाल का शब्द है जो एक वस्तु संपत्ति का एक मूल्य है। लेकिन उस फ़ंक्शन का उसके "ऑब्जेक्ट" से कोई विशिष्ट लिंक नहीं है।

निम्नलिखित उदाहरण पर विचार करें:

function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = function() {
    console.log(this.data);
};

समारोह this.methodके रूप में क्लिक करें ईवेंट हैंडलर असाइन किया गया है, लेकिन अगर document.bodyक्लिक किया जाता है, मूल्य लॉग इन किया जाएगा undefined, क्योंकि ईवेंट हैंडलर के अंदर, thisको संदर्भित करता है document.bodyकी, नहीं उदाहरण Foo
जैसा कि शुरुआत में पहले ही उल्लेख किया गया है, जो इस thisबात पर निर्भर करता है कि फ़ंक्शन कैसे कहा जाता है , न कि इसे कैसे परिभाषित किया जाता है
यदि कोड निम्न जैसा था, तो यह अधिक स्पष्ट हो सकता है कि फ़ंक्शन में ऑब्जेक्ट का कोई निहित संदर्भ नहीं है:

function method() {
    console.log(this.data);
}


function Foo() {
    this.data = 42,
    document.body.onclick = this.method;
}

Foo.prototype.method = method;

समाधान ऊपर उल्लिखित के समान है: यदि उपलब्ध हो, तो एक विशिष्ट मूल्य के .bindलिए स्पष्ट रूप से बांधने के thisलिए उपयोग करें

document.body.onclick = this.method.bind(this);

या फ़ंक्शन को कॉलबैक / ईवेंट हैंडलर के रूप में अनाम फ़ंक्शन का उपयोग करके या किसी thisअन्य चर के लिए ऑब्जेक्ट को "विधि" के रूप में स्पष्ट रूप से कॉल करें :

var self = this;
document.body.onclick = function() {
    self.method();
};

या एक तीर फ़ंक्शन का उपयोग करें:

document.body.onclick = () => this.method();

39
फेलिक्स, मैंने इस उत्तर को पहले पढ़ा है लेकिन कभी उत्तर नहीं दिया। मैं चिंतित हूं कि लोग इसका उपयोग करते हैं selfऔर thatसंदर्भित करते हैं this। मैं इस तरह महसूस करता हूं क्योंकि thisविभिन्न संदर्भों में उपयोग किए जाने वाले एक अतिभारित चर है; जबकि selfआमतौर पर स्थानीय उदाहरण से मेल खाती है और thatआमतौर पर किसी अन्य वस्तु को संदर्भित करता है। मुझे पता है कि आपने यह नियम निर्धारित नहीं किया है, जैसा कि मैंने देखा है कि यह कई अन्य स्थानों में दिखाई देता है, लेकिन यह भी है कि मैंने इसका उपयोग क्यों करना शुरू कर दिया है _this, लेकिन यह सुनिश्चित नहीं है कि गैर-समान व्यवहार को छोड़कर अन्य लोग कैसा महसूस करते हैं इसका परिणाम हुआ है।
Vol7ron

3
@FelixKling यह मान लेना सुरक्षित होगा कि प्रोटोटाइप कार्यों के अंदर इसका उपयोग करने पर हमेशा अपेक्षित व्यवहार होगा चाहे वे कैसे भी हों (आमतौर पर इसे कैसे कहा जाता है? प्रोटोटाइप फ़ंक्शन के अंदर कॉलबैक का उपयोग करते समय, क्या बाइंड (), स्व या के लिए एक विकल्प है?
andig

5
@FelixKling यह समय पर Function.prototype.call ()और भरोसा करने के लिए उपयोगी हो सकता है Function.prototype.apply ()। विशेष रूप से apply ()मैंने बहुत अधिक लाभ प्राप्त किया है। मैं bind ()शायद केवल आदत से बाहर का उपयोग करने के लिए इच्छुक हूं, हालांकि मुझे पता है (लेकिन कुछ निश्चित नहीं) कि अन्य विकल्पों पर बाँध का उपयोग करने के लिए मामूली ओवरहेड फायदे हो सकते हैं।
नोलो

5
महान जवाब लेकिन एक अतिरिक्त वैकल्पिक समाधान जोड़ने पर विचार करें जो कि कक्षाओं, नए या इस सब का उपयोग नहीं करना है।
अलुआन हदद

4
पुनः तीर कार्य "इसके बजाय, इसे सामान्य चर की तरह दायरे में देखा जाता है।" पूरी तरह से इस पर क्लिक करें मेरे लिए, धन्यवाद! () => this.clicked();)
अल्फ़ान्यूमेरिक

211

बच्चे के संदर्भ में माता-पिता के संदर्भ तक पहुंचने के कई तरीके यहां दिए गए हैं -

  1. आप bind()फ़ंक्शन का उपयोग कर सकते हैं ।
  2. संदर्भ के संदर्भ में स्टोर करें / इसे दूसरे चर के अंदर (उदाहरण के नीचे देखें)।
  3. ES6 एरो फ़ंक्शंस का उपयोग करें ।
  4. अल्टर कोड / फंक्शन डिज़ाइन / आर्किटेक्चर - इसके लिए आपके पास जावास्क्रिप्ट में डिज़ाइन पैटर्न पर कमांड होनी चाहिए ।

1. bind()फ़ंक्शन का उपयोग करें

function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data', ( function () {
        alert(this.data);
    }).bind(this) );
}
// Mock transport object
var transport = {
    on: function(event, callback) {
        setTimeout(callback, 1000);
    }
};
// called as
var obj = new MyConstructor('foo', transport);

यदि आप उपयोग कर रहे हैं underscore.js- http://underscorejs.org/#bind

transport.on('data', _.bind(function () {
    alert(this.data);
}, this));

संदर्भ के लिए 2 स्टोर संदर्भ / यह एक और चर के अंदर

function MyConstructor(data, transport) {
  var self = this;
  this.data = data;
  transport.on('data', function() {
    alert(self.data);
  });
}

3 तीर समारोह

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

1
बाइंड () विकल्प आश्चर्यजनक है कि इस ऑब्जेक्ट के पॉइंटर को पास करने पर यह अन्य ऑब्जेक्ट पर हो सकता है: (धन्यवाद!
स्टड बोडिक

बाँध () आकर्षण की तरह काम करता है। बहुत बहुत शुक्रिया +1 मुझ से :)
अंजना सिल्वा

56

यह सब "मैजिक" सिंटेक्स ऑफ़ द मेक ऑफ़ मेथड:

object.property();

जब आप ऑब्जेक्ट से संपत्ति प्राप्त करते हैं और इसे एक बार में कहते हैं, तो ऑब्जेक्ट विधि के लिए संदर्भ होगा। यदि आप एक ही विधि कहते हैं, लेकिन अलग-अलग चरणों में, संदर्भ इसके बजाय वैश्विक क्षेत्र (विंडो) है:

var f = object.property;
f();

जब आपको किसी विधि का संदर्भ मिलता है, तो यह ऑब्जेक्ट से जुड़ी नहीं होती है, यह केवल एक सादे फ़ंक्शन का संदर्भ है। जब आप कॉलबैक के रूप में उपयोग करने के लिए संदर्भ प्राप्त करते हैं तो ऐसा ही होता है:

this.saveNextLevelData(this.setAll);

यह वह जगह है जहाँ आप फ़ंक्शन के संदर्भ को बाँधेंगे:

this.saveNextLevelData(this.setAll.bind(this));

यदि आप jQuery का उपयोग कर रहे हैं, तो आपको $.proxyइसके बजाय विधि का उपयोग करना चाहिए , जैसा bindकि सभी ब्राउज़रों में समर्थित नहीं है:

this.saveNextLevelData($.proxy(this.setAll, this));

33

"संदर्भ" के साथ परेशानी

शब्द "संदर्भ" का उपयोग कभी-कभी इसके द्वारा संदर्भित ऑब्जेक्ट के संदर्भ में किया जाता है । इसका उपयोग अनुचित क्योंकि यह या तो शब्दार्थ या तकनीकी रूप से फिट नहीं करता है के साथ है ECMAScript के इस

"प्रसंग" का अर्थ किसी ऐसी चीज के आस-पास की परिस्थितियों से है जो अर्थ जोड़ता है, या कुछ पूर्ववर्ती और निम्नलिखित जानकारी देता है जो अतिरिक्त अर्थ देता है। शब्द "संदर्भ" का उपयोग ईसीएमएस्क्रिप्ट में निष्पादन संदर्भ को संदर्भित करने के लिए किया जाता है , जो सभी मापदंडों, दायरे और यह है कुछ क्रियान्वित कोड के दायरे के भीतर।

इसे ECMA-262 खंड 10.4.2 में दिखाया गया है :

इसBinding को कॉलिंग एक्ज़िस्टेंस कॉन्टेन्स के ThisBinding के समान मान पर सेट करें

जो स्पष्ट रूप से इंगित करता है कि यह एक निष्पादन संदर्भ का हिस्सा है।

एक निष्पादन संदर्भ आसपास की जानकारी प्रदान करता है जो उस कोड को अर्थ जोड़ता है जिसे निष्पादित किया जा रहा है। इसमें सिर्फ और सिर्फ से अधिक जानकारी शामिल है बाइंडिंग की

तो का मूल्य इस "संदर्भ" नहीं है, यह एक निष्पादन संदर्भ का सिर्फ एक हिस्सा है। यह अनिवार्य रूप से एक स्थानीय चर है जिसे कॉल द्वारा किसी भी वस्तु और सख्त मोड में किसी भी मूल्य पर सेट किया जा सकता है।


इस उत्तर से सहमत नहीं हो सकते। शब्द "निष्पादन संदर्भ" का अस्तित्व "संदर्भ" के अन्य उपयोगों को रेखांकित नहीं करता है, जितना कि "निष्पादन" के अन्य उपयोगों की तुलना में यह अधिक है। शायद वर्णन करने के लिए एक बेहतर शब्द है, thisलेकिन यहां कोई भी पेश नहीं किया गया है, और "संदर्भ" पर दरवाजा बंद करने के लिए यकीनन बहुत देर हो चुकी है।
Roamer-1888

@ Roamer-1888 — संपादन के लिए धन्यवाद। आप सही हैं, लेकिन मेरा तर्क किसी अन्य उद्देश्य के लिए "संदर्भ" को छोड़कर "निष्पादन संदर्भ" के अस्तित्व पर निर्भर नहीं करता है। बल्कि, यह "संदर्भ" तकनीकी और शब्दार्थ दोनों के दृष्टिकोण से अनुचित होने पर आधारित है। मैं यह भी सोचता हूं कि "यह" के बजाय "संदर्भ" का उपयोग मर रहा है। मुझे इस या इस बाइंडिंग के लिए एक वैकल्पिक शब्द खोजने का कोई कारण नहीं दिखता है , यह सिर्फ और केवल इस बिंदु पर आपको समझाता है कि "संदर्भ" वास्तव में यह है , और यह कि वैसे भी "संदर्भ" में नहीं है। :-)
रोबग

मुझे नहीं लगता कि आप यह कह सकते हैं कि यह किसी भी तरह से "संदर्भ" नहीं है, जब आपने पहले ही स्वीकार कर लिया है कि यह निष्पादन के संदर्भ का एक हिस्सा है, जहां "निष्पादन" केवल विशेषण है।
रोमर -1888

@ Roamer-1888 — मैं इस बिंदु पर इस बातचीत को जारी नहीं रखने जा रहा हूं। हां, यह एक निष्पादन संदर्भ का हिस्सा है। कह रही है यह संदर्भ कह एक टीम का एक खिलाड़ी टीम है की तरह है।
रॉबग

रॉब, दया आप जारी नहीं रखना चाहते हैं। यह एक दिलचस्प बहस है। मुझे अपना समय देने के लिए धन्यवाद।
रोमेर -1888

31

आपको "यह" कीवर्ड के बारे में पता होना चाहिए।

मेरे विचार के अनुसार आप "इसे" तीन तरीकों से लागू कर सकते हैं (सेल्फ / एरो फंक्शन / बिंद मेथड)

एक फ़ंक्शन का यह कीवर्ड अन्य भाषाओं की तुलना में जावास्क्रिप्ट में थोड़ा अलग व्यवहार करता है।

यह सख्त मोड और गैर-सख्त मोड के बीच कुछ अंतर भी है।

ज्यादातर मामलों में, इसका मान किसी फ़ंक्शन को कैसे कहा जाता है, इसके द्वारा निर्धारित किया जाता है।

इसे निष्पादन के दौरान असाइनमेंट द्वारा सेट नहीं किया जा सकता है, और यह फ़ंक्शन कहे जाने पर हर बार अलग हो सकता है।

ES5 ने फ़ंक्शन के मान को सेट करने के लिए बाइंड () विधि की शुरुआत की, भले ही इसे कैसे कहा जाए,

और ES2015 ने एरो फ़ंक्शंस पेश किए जो कि इस बंधन को प्रदान नहीं करते हैं (यह एन्कोडिंग लेक्सिकल संदर्भ के इस मान को बरकरार रखता है)।

विधि 1: स्व - स्वयं का उपयोग मूल के संदर्भ को बनाए रखने के लिए किया जा रहा है, भले ही संदर्भ बदल रहा हो। यह अक्सर इवेंट हैंडलर (विशेषकर क्लोजर में) में उपयोग की जाने वाली तकनीक है।

संदर्भ : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

function MyConstructor(data, transport) {
    this.data = data;
    var self = this;
    transport.on('data', function () {
        alert(self.data);
    });
}

Method2 : एरो फंक्शन - एक एरो फंक्शन एक्सप्रेशन एक नियमित रूप से फंक्शन एक्सप्रेशन के लिए एक सिंटैक्टली कॉम्पैक्ट विकल्प है

हालांकि इसके अपने स्वयं के बाइंडिंग के बिना, तर्क, सुपर, या new.target कीवर्ड।

एरो फंक्शन एक्सप्रेशंस विधियों के रूप में बीमार हैं, और उन्हें कंस्ट्रक्टर के रूप में उपयोग नहीं किया जा सकता है।

संदर्भ : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',()=> {
        alert(this.data);
    });
}

विधि 3 : बाइंड- बाइंड () विधि एक नया फ़ंक्शन बनाती है,

जब कहा जाता है, तो इसका यह कीवर्ड प्रदान किए गए मान पर सेट है,

नए फ़ंक्शन को कॉल करने पर दिए गए तर्कों से पहले दिए गए किसी भी अनुक्रम के साथ।

संदर्भ: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind

  function MyConstructor(data, transport) {
    this.data = data;
    transport.on('data',(function() {
        alert(this.data);
    }).bind(this);

25

सबसे पहले, आपको के संदर्भ में कीवर्ड की स्पष्ट समझ scopeऔर व्यवहार की आवश्यकता thisहै scope

this& scope:


there are two types of scope in javascript. They are :

   1) Global Scope

   2) Function Scope

संक्षेप में, वैश्विक गुंजाइश विंडो ऑब्जेक्ट को संदर्भित करती है। वैश्विक दायरे में घोषित वेरिएबल्स कहीं से भी सुलभ हैं। दूसरे हाथ फ़ंक्शन का दायरा एक फ़ंक्शन के अंदर रहता है। एक फ़ंक्शन के अंदर घोषित किया जा सकता है। thisवैश्विक दायरे में कीवर्ड विंडो ऑब्जेक्ट को संदर्भित करता है। thisअंदर का कार्य भी विंडो ऑब्जेक्ट thisको संदर्भित करता है। जब तक हम thisअपने स्वयं के चुनने के संदर्भ को इंगित करने के लिए हेरफेर करने का एक तरीका नहीं ढूंढते हैं, तब तक हमेशा खिड़की को संदर्भित करेगा ।

--------------------------------------------------------------------------------
-                                                                              -
-   Global Scope                                                               -
-   ( globally "this" refers to window object)                                 -     
-                                                                              -
-         function outer_function(callback){                                   -
-                                                                              -
-               // outer function scope                                        -
-               // inside outer function"this" keyword refers to window object -                                                                              -
-              callback() // "this" inside callback also refers window object  -

-         }                                                                    -
-                                                                              -
-         function callback_function(){                                        -
-                                                                              -
-                //  function to be passed as callback                         -
-                                                                              -
-                // here "THIS" refers to window object also                   -
-                                                                              -
-         }                                                                    -
-                                                                              -
-         outer_function(callback_function)                                    -
-         // invoke with callback                                              -
--------------------------------------------------------------------------------

हेरफेर करने के विभिन्न तरीके thisकॉलबैक फ़ंक्शन के अंदर :

यहाँ मेरा एक कंस्ट्रक्टर फंक्शन है जिसे पर्सन कहा जाता है। यह एक संपत्ति कहा जाता है nameऔर चार विधि कहा जाता है sayNameVersion1, sayNameVersion2, sayNameVersion3, sayNameVersion4। इन चारों में एक विशिष्ट कार्य है। एक कॉलबैक को स्वीकार करें और इसे लागू करें। कॉलबैक में एक विशिष्ट कार्य होता है जो कि व्यक्ति निर्माण फ़ंक्शन के एक उदाहरण की नाम संपत्ति को लॉग इन करना है।

function Person(name){

    this.name = name

    this.sayNameVersion1 = function(callback){
        callback.bind(this)()
    }
    this.sayNameVersion2 = function(callback){
        callback()
    }

    this.sayNameVersion3 = function(callback){
        callback.call(this)
    }

    this.sayNameVersion4 = function(callback){
        callback.apply(this)
    }

}

function niceCallback(){

    // function to be used as callback

    var parentObject = this

    console.log(parentObject)

}

आइए अब व्यक्ति निर्माणकर्ता से एक उदाहरण बनाएं और sayNameVersionX(एक्स को संदर्भित करता है 1,2,3,4) के विभिन्न संस्करणों niceCallbackको देखें कि हम उदाहरण thisके personलिए कॉलबैक में कितने तरीकों से हेरफेर कर सकते हैं ।

var p1 = new Person('zami') // create an instance of Person constructor

बाँध:

thisप्रदान किए गए मान के साथ सेट किए गए कीवर्ड के साथ एक नया फ़ंक्शन बनाने के लिए क्या करना है ।

sayNameVersion1और कॉलबैक फ़ंक्शन के sayNameVersion2हेरफेर thisके लिए बाइंड का उपयोग करें ।

this.sayNameVersion1 = function(callback){
    callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
    callback()
}

पहले एक thisकॉलबैक के साथ विधि के अंदर ही बांधता है। और दूसरे एक कॉलबैक के लिए बाध्य किया जाता है।

p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method

p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback

कॉल करें:

first argumentकी callविधि के रूप में प्रयोग किया जाता है thisसमारोह है कि के साथ शुरू हो जाती है अंदरcall इसे से जुड़े।

sayNameVersion3विंडो ऑब्जेक्ट के बजाय, उस व्यक्ति ऑब्जेक्ट को संदर्भित करने के callलिए हेरफेर करने के thisलिए उपयोग करता है जिसे हमने बनाया था।

this.sayNameVersion3 = function(callback){
    callback.call(this)
}

और इसे निम्नलिखित की तरह कहा जाता है:

p1.sayNameVersion3(niceCallback)

लागू :

इसी प्रकार call, पहले तर्क का applyतात्पर्य उस वस्तु से है, जिसे इंगित किया जाएगाthisकीवर्ड के ।

sayNameVersion4व्यक्ति वस्तु को संदर्भित करने के applyलिए हेरफेर thisकरने के लिए उपयोग करता है

this.sayNameVersion4 = function(callback){
    callback.apply(this)
}

और इसे निम्नलिखित की तरह कहा जाता है। तेजी से कॉलबैक पारित किया जाता है,

p1.sayNameVersion4(niceCallback)

1
उत्तर के संबंध में किसी भी रचनात्मक आलोचना की सराहना की जाएगी!
AL-zami

1
वैश्विक दायरे में यह कीवर्ड आवश्यक रूप से विंडो ऑब्जेक्ट को संदर्भित नहीं करता है । यह केवल एक ब्राउज़र में सच है।
रान्डेल फ्लैग

1
@RandallFlagg मैंने यह उत्तर एक ब्राउज़र के दृष्टिकोण से लिखा था। यदि आवश्यक हो तो इस उत्तर को नि: शुल्क लिखें। :)
AL-zami

19

हम इसे बांध नहीं सकते हैं setTimeout(), क्योंकि यह हमेशा वैश्विक ऑब्जेक्ट (विंडो) के साथ निष्पादित होता है , यदि आप thisकॉलबैक फ़ंक्शन में संदर्भ का उपयोग करना चाहते हैं तो कॉलबैक फ़ंक्शन का उपयोग करके bind()हम इसे प्राप्त कर सकते हैं:

setTimeout(function(){
    this.methodName();
}.bind(this), 2000);

9
यह किसी भी मौजूदा जवाब से अलग कैसे है?
फेलिक्स क्लिंग

13

यह सवाल घूमता है कि thisजावास्क्रिप्ट में कीवर्ड कैसे व्यवहार करता है। thisनीचे के रूप में अलग तरह से व्यवहार करता है,

  1. का मूल्य this आमतौर पर एक कार्य निष्पादन संदर्भ द्वारा निर्धारित किया जाता है।
  2. वैश्विक दायरे में, thisवैश्विक वस्तु ( windowऑब्जेक्ट) को संदर्भित करता है ।
  3. यदि किसी भी फ़ंक्शन के लिए सख्त मोड सक्षम है, तो मान this वसीयतundefined सख्त मोड में होगा, ऑब्जेक्ट के undefinedस्थान पर वैश्विक ऑब्जेक्ट संदर्भित होता है window
  4. वह वस्तु जो डॉट के सामने खड़ी है, वह वही है जो यह कीवर्ड बाध्य होगा।
  5. हम इसका मूल्य स्पष्ट रूप से निर्धारित कर सकते हैं call() , bind()औरapply()
  6. जब newकीवर्ड का उपयोग किया जाता है (एक कंस्ट्रक्टर), यह नई ऑब्जेक्ट के निर्माण के लिए बाध्य होता है।
  7. एरो फ़ंक्शंस बाँध नहीं है this  - इसके बजाय, thislexically बाध्य है (यानी मूल संदर्भ के आधार पर)

जैसा कि अधिकांश उत्तर बताते हैं, हम एरो फ़ंक्शन या bind()मेथड या सेल्फ वर्जन का उपयोग कर सकते हैं । मैं lambdas (एरो फ़ंक्शन) के बारे में एक बिंदु उद्धृत करूंगा Google जावास्क्रिप्ट स्टाइल गाइड

F.bind (यह), और विशेष रूप से goog.bind (f, यह) पर तीर फ़ंक्शन का उपयोग करना पसंद करें। कॉन्स्टल सेल्फ = यह लिखने से बचें। एरो फ़ंक्शंस कॉलबैक के लिए विशेष रूप से उपयोगी हैं, जो कभी-कभी अप्रत्याशित अतिरिक्त तर्क पास करते हैं।

Google स्पष्ट रूप से बाँध या के बजाय लैम्ब्डा का उपयोग करने की सलाह देता है const self = this

तो सबसे अच्छा उपाय यह होगा कि नीचे दिए गए लंबोदर का उपयोग करें,

function MyConstructor(data, transport) {
  this.data = data;
  transport.on('data', () => {
    alert(this.data);
  });
}

संदर्भ:

  1. https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
  2. तीर-कार्यों-बनाम-बाँध

यह प्रश्न विशेष रूप से कॉलबैक के रूप में फ़ंक्शन / विधियों का उपयोग करने के बारे में है। आपका जवाब stackoverflow.com/q/3127429/218196 के लिए एक बेहतर फिट हो सकता है ।
फेलिक्स क्लिंग

@FelixKling हाँ प्रश्न फ़ंक्शंस / विधियों का उपयोग करने के बारे में है कि कॉलबैक में मुख्य मुद्दा thisकीवर्ड की हैंडलिंग के कारण था, इसलिए मैंने अपने उत्तर को दो भागों में विभाजित किया, एक के बारे में thisऔर दूसरा कॉलबैक के रूप में फ़ंक्शन / विधियों का उपयोग करने के बारे में। जवाब को संपादित करने के लिए स्वतंत्र महसूस करें।
कोड_मोड

मुझे आपकी चौथी बात अस्पष्ट लगती है। उदाहरण पर विचार करें "कॉलबैक के रूप में इस वस्तु के साथ तरीकों का उपयोग करते समय समस्या" , जहां सही वस्तु डॉट के सामने खड़ी है, लेकिन फिर भी संदर्भ वह वस्तु नहीं है।
ब्लिफ्टिफ्ट 2

7

वर्तमान में एक और दृष्टिकोण संभव है अगर वर्गों को कोड में उपयोग किया जाता है।

वर्ग फ़ील्ड के समर्थन से इसे अगले तरीके से बनाना संभव है:

class someView {
    onSomeInputKeyUp = (event) => {
        console.log(this); // this refers to correct value
    // ....
    someInitMethod() {
        //...
        someInput.addEventListener('input', this.onSomeInputKeyUp)

हुड के तहत सुनिश्चित करने के लिए यह सभी पुराने अच्छे तीर फ़ंक्शन है जो संदर्भ को बांधते हैं लेकिन इस रूप में यह अधिक स्पष्ट है कि स्पष्ट बाध्यकारी है।

चूंकि यह स्टेज 3 प्रस्ताव है, इसलिए आपको इसे (08/2018) के लिए संसाधित करने के लिए बेबल और उपयुक्त बैबल प्लगइन की आवश्यकता होगी ।


2
यह ठीक उसी तरह है जैसे मुझे यह टाइपस्क्रिप्ट में काम करने के लिए मिला है: public methodName = (params) => { body }एक कक्षा के अंदर।
येयेरमैन

5

एक अन्य दृष्टिकोण, जो कि इवेंट श्रोता के भीतर बांधने के लिए DOM2 के बाद से मानक तरीकाthis है, जो आपको हमेशा श्रोता (अन्य लाभों के बीच) को हटाने देता है , इंटरफ़ेस handleEvent(evt)से विधि है EventListener:

var obj = {
  handleEvent(e) {
    // always true
    console.log(this === obj);
  }
};

document.body.addEventListener('click', obj);

उपयोग करने के बारे में विस्तृत जानकारी handleEventयहाँ पाई जा सकती है: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38


0

this जेएस में:

thisजेएस का मान 100% इस बात से निर्धारित होता है कि किसी फ़ंक्शन को कैसे कहा जाता है, न कि इसे कैसे परिभाषित किया जाता है। हम अपेक्षाकृत आसान का मूल्य प्राप्त कर सकते हैं thisद्वारा 'डॉट शासन के छोड़ दिया' :

  1. जब फ़ंक्शन फ़ंक्शन कीवर्ड का उपयोग करके फ़ंक्शन का निर्माण किया जाता है, तो फ़ंक्शन thisके डॉट के बाईं ओर स्थित ऑब्जेक्ट जिसे कहा जाता है
  2. यदि डॉट का कोई ऑब्जेक्ट नहीं बचा है, तो thisकिसी फ़ंक्शन के अंदर का मान अक्सर वैश्विक ऑब्जेक्ट ( globalनोड में, windowब्राउज़र में) होता है। मैं thisयहां कीवर्ड का उपयोग करने की अनुशंसा नहीं करूंगा क्योंकि यह किसी चीज़ का उपयोग करने से कम स्पष्ट नहीं हैwindow !
  3. फ़ंक्शन का उपयोग करके बनाए गए कुछ फ़ंक्शन और फ़ंक्शंस जैसे फ़ंक्शन मौजूद हैं Function.prototype.bind()जो मान को ठीक कर सकते हैं this। ये नियम के अपवाद हैं लेकिन मूल्य को ठीक करने के लिए वास्तव में सहायक हैं this

नोडजेएस में उदाहरण

module.exports.data = 'module data';
// This outside a function in node refers to module.exports object
console.log(this);

const obj1 = {
    data: "obj1 data",
    met1: function () {
        console.log(this.data);
    },
    met2: () => {
        console.log(this.data);
    },
};

const obj2 = {
    data: "obj2 data",
    test1: function () {
        console.log(this.data);
    },
    test2: function () {
        console.log(this.data);
    }.bind(obj1),
    test3: obj1.met1,
    test4: obj1.met2,
};

obj2.test1();
obj2.test2();
obj2.test3();
obj2.test4();
obj1.met1.call(obj2);

आउटपुट:

यहां छवि विवरण दर्ज करें

चलिए मैं आपको 1 आउटपुट 1 के माध्यम से चलता हूं (दूसरे से शुरू होने वाले पहले लॉग को अनदेखा करता हूं):

  1. thisहै obj2डॉट नियम के बाईं की वजह से, हम देख सकते हैं कि test1कहा जाता है obj2.test1();obj2और इस प्रकार thisमूल्य का बचा है ।
  2. भले ही obj2बिंदी बची हो, लेकिन विधि से test2बंधी है । तो मान है ।obj1bind()thisobj1
  3. obj2फ़ंक्शन से डॉट को छोड़ दिया जाता है जिसे कहा जाता है obj2.test3():। इसलिए obj2का मूल्य होगा this
  4. इस मामले में: obj2.test4() obj2डॉट के लिए छोड़ दिया गया है। हालांकि तीर फ़ंक्शन का अपना thisबंधन नहीं है । इसलिए यह thisबाहरी दायरे के मूल्य के लिए बाध्य होगा जो कि हैmodule.exports वस्तु है जिसे शुरुआत में लॉग किया गया था।
  5. हम फ़ंक्शन thisका उपयोग करके मूल्य भी निर्दिष्ट कर सकते हैं call। यहां हम thisएक तर्क के रूप में वांछित मूल्य में पास कर सकते हैं , जो obj2इस मामले में है।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.