Bir geri arama içinde doğru `buna 'nasıl erişilir?


1425

Bir olay işleyicisi kaydeder bir yapıcı işlevi var:

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

Ancak, datageri arama içinde oluşturulan nesnenin özelliğine erişemiyorum . thisOluşturulan nesneye değil, başka bir nesneye atıfta bulunuyor gibi görünüyor .

Ayrıca anonim bir işlev yerine bir nesne yöntemi kullanmaya çalıştım:

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

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

ama aynı sorunları sergiliyor.

Doğru nesneye nasıl erişebilirim?


95
Zaman zaman belli bir sorudan bıktım, kanonik bir cevap yazmaya karar verdim. Bu sorular bir milyon kez cevaplanmış olmasına rağmen, alakasız bilgilerle “kirlenmemiş” iyi bir soru + cevap çifti bulmak her zaman mümkün değildir. Bu o anlardan biri ve bu sorulardan biri (ve sıkıldım). Bu tür bir soru için gerçekten iyi bir kanonik soru / cevap olduğunu düşünüyorsanız, bana bildirin, bunu silerim. İyileştirme önerileri bekliyoruz!
Felix Kling



3
Bu konuda yararlı TypeScript sayfası , çoğunlukla JS için de geçerlidir.
Ondra Žižka

Yanıtlar:


1790

Bilmeniz gerekenler this

this(diğer bir deyişle "bağlam") her bir işlevin içindeki özel bir anahtar kelimedir ve değeri , işlevin nasıl / ne zaman / nerede tanımlandığına değil, yalnızca işlevin nasıl çağrıldığına bağlıdır . Diğer değişkenler gibi sözcüksel kapsamlardan etkilenmez (ok işlevleri hariç, aşağıya bakın). İşte bazı örnekler:

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`

Hakkında daha fazla bilgi edinmek thisiçin MDN belgelerine bakın .


Doğru nasıl başvurulur this

Kullanma this

Aslında thisözel olarak erişmek istemezsiniz , ama sözünü ettiği nesne . Bu nedenle kolay bir çözüm, o nesneyi de ifade eden yeni bir değişken oluşturmaktır. Değişkenin herhangi bir adı olabilir, ancak yaygın olanları selfve that.

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

Yana selfnormal bir değişkendir, bu sözcük kapsam kuralları uyar ve geri arama içeride erişilebilir. Bu ayrıca thisgeri arama değerine erişebilme avantajına sahiptir .

Açıkça thisgeri arama seti - Bölüm 1

thisDeğeri otomatik olarak ayarlandığından, değeri üzerinde hiçbir kontrolünüz yok gibi görünebilir , ancak aslında durum böyle değildir.

Her işlev, bir değere bağlı yeni bir işlev döndüren .bind [docs] yöntemine sahiptir this. İşlev .bind, yalnızca thissizin tarafınızdan ayarlanmış olanla aynı davranışa sahiptir . Bu işlev nasıl veya ne zaman çağrılırsa çağrılsın, thisher zaman iletilen değere işaret eder.

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

Bu durumda, geri aramaları 's thisdeğerine MyConstructorbağlarız this.

Not: jQuery için bağlam bağlarken, bunun yerine jQuery.proxy [docs] kullanın. Bunu yapmanın nedeni, bir olay geri aramasını bağlarken işleve başvuruyu depolamanıza gerek kalmamasıdır. jQuery bunu dahili olarak ele alır.

ECMAScript 6: Ok işlevlerini kullanma

ECMAScript 6 , lambda işlevleri olarak düşünülebilecek ok işlevlerini sunar. Kendi thisbağları yok. Bunun yerine, thisnormal bir değişken gibi kapsam olarak bakılır. Bu, aramak zorunda olmadığınız anlamına gelir .bind. Sahip oldukları tek özel davranış bu değildir, daha fazla bilgi için lütfen MDN belgelerine bakın.

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

thisGeri arama seti - bölüm 2

Geri aramaları kabul eden bazı işlevler / yöntemler de geri aramaların thisbaşvurması gereken bir değeri kabul eder. Bu temel olarak kendiniz bağlamakla aynıdır, ancak işlev / yöntem bunu sizin için yapar. Array#map [dokümanlar] böyle bir yöntemdir. İmzası:

array.map(callback[, thisArg])

İlk argüman geri arama, ikinci argüman ise değerin thisbaşvurması gerektiğidir. İşte örnek bir örnek:

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

Not: Bir değer thisiletip iletemeyeceğiniz genellikle bu işlevin / yöntemin belgelerinde belirtilir. Örneğin, jQuery'nin $.ajaxyöntemi [docs] , şu şekilde adlandırılan bir seçeneği açıklar context:

Bu nesne, Ajax ile ilgili tüm geri çağrıların bağlamı haline getirilecektir.


Genel sorun: Nesne yöntemlerini geri çağrılar / olay işleyicileri olarak kullanma

Bu sorunun ortak bir başka belirtisi, bir nesne yönteminin geri çağrı / olay işleyicisi olarak kullanılmasıdır. İşlevler, JavaScript'teki birinci sınıf vatandaşlardır ve "yöntem" terimi, bir nesne özelliğinin değeri olan bir işlev için yalnızca konuşma dilidir. Ancak bu işlevin "içeren" nesnesine belirli bir bağlantısı yoktur.

Aşağıdaki örneği düşünün:

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

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

İşlev this.method, click olay işleyicisi olarak atanır, ancak document.bodytıklanırsa, undefinedolay işleyicisi içinde örneğini değil, günlüğe thisatıfta bulunduğu için günlüğe kaydedilen değer olur . Başlangıçta daha önce de belirtildiği gibi, ne ifade edileceği, işlevin nasıl tanımlandığına değil, nasıl adlandırıldığına bağlıdır . Kod aşağıdaki gibiyse, işlevin nesneye örtülü bir başvurusu olmadığı daha açık olabilir:document.bodyFoo
this

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


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

Foo.prototype.method = method;

Çözüm , yukarıda belirtilenle aynıdır: Varsa, belirli bir değere .bindaçıkça bağlanmak thisiçin kullanın

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

veya geri arama / olay işleyici olarak anonim bir işlev kullanarak işlevi nesnenin "yöntemi" olarak açıkça çağırır ve object ( this) öğesini başka bir değişkene atar :

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

veya bir ok işlevi kullanın:

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

39
Felix, bu cevabı daha önce okudum ama cevap vermedim. İnsanların kullandıkları selfve thatatıfta bulunduğu endişelerim var this. Bu şekilde hissediyorum this, çünkü farklı bağlamlarda kullanılan aşırı yüklenmiş bir değişken; oysa selfgenellikle yerel örneğe ve thatgenellikle başka bir nesneye karşılık gelir. Başka bir yerde göründüğünü gördüğüm için bu kuralı ayarlamadığınızı biliyorum, ama aynı zamanda kullanmaya başladım _this, ancak tek tip olmayan uygulama dışında başkalarının nasıl hissettiğinden emin değilim sonuçlandı.
vol7ron

3
@FelixKling, bu iç prototip işlevlerini kullanmanın (tipik olarak) nasıl adlandırıldıklarına bakılmaksızın her zaman beklenen davranışa sahip olacağını varsaymak güvenli olur mu? Prototip işlevleri içinde geri çağrılar kullanırken, bind (), self veya that'a bir alternatif var mı?
andig

5
Zaman güvenmek de It @FelixKling faydalı olabilir Function.prototype.call ()ve Function.prototype.apply (). Özellikle apply ()de çok fazla kilometre aldım. bind ()Belki de alışkanlık dışında kullanmaya daha az eğilimliyim, ancak diğer seçenekler üzerinde bağlama kullanmanın hafif havai avantajları olabileceğinin farkındayım (ancak emin değilim).
Nolo

5
Harika bir yanıt ama sadece sınıfları, yeni ya da bunu kullanmamak için ek bir isteğe bağlı çözüm eklemeyi düşünün.
Aluan Haddad

4
yeniden ok fonksiyonları "Bunun yerine, bu normal bir değişken gibi kapsam içinde aranır." Tamamen benim için bu tıklamayı yaptı, teşekkür ederim! () => this.clicked();)
alfanümerik0101

211

Alt bağlam içindeki üst bağlama erişmenin birkaç yolu şunlardır -

  1. bind()Fonksiyonu kullanabilirsiniz .
  2. Bağlama / buna referansı başka bir değişken içinde saklayın (aşağıdaki örneğe bakın).
  3. ES6 Ok işlevlerini kullanın .
  4. Kodu / işlev tasarımını / mimarisini değiştirin - bunun için javascript tasarım desenleri üzerinde komutunuz olmalıdır .

1. kullanım bind()fonksiyonu

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

Kullanıyorsanız underscore.js- http://underscorejs.org/#bind

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

2 Bağlama / buna referansı başka bir değişken içinde saklayın

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

3 Ok fonksiyonu

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

1
Bind () seçeneği, bu nesnenin işaretçisini diğer nesnede bu olmak için geçmesi şaşırtıcı: (Teşekkürler!
Stav Bodik

Bind () bir cazibe gibi çalışır. Benden +1 çok teşekkür ederim :)
Anjana Silva

56

Her şey bir yöntemi çağırmanın "sihirli" sözdiziminde:

object.property();

Özelliği nesneden alıp tek seferde çağırdığınızda, nesne yöntemin bağlamı olur. Aynı yöntemi, ancak ayrı adımlarla çağırırsanız, bunun yerine bağlam genel kapsamdır (pencere):

var f = object.property;
f();

Bir yöntemin başvurusunu aldığınızda, artık nesneye bağlı değildir, yalnızca düz bir işleve başvurudur. Aynı durum, geri arama olarak kullanılacak referansı aldığınızda da olur:

this.saveNextLevelData(this.setAll);

Burada bağlamı işleve bağlarsınız:

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

JQuery kullanıyorsanız, tüm tarayıcılarda desteklenmediği için $.proxybunun yerine yöntemi kullanmalısınız bind:

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

33

"Bağlam" ile ilgili sorun

"Bağlam" terimi bazen tarafından başvurulan nesne başvurmak için kullanılır bu . Onunla semantik veya teknik ya uymuyor çünkü Onun kullanılması uygun değildir ECMAScript en bu .

"Bağlam" , anlam katan bir şeyi çevreleyen koşullar veya fazladan anlam veren önceki ve sonraki bazı bilgiler anlamına gelir. "Bağlam" terimi, ECMAScript'te , bazı yürütme kodlarının kapsamındaki tüm parametreler, kapsam ve bu olan yürütme bağlamına atıfta bulunmak için kullanılır .

Bu, ECMA-262 bölüm 10.4.2'de gösterilmiştir :

ThisBinding, çağıran yürütme bağlamının ThisBinding ile aynı değere ayarlayın

açık olan belirtir , bu bir yürütme içeriği bir parçasıdır.

Bir yürütme bağlamı, yürütülmekte olan koda anlam katan çevreleyen bilgileri sağlar. Sadece thisBinding'dan çok daha fazla bilgi içerir .

Değeri Yani bu "bağlam" değil, bir yürütme içeriği sadece bir parçası. Temelde herhangi bir nesneye çağrı ve katı modda herhangi bir değere ayarlanabilen yerel bir değişkendir.


Bu yanıta katılamıyorum. "Yürütme bağlamı" teriminin varlığı, "yürütme" nin diğer kullanımlarından daha fazla "bağlam" ın diğer kullanımlarını yasaklamaz. Belki tarif etmek için daha iyi bir terim vardır, thisancak burada hiçbiri önerilmemektedir ve "bağlam" ın kapısını kapatmak için muhtemelen çok geç.
Roamer-1888

@ Roamer-1888 - düzenleme için teşekkür ederim. Haklısın, ama benim argümanım başka bir amaçla "bağlam" ın önüne geçen "yürütme bağlamı" nın varlığına dayanmıyor. Aksine, "bağlam" ın hem teknik hem de anlamsal açıdan uygun olmaması üzerine kuruludur. Ben de "bu" yerine "bağlam" kullanımının yok olduğunu düşünüyorum. Bu veya thisBinding için alternatif bir terim bulmak için herhangi bir neden görmüyorum , sadece şaşırtıyor ve bir noktada "bağlam" ın aslında bu olduğunu ve yine de "bağlamda" olmadığını açıklamanız gerektiği anlamına geliyor . :-)
RobG

Bunu söyleyeceğini sanmıyorum bu zaten o "yürütme" sadece sıfat olan bir yürütme içeriği, biri parçası olduğunu admittted ne zaman, hiçbir şekilde "bağlam" değildir.
Roamer-1888

@ Roamer-1888 — Bu konuşmaya bu noktadan sonra devam etmeyeceğim. Evet, bu bir kısım bir yürütme bağlamının. Öyle diyor bağlam bir takımın bir oyuncu ekibi söylemek gibidir.
RobG

RobG, yazık ki devam etmek istemiyorsun. Bu ilginç bir tartışma. Bana zaman ayırdığın için teşekkürler.
Roamer-1888

31

"Bu" Anahtar Kelimeyi bilmelisiniz.

Benim görüşüme göre "bunu" üç şekilde uygulayabilirsiniz (Öz / Ok işlevi / Bağlama Yöntemi)

Bir fonksiyonun bu anahtar kelimesi JavaScript'te diğer dillerle karşılaştırıldığında biraz farklı davranır.

Ayrıca katı mod ile katı olmayan mod arasında bazı farklılıklar vardır.

Çoğu durumda, bunun değeri bir fonksiyonun nasıl çağrıldığına göre belirlenir.

Yürütme sırasında atama ile ayarlanamaz ve işlev her çağrıldığında farklı olabilir.

ES5, nasıl adlandırıldığına bakılmaksızın bir işlevin bu değerinin değerini ayarlamak için bind () yöntemini tanıttı,

ve ES2015, kendilerine bu bağlamayı sağlamayan ok fonksiyonlarını tanıttı (bu, etraftaki sözcüksel bağlamın bu değerini korur).

Yöntem1: Öz - Öz, bağlam değişse bile orijinaline bir başvuru sağlamak için kullanılır. Olay işleyicilerinde (özellikle kapaklarda) sıklıkla kullanılan bir tekniktir.

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

Yöntem2 : Ok işlevi - Ok işlevi ifadesi, normal işlev ifadesine sözdizimsel olarak kompakt bir alternatiftir,

buna kendi bağlantıları olmadan, argümanlar, süper veya new.target anahtar kelimeleri.

Ok işlev ifadeleri yöntem olarak uygun değildir ve yapıcı olarak kullanılamazlar.

Referans : https://developer.mozilla.org/tr-TR/docs/Web/JavaScript/Reference/Functions/Arrow_functions

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

Method3 : Bind- bind () yöntemi,

çağrıldığında, bu anahtar kelimesi sağlanan değere ayarlanmışsa,

yeni işlev çağrıldığında sağlanan herhangi bir argüman dizisinden önce verilen bir dizi bağımsız değişkeni içerir.

Referans: 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

İlk olarak, anahtar kelime bağlamında net bir anlayışa scopeve davranışa sahip olmanız gerekir .thisscope

this& scope:


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

   1) Global Scope

   2) Function Scope

Kısacası, global kapsam pencere nesnesini ifade eder.Küresel kapsamda bildirilen değişkenlere her yerden erişilebilir.Öte yandan işlev kapsamı bir işlevin içinde bulunur. bir işlev içinde bildirilen değişkenlere normalde dış dünyadan erişilemez. thisglobal kapsamdaki anahtar kelime, pencere nesnesini ifade eder. thiskendi fonksiyonumuzu belirtmek için thismanipüle etmenin bir yolunu bulana kadar pencereye her zaman başvururuz 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                                              -
--------------------------------------------------------------------------------

thisGeri arama işlevlerini değiştirmenin farklı yolları :

Burada Kişi adında bir yapıcı işlevim var. Adlı bir özelliği varname ve adı verilen dört yöntem sayNameVersion1, sayNameVersion2, sayNameVersion3, sayNameVersion4. Dördü de belirli bir göreve sahiptir.Bir geri çağrıyı kabul et ve çağır. Geri çağırma özelliğinin, bir yapıcı işlevi örneğinin name özelliğini günlüğe kaydetmek için belirli bir görevi vardır.

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)

}

Şimdi kişi yapıcısından bir örnek oluşturalım ve farklı sürümlerini sayNameVersionX başvurmak için iç geri aramayı niceCallbackkaç yolla değiştirebileceğimizi görmek için (X, 1,2,3,4'e başvuruyor) yönteminin .thisperson

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

bağlama:

Bağlanan, thisanahtar kelime sağlanan değere ayarlanmış olarak yeni bir işlev oluşturmaktır .

sayNameVersion1ve geri arama işlevini sayNameVersion2değiştirmek için bind komutunu kullanın this.

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

ilk bağlantı this yöntemin kendisinde geri arama ile ve ikincisi için geri çağırma nesnesi ona bağlı olarak geçirilir.

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

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

aramak :

first argumentarasındacall yöntem olarak kullanılmaktadır thisçağrılır işlevi içinde call, kendisine bağlı.

sayNameVersion3 kullanımları callthispencere nesnesi yerine oluşturduğumuz kişi nesnesine başvuruda bulunmak için .

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

ve şöyle denir:

p1.sayNameVersion3(niceCallback)

uygulamak :

Benzer call, ilk argümanıapplythis anahtar kelime ile gösterilecek nesneyi ifade eder .

sayNameVersion4applymanipüle etmek için kullanırthiskişi nesnesine başvurmak etmek için

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

ve aşağıdaki gibi çağrılır.

p1.sayNameVersion4(niceCallback)

1
cevap ile ilgili herhangi bir yapıcı eleştiri takdir edilecektir!
AL-zami

1
Genel kapsamdaki bu anahtar kelime mutlaka pencere nesnesine başvurmaz . Bu sadece bir tarayıcıda geçerlidir.
Randall Flagg

1
@RandallFlagg bu cevabı bir tarayıcı perspektifinden yazdım.Gerekirse bu cevabı atmaktan çekinmeyin :)
AL-zami

19

Geri çağırma işlevinde bağlama erişmek ve sonra geri arama işlevini kullanarak setTimeout()her zaman genel nesne (Pencere) ile yürütüldüğü için bunu bağlayamayız :thisbind()

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

9
Bu mevcut cevaplardan herhangi birinden nasıl farklı?
Felix Kling

13

Soru, thisanahtar kelimenin javascript'te nasıl davrandığıyla ilgilidir. thisaşağıdaki gibi farklı davranır,

  1. Değeri this genellikle bir işlev yürütme bağlamıyla belirlenir.
  2. Global kapsamda, thisglobal nesneyi ( windownesne) ifade eder .
  3. Herhangi bir işlev için katı mod etkinleştirilirse, değeri katı modda thisolduğu undefinedgibi olur, genel nesne nesnenin undefinedyerine windowbaşvurur.
  4. Noktadan önce duran nesne, bu anahtar kelimenin bağlanacağı şeydir.
  5. Biz birlikte bunu açıkça değerini ayarlayabilirsiniz call(), bind()veapply()
  6. Ne zaman new anahtar kelime (bir yapıcı) kullanılır, bu yeni nesne oluşturulan bağlıdır.
  7. Arrow İşlevler bağlanmaz this - bunun yerine thissözcüksel olarak bağlanır (örn. Orijinal bağlama göre)

Cevapların çoğunun önerdiği gibi, Ok işlevi veya bind()Yöntem veya Self var. Google JavaScript Stil Kılavuzu'ndan lambdas (Ok işlevi) hakkında bir nokta alıntı yapardım

F.bind (bu) ve özellikle goog.bind (f, this) yerine ok işlevlerini kullanmayı tercih edin. Const self = this yazmaktan kaçının. Ok işlevleri, bazen beklenmedik ek argümanlar ileten geri aramalar için özellikle yararlıdır.

Google, bağlama yerine lambdas kullanmanızı önerir. const self = this

Bu yüzden en iyi çözüm lambdaları aşağıdaki gibi kullanmak olacaktır,

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

Referanslar:

  1. https://medium.com/tech-tajawal/javascript-this-4-rules-7354abdb274c
  2. ok-fonksiyonlar-vs-bağlama

Bu soru, işlevlerin / yöntemlerin geri arama olarak kullanılmasıyla ilgilidir. Cevabınız stackoverflow.com/q/3127429/218196 için daha uygun olabilir .
Felix Kling

Evet soru bu ana konuda geri aramaları gibi işlevleri / yöntemleri kullanmaktan ibarettir @FelixKling taşınması nedeniyle oldu thisİki parça, yaklaşık birinde benim cevap bölünmüş neden anahtar kelime thats thisve ikinci geri aramaları gibi işlevleri / yöntemleri kullanarak ilgili. Cevabı düzenlemekten çekinmeyin.
Code_Mode

Dördüncü noktanızı belirsiz bir şekilde ifade edilmiş buluyorum. Doğru nesnenin noktadan önce durduğu ancak yine de bağlamın o nesne olmadığı "Örnek, Bu Nesneyi Geri Çağırma Olarak Kullanırken Sorun" örneğini düşünün .
bleistift2

7

Şu anda sınıflar kodda kullanılıyorsa başka bir yaklaşım daha vardır.

Sınıf alanlarının desteklenmesi ile bunu bir sonraki yoldan yapmak mümkündür:

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

Kesinlikle kaputun altında bağlamı bağlayan eski iyi ok işlevi var, ancak bu formda bu açık bağlamanın çok daha net olduğu görülüyor.

Aşama 3 Önerisi olduğundan , şu anki gibi işlemek için babil ve uygun babil eklentisine ihtiyacınız olacak (08/2018).


2
İşte tam olarak bu yazıyı Typescript'te çalıştırıyorum: public methodName = (params) => { body }bir sınıf içinde.
yeyeyerman

5

DOM2'ninthis olay dinleyicisine bağlanmanın standart yoludur ve dinleyiciyi (diğer avantajların yanı sıra) her zaman kaldırmanıza olanak tanıyan başka bir yaklaşım, arabirimden handleEvent(evt)yöntemdir EventListener:

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

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

Kullanımı hakkında ayrıntılı bilgi handleEventburada bulunabilir: https://medium.com/@WebReflection/dom-handleevent-a-cross-platform-standard-since-year-2000-5bf17287fd38


0

this JS'de:

thisJS'deki değeri, bir işlevin nasıl tanımlandığına değil, nasıl adlandırıldığına göre% 100 belirlenir. Biz nispeten kolay değerini bulabilirsiniz thistarafından 'nokta kuralının sol' :

  1. İşlev function anahtar sözcüğü kullanılarak oluşturulduğunda, değeri this, işlevin çağrıldığı noktanın solundaki nesnedir
  2. Noktanın dışında bir nesne yoksa, thisbir işlevin içindeki değer genellikle genel nesnedir ( globaldüğümde, windowtarayıcıda). thisAnahtar kelimeyi burada kullanmanızı tavsiye etmiyorum çünkü böyle bir şey kullanmaktan daha az açık window!
  3. Ok işlevleri ve işlevini kullanarak oluşturulan Function.prototype.bind()ve değerini düzeltebilen işlevler gibi belirli yapılar vardır this. Bunlar kuralın istisnalarıdır, ancak değerini düzeltmek için gerçekten yararlıdır this.

DüğümJS örneği

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

Çıktı:

resim açıklamasını buraya girin

Size 1'den 1'e kadar çıkışlarda yürüyelim (ikinciden başlayarak ilk günlüğü yok sayarak):

  1. thisolduğu obj2, çünkü nokta kuralı solun, biz nasıl görebilirsiniz test1denir obj2.test1();. obj2noktanın ve dolayısıyla thisdeğerin solunda kalır .
  2. Olsa obj2Noktanın bırakılır, test2bağlı olduğu obj1aracılığı bind()yöntemle. Yani thisdeğer obj1.
  3. obj2denir işlevinden noktanın bırakılır: obj2.test3(). Bu nedenle obj2değeri olacaktır this.
  4. Bu durumda: obj2.test4() obj2noktanın solunda kalır. Ancak ok işlevinin kendi thisbağları yoktur. Bu nedenle this, dış kapsamın değerinemodule.exports , başlangıçta kaydedilen nesne olan .
  5. İşlevini thiskullanarak değerini de belirleyebiliriz call. Burada istenen thisdeğeri bir argüman olarak iletebiliriz obj2, bu durumda.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.