javascript - w3schools - कॉलबैक के अंदर सही 'यह' कैसे पहुंचे?




w3schools python (4)

मेरे पास एक कन्स्ट्रक्टर फ़ंक्शन है जो एक ईवेंट हैंडलर पंजीकृत करता है:

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

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

मैं सही वस्तु का उपयोग कैसे कर सकता हूं?


आपको इसके बारे में क्या पता होना चाहिए

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`

इसके बारे में और जानने के लिए, एमडीएन दस्तावेज देखें

इसे सही कैसे देखें

इसका इस्तेमाल न करें

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

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

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

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

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

प्रत्येक फ़ंक्शन में विधि है। .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);
}

इस मामले में, हम कॉलबैक को MyConstructor के मूल्य पर बाध्य कर रहे हैं।

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

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

ईसीएमएस्क्रिप्ट 6 तीर कार्यों को प्रस्तुत करता है , जिसे लैम्ब्डा कार्यों के रूप में माना जा सकता है। उनके पास this बाध्यकारी नहीं है। इसके बजाए, this एक सामान्य चर की तरह दायरे में देखा जाता है। इसका मतलब है कि आपको कॉल करने की ज़रूरत नहीं है। उनके पास यह एकमात्र विशेष व्यवहार नहीं है, कृपया अधिक जानकारी के लिए एमडीएन दस्तावेज देखें।

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

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

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

array.map(callback[, thisArg])

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

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

नोट: इसके लिए आप एक मान पास कर सकते हैं या नहीं, आमतौर पर उस कार्य / विधि के दस्तावेज़ीकरण में उल्लिखित है। उदाहरण के लिए, jQuery की $.ajax विधि [डॉक्स] context नामक एक विकल्प का वर्णन करती 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 का उपयोग करें

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

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

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

या एक तीर समारोह का उपयोग करें:

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

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

  1. आप bind () फ़ंक्शन का उपयोग कर सकते हैं।
  2. किसी अन्य चर के अंदर संदर्भ / संदर्भ के लिए संदर्भ संदर्भ (नीचे उदाहरण देखें)।
  3. ES6 Arrow फ़ंक्शंस का उपयोग करें।
  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);
  });
}

यह एक विधि को बुलाए जाने के "जादू" वाक्यविन्यास में है:

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

सबसे पहले, आपको this कीवर्ड के 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 (X को 1,2,3,4 संदर्भित करें) विधि के विभिन्न संस्करणों को आह्वान करें, यह देखने के लिए कि हम कॉलबैक के अंदर this उदाहरण को संदर्भित करने के लिए कितने तरीकों का उपयोग कर सकते हैं।

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

बांधना

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

sayNameVersion1 और sayNameVersion2 कॉलबैक फ़ंक्शन में हेरफेर करने के लिए बाध्य करें।

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

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

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

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

कॉल करें:

call विधि का first argument उस फ़ंक्शन के अंदर उपयोग किया जाता है call उससे जुड़े call साथ बुलाया जाता है।

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

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

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

p1.sayNameVersion3(niceCallback)

लागू करें :

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

sayNameVersion4 का प्रयोग व्यक्तिगत ऑब्जेक्ट को संदर्भित करने के लिए sayNameVersion4 उपयोग apply लिए apply है

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

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

p1.sayNameVersion4(niceCallback)





this