“This” anahtar kelimesi nasıl çalışır?


1309

thisAnahtar kelimenin ne olduğunu ve nasıl yığın taşması sitesinde JavaScript'te doğru (ve yanlış) kullanıldığına dair net bir açıklama görünmediğini fark ettim .

Onunla çok garip bir davranışa tanık oldum ve neden oluştuğunu anlayamadım.

Nasıl thisçalışır ve ne zaman kullanılmalıdır?


6
Bunu "bu" googled ettiğimde buldum quirksmode.org/js/this.html
Wai Wong



1
MDN'ye genel bakış yarı kötü değil ... developer.mozilla.org/tr-TR/docs/JavaScript/Reference/Operators/…
dat

2
thisAnahtar kelimenin ilginç bir açıklaması : rainsoft.io/gentle-explanation-of-this-in-javascript
Dmitri Pavlutin

Yanıtlar:


1350

Önce Mike West'in Scope ( ayna ) içindeki makalesini okumanızı tavsiye ederim . thisJavaScript kavramlarına ve kapsam zincirlerine mükemmel ve samimi bir giriş niteliğindedir .

Alışmaya başladığınızda this, kurallar aslında oldukça basittir. ECMAScript 5.1 Standart tanımlar this:

§11.1.1this kelime

thisMevcut uygulama bağlamında ThisBinding değerine kelime değerlendirir

ThisBinding, JavaScript yorumlayıcısının, bir nesneye referans tutan özel bir CPU kaydı gibi, JavaScript kodunu değerlendirirken sürdürdüğü bir şeydir. Yorumlayıcı, yalnızca üç farklı durumdan birinde yürütme bağlamı oluştururken ThisBinding'ı günceller:

1. İlk global yürütme bağlamı

Bu, en üst düzeyde değerlendirilen JavaScript kodunda, örneğin doğrudan a <script>:

<script>
  alert("I'm evaluated in the initial global execution context!");

  setTimeout(function () {
      alert("I'm NOT evaluated in the initial global execution context.");
  }, 1);
</script>

İlk global yürütme bağlamında kod değerlendirilirken ThisBinding genel nesneye ayarlanır window( §10.4.1.1 ).

Değerlendirme kodunu girme

  • … Doğrudan eval() ThisBinding çağrısı değişmeden kalır; çağıran yürütme bağlamının ThisBinding ile aynı değerdir ( §10.4.2 (2) (a)).

  • … Eğer eval()
    ThisBinding'a doğrudan çağrı yapılmazsa, global nesneye ilk global yürütme bağlamında yürütülüyormuş gibi ayarlanır ( §10.4.2 (1)).

§15.1.2.1.1 doğrudan aramanın ne olduğunu tanımlar eval(). Temel olarak, eval(...)doğrudan bir çağrı, buna benzer bir şey (0, eval)(...)veya var indirectEval = eval; indirectEval(...);dolaylı bir çağrıdır eval(). Bkz chuckj yanıtını için JavaScript eval ( 'bu') vs (1, eval) ( 'Bu')? ve Dmitry Soshnikov'un ECMA-262-5'i detaylı olarak. Bölüm 2. Sıkı Mod. dolaylı eval()çağrı yapabileceğiniz zaman için .

Fonksiyon kodunu girme

Bu, bir işlev çağrıldığında oluşur. Bir işlev içinde obj.myMethod()veya eşdeğeri gibi bir nesnede çağrılırsa, obj["myMethod"]()ThisBinding nesneye ayarlanır ( objörnekte; §13.2.1 ). Diğer çoğu durumda, ThisBinding genel nesneye ayarlanır ( §10.4.3 ).

"Çoğu durumda" yazmanın nedeni, ThisBinding öğesinin bağımsız değişkenler listesinde belirtilmesine izin veren sekiz adet ECMAScript 5 yerleşik işlevinin olmasıdır. Bu özel işlevler thisArg, işlevi çağırırken ThisBinding haline gelen bir sözde ( §10.4.3 ).

Bu özel yerleşik işlevler şunlardır:

  • Function.prototype.apply( thisArg, argArray )
  • Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
  • Array.prototype.every( callbackfn [ , thisArg ] )
  • Array.prototype.some( callbackfn [ , thisArg ] )
  • Array.prototype.forEach( callbackfn [ , thisArg ] )
  • Array.prototype.map( callbackfn [ , thisArg ] )
  • Array.prototype.filter( callbackfn [ , thisArg ] )

Function.prototypeİşlevler durumunda , bunlar bir işlev nesnesinde çağrılır, ancak ThisBinding işlev nesnesine ayarlamak yerine ThisBinding öğesi olarak ayarlanır thisArg.

Array.prototypeİşlevler söz konusu olduğunda , verilen callbackfn, bu bağlamanın sağlanmışsa olarak ayarlandığı bir yürütme bağlamında çağrılır thisArg; aksi takdirde, küresel nesneye.

Bunlar düz JavaScript için kurallardır. JavaScript kitaplıklarını kullanmaya başladığınızda (örn. JQuery), belirli kitaplık işlevlerinin değerini değiştirdiğini görebilirsiniz this. Bu JavaScript kitaplıklarının geliştiricileri bunu en yaygın kullanım örneklerini destekleme eğiliminde olduğu için yapar ve kitaplık kullanıcıları genellikle bu davranışı daha uygun bulurlar. thisKütüphane işlevlerine referans veren geri çağırma işlevlerini iletirken this, işlev çağrıldığında değerinin ne olduğu konusunda herhangi bir garanti için belgelere başvurmalısınız .

Bir JavaScript kitaplığının değerini nasıl değiştirdiğini merak ediyorsanız this, kitaplık yalnızca a thisArg. Siz de bir geri arama işlevi alarak kendi işlevinizi yazabilirsiniz ve thisArg:

function doWork(callbackfn, thisArg) {
    //...
    if (callbackfn != null) callbackfn.call(thisArg);
}

Henüz bahsetmediğim özel bir durum var. newOperatör aracılığıyla yeni bir nesne oluştururken, JavaScript yorumlayıcısı yeni, boş bir nesne oluşturur, bazı iç özellikleri ayarlar ve ardından yeni nesne üzerindeki yapıcı işlevini çağırır. Bu nedenle, bir işlev yapıcı bağlamında çağrıldığında, değeri thisyorumlayıcının oluşturduğu yeni nesnedir:

function MyType() {
    this.someData = "a string";
}

var instance = new MyType();
// Kind of like the following, but there are more steps involved:
// var instance = {};
// MyType.call(instance);

Ok fonksiyonları

Ok fonksiyonları (ECMA6'da tanıtıldı) kapsamını değiştirir this. Mevcut kanonik soru olan Ok fonksiyonuna karşı fonksiyon bildirimi / ifadeler: Eşdeğer / değiştirilebilir mi? daha fazla bilgi için. Ama kısaca:

Ok fonksiyonlarının kendi thisbağları yoktur. Bunun yerine, bu tanımlayıcılar diğer değişkenler gibi sözcüksel kapsamda çözümlenir. Bu, bir ok fonksiyonunun içinde, this... thisok fonksiyonunun tanımlandığı ortamdaki değerlere atıfta bulunur .

Sadece eğlence için, bazı örneklerle anlayışınızı test edin

Cevapları ortaya çıkarmak için, fareyi açık gri kutuların üzerine getirin.

  1. thisİşaretli satırdaki değeri nedir ? Neden?

    window - İşaretli çizgi ilk global yürütme bağlamında değerlendirilir.

    if (true) {
        // What is `this` here?
    }
    
  2. thisYürütüldüğünde işaretli satırdaki değeri nedir obj.staticFunction()? Neden?

    obj - Bir nesne üzerindeki bir işlevi çağırırken, ThisBinding nesneye ayarlanır.

    var obj = {
        someData: "a string"
    };
    
    function myFun() {
        return this // What is `this` here?
    }
    
    obj.staticFunction = myFun;
    
    console.log("this is window:", obj.staticFunction() == window);
    console.log("this is obj:", obj.staticFunction() == obj);
      

  3. thisİşaretli satırdaki değeri nedir ? Neden?

    window

    Bu örnekte, JavaScript yorumlayıcısı işlev kodunu girer, ancak myFun/ obj.myMethodbir nesnede çağrılmadığından ThisBinding olarak ayarlanır window.

    Bu, bir method ( obj.myMethod) öğesine erişmenin bağlı bir yöntem nesnesi oluşturduğu Python'dan farklıdır .

    var obj = {
        myMethod: function () {
            return this; // What is `this` here?
        }
    };
    var myFun = obj.myMethod;
    console.log("this is window:", myFun() == window);
    console.log("this is obj:", myFun() == obj);
      

  4. thisİşaretli satırdaki değeri nedir ? Neden?

    window

    Bu zor oldu. Eval kod değerlendirirken, thisbir obj. Ancak, eval kodunda, myFunbir nesne üzerinde çağrılmaz, bu nedenle ThisBinding windowçağrı için ayarlanır .

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
    
  5. thisİşaretli satırdaki değeri nedir ? Neden?

    obj

    Çizgi myFun.call(obj);, ilk argüman olarak Function.prototype.call()kabul edilen özel yerleşik işlevi çağırıyor thisArg.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        someData: "a string"
    };
    console.log("this is window:", myFun.call(obj) == window);
    console.log("this is obj:", myFun.call(obj) == obj);
      


6
@Ali: ECMAScript Standardı ECMA- 262'nin 5.1 sürümündeki bölümlere referanslardır . İsterseniz teknik detaylar için Standardı okuyabilmeniz için onlara veriyorum.
Daniel Trebbien

1
Sanırım # supertonsky # 2 hakkında haklı - eğer myFun () global kapsamdan çağrılırsa ve nesne üzerinde bir yöntem olarak değil, "bu" global nesne olacak, bu yüzden sorunun ifadesi önemlidir. btw - Böyle bir şeyin cevabını almak için fareyle üzerine gelme fikrini gerçekten seviyorum.
user655489

2
Ama jsfiddle.net/H4LYm/2 göstermektedir setTimeoutörnek vardır thisiçinde window(global).
Kevin Meredith

2
Python gelen bir 3. örneğe çarptı zaman ben vardı hayal kırıklığı seviyeleri hayal ediyorum .. smh
Marius Mucenicu

1
Bu cevap muhtemelen değişiklikler terminolojik olsa bile ES2020 gerçeğini yansıtacak şekilde güncellenmelidir.
Ben Aston

156

thisFarklı JavaScript kelime davranacağını diğer dillere göre. Nesne Tabanlı dillerde, thisanahtar kelime sınıfın geçerli örneğini ifade eder. JavaScript'te değeri, this( context.function()) işlevinin çağırma bağlamı ve nerede çağrıldığı ile belirlenir.

1. Küresel bağlamda kullanıldığında

Genel thisbağlamda kullandığınızda, genel nesneye bağlanır ( windowtarayıcıda)

document.write(this);  //[object Window]

Genel thisbağlamda tanımlanan bir fonksiyonun içinde kullandığınızda this, fonksiyon aslında küresel bağlamın bir yöntemi haline getirildiği için hala global nesneye bağlıdır.

function f1()
{
   return this;
}
document.write(f1());  //[object Window]

Yukarıda f1küresel bir nesne yöntemi yapılmıştır. Böylece windownesneyi şöyle de adlandırabiliriz :

function f()
{
    return this;
}

document.write(window.f()); //[object Window]

2. Nesne yönteminin içinde kullanıldığında

Bir thisnesne yönteminin içinde anahtar kelime kullandığınızda this, "hemen" çevreleyen nesneye bağlanır.

var obj = {
    name: "obj",
    f: function () {
        return this + ":" + this.name;
    }
};
document.write(obj.f());  //[object Object]:obj

Yukarıda kelimeyi hemen çift tırnak içine aldım. Eğer nesneyi başka bir nesnenin içine yerleştirirseniz, o zaman thisüst ebeveyne bağlı olunur.

var obj = {
    name: "obj1",
    nestedobj: {
        name:"nestedobj",
        f: function () {
            return this + ":" + this.name;
        }
    }            
}

document.write(obj.nestedobj.f()); //[object Object]:nestedobj

Nesneye yöntem olarak açıkça işlev ekleseniz bile, yine de yukarıdaki kurallara thisuyar;

var obj1 = {
    name: "obj1",
}

function returnName() {
    return this + ":" + this.name;
}

obj1.f = returnName; //add method to object
document.write(obj1.f()); //[object Object]:obj1

3. Bağlamdan bağımsız işlevi çağırırken

Kullandığınızda this(herhangi bir nesne üzerinde değil yani) herhangi bir kaynak gösterilmeksizin çağrılır iç işlevini, bu (küresel nesneye bağlıdır window(işlev nesnesinin içinde tanımlanmış olsa bile) tarayıcıda).

var context = "global";

var obj = {  
    context: "object",
    method: function () {                  
        function f() {
            var context = "function";
            return this + ":" +this.context; 
        };
        return f(); //invoked without context
    }
};

document.write(obj.method()); //[object Window]:global 

Hepsini işlevlerle denemek

Yukarıdaki noktaları fonksiyonlarla deneyebiliriz. Ancak bazı farklılıklar vardır.

  • Yukarıda, nesne değişmez gösterimini kullanarak nesnelere üyeler ekledik. Kullanarak fonksiyonlara üye ekleyebiliriz this. belirtmek için.
  • Nesne değişmez gösterimi, hemen kullanabileceğimiz bir nesne örneği oluşturur. İşlev ile ilk olarak newoperatörünü kullanarak örneğini oluşturmanız gerekebilir .
  • Ayrıca bir nesne değişmez yaklaşımında, nokta operatörünü kullanarak üyeleri zaten tanımlanmış nesneye açıkça ekleyebiliriz. Bu yalnızca belirli örneğe eklenir. Ancak fonksiyon prototipine değişken ekledim, böylece fonksiyonun tüm örneklerine yansıtılacak.

Aşağıda, Object ve thisüstü ile yaptığımız her şeyi denedim , ancak doğrudan bir nesne yazmak yerine işlev oluşturarak.

/********************************************************************* 
  1. When you add variable to the function using this keyword, it 
     gets added to the function prototype, thus allowing all function 
     instances to have their own copy of the variables added.
*********************************************************************/
function functionDef()
{
    this.name = "ObjDefinition";
    this.getName = function(){                
        return this+":"+this.name;
    }
}        

obj1 = new functionDef();
document.write(obj1.getName() + "<br />"); //[object Object]:ObjDefinition   

/********************************************************************* 
   2. Members explicitly added to the function protorype also behave 
      as above: all function instances have their own copy of the 
      variable added.
*********************************************************************/
functionDef.prototype.version = 1;
functionDef.prototype.getVersion = function(){
    return "v"+this.version; //see how this.version refers to the
                             //version variable added through 
                             //prototype
}
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   3. Illustrating that the function variables added by both above 
      ways have their own copies across function instances
*********************************************************************/
functionDef.prototype.incrementVersion = function(){
    this.version = this.version + 1;
}
var obj2 = new functionDef();
document.write(obj2.getVersion() + "<br />"); //v1

obj2.incrementVersion();      //incrementing version in obj2
                              //does not affect obj1 version

document.write(obj2.getVersion() + "<br />"); //v2
document.write(obj1.getVersion() + "<br />"); //v1

/********************************************************************* 
   4. `this` keyword refers to the immediate parent object. If you 
       nest the object through function prototype, then `this` inside 
       object refers to the nested object not the function instance
*********************************************************************/
functionDef.prototype.nestedObj = { name: 'nestedObj', 
                                    getName1 : function(){
                                        return this+":"+this.name;
                                    }                            
                                  };

document.write(obj2.nestedObj.getName1() + "<br />"); //[object Object]:nestedObj

/********************************************************************* 
   5. If the method is on an object's prototype chain, `this` refers 
      to the object the method was called on, as if the method was on 
      the object.
*********************************************************************/
var ProtoObj = { fun: function () { return this.a } };
var obj3 = Object.create(ProtoObj); //creating an object setting ProtoObj
                                    //as its prototype
obj3.a = 999;                       //adding instance member to obj3
document.write(obj3.fun()+"<br />");//999
                                    //calling obj3.fun() makes 
                                    //ProtoObj.fun() to access obj3.a as 
                                    //if fun() is defined on obj3

4. Yapıcı işlevi içinde kullanıldığında .

İşlev bir kurucu olarak kullanıldığında (yani newanahtar sözcükle çağrıldığında ), thisişlev gövdesi içinde inşa edilen yeni nesneyi gösterir.

var myname = "global context";
function SimpleFun()
{
    this.myname = "simple function";
}

var obj1 = new SimpleFun(); //adds myname to obj1
//1. `new` causes `this` inside the SimpleFun() to point to the
//   object being constructed thus adding any member
//   created inside SimipleFun() using this.membername to the
//   object being constructed
//2. And by default `new` makes function to return newly 
//   constructed object if no explicit return value is specified

document.write(obj1.myname); //simple function

5. Prototip zincirinde tanımlanan fonksiyonun içinde kullanıldığında

Yöntem bir nesnenin prototip zincirindeyse, thisbu yöntem içinde, yöntem nesnede tanımlanmış gibi, yöntemin çağrıldığı nesneyi ifade eder.

var ProtoObj = {
    fun: function () {
        return this.a;
    }
};
//Object.create() creates object with ProtoObj as its
//prototype and assigns it to obj3, thus making fun() 
//to be the method on its prototype chain

var obj3 = Object.create(ProtoObj);
obj3.a = 999;
document.write(obj3.fun()); //999

//Notice that fun() is defined on obj3's prototype but 
//`this.a` inside fun() retrieves obj3.a   

6. Inside call (), uygulamak () ve bind () işlevleri

  • Tüm bu yöntemler tanımlanmıştır Function.prototype.
  • Bu yöntemler bir fonksiyonun bir kez yazılmasına ve farklı bağlamda çağrılmasına izin verir. Başka bir deyişle, thisişlev yürütülürken kullanılacak değeri belirtmeye izin verir . Ayrıca, çağrıldığında orijinal işleve geçirilecek parametreleri alırlar.
  • fun.apply(obj1 [, argsArray])İçinin obj1değeri olarak thisayarlanır fun()ve fun()geçen öğelerini argsArrayargümanları olarak çağırır .
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- İçerideki obj1değeri ve argüman olarak iletilen çağrıları ayarlar .thisfun()fun()arg1, arg2, arg3, ...
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- işlevine başvuru döndürür funile thisiç bağlanan eğlenceli obj1ve parametreleri funbelirtilen parametrelere bağlı arg1, arg2, arg3,....
  • Artık arasındaki fark apply, callve bindbelirgin hale gelmiş olmalıdır. applydizi benzeri nesne olarak işlev görecek bağımsız değişkenlerin belirtilmesine izin verir; başka bir deyişle sayısal bir lengthözelliğe ve karşılık gelen negatif olmayan tamsayı özelliklerine sahip bir nesneye . Oysa callişlevin bağımsız değişkenlerini doğrudan belirtmeye izin verir. Hem applyve callhemen işlevi belirtilen bağlamda ve belirtilen bağımsız değişkenlerle çağırır. Öte yandan, bindsadece belirtilen thisdeğere ve bağımsız değişkenlere bağlı işlevi döndürür . Bu döndürülen işleve referansı bir değişkene atayarak yakalayabiliriz ve daha sonra istediğiniz zaman çağırabiliriz.
function add(inc1, inc2)
{
    return this.a + inc1 + inc2;
}

var o = { a : 4 };
document.write(add.call(o, 5, 6)+"<br />"); //15
      //above add.call(o,5,6) sets `this` inside
      //add() to `o` and calls add() resulting:
      // this.a + inc1 + inc2 = 
      // `o.a` i.e. 4 + 5 + 6 = 15
document.write(add.apply(o, [5, 6]) + "<br />"); //15
      // `o.a` i.e. 4 + 5 + 6 = 15

var g = add.bind(o, 5, 6);       //g: `o.a` i.e. 4 + 5 + 6
document.write(g()+"<br />");    //15

var h = add.bind(o, 5);          //h: `o.a` i.e. 4 + 5 + ?
document.write(h(6) + "<br />"); //15
      // 4 + 5 + 6 = 15
document.write(h() + "<br />");  //NaN
      //no parameter is passed to h()
      //thus inc2 inside add() is `undefined`
      //4 + 5 + undefined = NaN</code>

7. thisiçerideki olay işleyicileri

  • Bir öğenin olay işleyicilerine doğrudan işlev atadığınızda, thisdoğrudan olay işleme işlevinin kullanımı karşılık gelen öğeyi ifade eder. Bu tür doğrudan işlev atama addeventListeneryöntemi kullanılarak veya gibi geleneksel olay kayıt yöntemleri kullanılarak yapılabilir onclick.
  • Benzer şekilde, thisdoğrudan <button onclick="...this..." >öğenin event özelliği (like ) içinde kullandığınızda, öğeyi ifade eder.
  • Ancak thisdolaylı olarak, olay işleme işlevinin veya olay özelliğinin içinde çağrılan diğer işlev aracılığıyla kullanılması , genel nesneye çözümlenir window.
  • Yukarıdaki davranış, Microsoft'un Olay Kayıt modeli yöntemini kullanarak olay işleyicisine eklediğimizde de elde edilir attachEvent. İşlevi olay işleyicisine atamak (ve böylece öğenin işlev yöntemini yapmak) yerine, olaydaki işlevi çağırır (etkin biçimde genel bağlamda çağırır).

JSFiddle daha iyi denemenizi öneririz .

<script> 
    function clickedMe() {
       alert(this + " : " + this.tagName + " : " + this.id);
    } 
    document.getElementById("button1").addEventListener("click", clickedMe, false);
    document.getElementById("button2").onclick = clickedMe;
    document.getElementById("button5").attachEvent('onclick', clickedMe);   
</script>

<h3>Using `this` "directly" inside event handler or event property</h3>
<button id="button1">click() "assigned" using addEventListner() </button><br />
<button id="button2">click() "assigned" using click() </button><br />
<button id="button3" onclick="alert(this+ ' : ' + this.tagName + ' : ' + this.id);">used `this` directly in click event property</button>

<h3>Using `this` "indirectly" inside event handler or event property</h3>
<button onclick="alert((function(){return this + ' : ' + this.tagName + ' : ' + this.id;})());">`this` used indirectly, inside function <br /> defined & called inside event property</button><br />

<button id="button4" onclick="clickedMe()">`this` used indirectly, inside function <br /> called inside event property</button> <br />

IE only: <button id="button5">click() "attached" using attachEvent() </button>

8. thisES6 ok işlevinde

Bir ok işlevinde thisortak değişkenler gibi davranacaktır: sözcüksel kapsamından miras alınacaktır. Fonksiyon en thisok fonksiyonu tanımlanır, ok fonksiyonu en olacaktır this.

Yani, aynı davranış:

(function(){}).bind(this)

Aşağıdaki koda bakın:

const globalArrowFunction = () => {
  return this;
};

console.log(globalArrowFunction()); //window

const contextObject = {
  method1: () => {return this},
  method2: function(){
    return () => {return this};
  }
};

console.log(contextObject.method1()); //window

const contextLessFunction = contextObject.method1;

console.log(contextLessFunction()); //window

console.log(contextObject.method2()()) //contextObject

const innerArrowFunction = contextObject.method2();

console.log(innerArrowFunction()); //contextObject 

"Bunu global bağlamda tanımlanan bir fonksiyonun içinde kullandığınızda, fonksiyon aslında global bağlamın bir yöntemi haline getirildiğinden, bu hala global nesneye bağlıdır." yanlış. bu , bir işlevin nasıl tanımlandığına veya bağlandığına göre belirlenir, tanımlandığı yere göre değil. Temel başvurusu ("bağlam") olmadan herhangi bir işlev çağrıldığında, bu değer varsayılan olarak genel nesneye ya da katı modda tanımsız olarak kalır.
RobG

@RobG hmm olabilir ama buldum MDN'yi bu : Bu durumda, değeri thisçağrısıyla ayarlı değil. Kod katı modda olmadığından, değeri thisher zaman bir nesne olmalıdır , böylece varsayılan olarak global nesneyi alır. Ve aslında bu yüzden doğrudan arama yapabileceğimizi düşündüm window.f1(), yani bu f1()zaten windownesneye zaten bağlı , yani çağrılmadan önce. Yanlış mı anladım?
Mahesha999

Ben senin ayarını bağlamaya ilişkin (belki değil açıkça) yorumlarken geldi bu bu bir çeşit denilen ait olduğunu sanki "fonksiyonu aslında küresel bağlamda bir yöntem yapılır" ile window.fndeğil, hangi. Bu herhangi bir temel referans çünkü fonksiyonu tanımlandığı gibidir bölgesinin çağrı kullanıldığı için genel nesneyi varsayılan (böylece bu hala işlev adı nasıl ile ayarlanır). Açıkça kullanarak ararsanız window.fn, o zaman ayarlarken bu kadar pencerenin . Aynı sonuç, farklı bir yoldan gitme. :-)
RobG

"Yukarıda kelimeyi hemen koydum ..." hayır. Hatayı düzeltmek için lütfen bunu revize edebilir misiniz? Cevaba anlamsal geliyor ve bu nedenle yanlış bir şey öğrenme korkusu giderilinceye kadar okumaya devam edemiyorum.
TylerH

@TylerH "acil" (çift tırnak dahil) dize bulmak için tarayıcınızda bu sayfada Ctrl + F yapmak Ben yanlış u anlıyorum varsa orada düşünüyorum
Mahesha999

64

JavaScript en this

Basit işlev çağırma

Aşağıdaki işlevi göz önünde bulundurun:

function foo() {
    console.log("bar");
    console.log(this);
}
foo(); // calling the function

Bunu normal modda çalıştırdığımızı, yani katı modun kullanılmadığını unutmayın.

Bir tarayıcıda çalışırken, değeri thisolarak günlüğe kaydedilir window. Bunun nedeni window, bir web tarayıcısının kapsamındaki global değişken olmasıdır.

Aynı kod parçasını node.js gibi bir ortamda çalıştırırsanız, thisuygulamanızdaki genel değişkene başvurur.

"use strict";İşlev deyiminin başlangıcına ifade ekleyerek bunu katı modda çalıştırırsak , thisartık ortamların hiçbirindeki genel değişkene başvurmayacağız. Bu, katı modda karışıklıkları önlemek için yapılır. thisBu durumda, sadece log olur undefined, çünkü budur, tanımlanmamıştır.

Aşağıdaki durumlarda, değerini nasıl değiştireceğimizi göreceğiz this.

Bir nesne üzerinde fonksiyon çağırma

Bunu yapmanın farklı yolları vardır. Javascript'te forEachve gibi yerel yöntemleri çağırdıysanız slice, zaten thisbu durumda değişkenin Objecto işlevi çağırdığınız anlamına geldiğini bilmelisiniz (Javascript'te, s ve s Objectdahil olmak üzere hemen hemen her şeyin bir olduğunu unutmayın ). Örneğin aşağıdaki kodu ele alalım.ArrayFunction

var myObj = {key: "Obj"};
myObj.logThis = function () {
    // I am a method
    console.log(this);
}
myObj.logThis(); // myObj is logged

Bir Object, a içeren bir özellik içeriyorsa Function, özelliğe yöntem adı verilir. Bu yöntem çağrıldığında, thisdeğişkenin Objectilişkili olduğu değişkene her zaman sahip olacaktır . Bu hem katı hem de katı olmayan modlar için geçerlidir.

Bir yöntem başka bir değişkende saklanırsa (veya kopyalanırsa), başvurunun thisartık yeni değişkende korunmadığına dikkat edin. Örneğin:

// continuing with the previous code snippet

var myVar = myObj.logThis;
myVar();
// logs either of window/global/undefined based on mode of operation

Daha yaygın olarak kullanılan bir senaryo dikkate alındığında:

var el = document.getElementById('idOfEl');
el.addEventListener('click', function() { console.log(this) });
// the function called by addEventListener contains this as the reference to the element
// so clicking on our element would log that element itself

newanahtar kelime

Javascript'te bir yapıcı işlevi düşünün:

function Person (name) {
    this.name = name;
    this.sayHello = function () {
        console.log ("Hello", this);
    }
}

var awal = new Person("Awal");
awal.sayHello();
// In `awal.sayHello`, `this` contains the reference to the variable `awal`

Bu nasıl çalışıyor? newAnahtar kelimeyi kullandığımızda ne olacağını görelim .

  1. İşlevi newanahtar sözcükle çağırmak derhal bir Objecttür başlatır Person.
  2. Bunun yapıcısının Objectyapıcısı olarak ayarlanmıştır Person. Ayrıca, sadece typeof awaldöneceğini unutmayın Object.
  3. Bu yeni Objectmodelin prototipi atanır Person.prototype. Bu, Personprototipteki herhangi bir yöntemin veya özelliğin Person, dahil tüm örnekleri için kullanılabilir olacağı anlamına gelir awal.
  4. Fonksiyonun Personkendisi çağrılmıştır; thisyeni inşa edilen nesneye referans olması awal.

Çok basit, ha?

Resmi ECMAScript spesifikasyonunun hiçbir yerde bu tür işlevlerin gerçek constructorişlevler olduğunu belirtmediğini unutmayın . Bunlar sadece normal işlevlerdir ve newherhangi bir işlevde kullanılabilir. Sadece onları bu şekilde kullanıyoruz ve bu yüzden onları sadece böyle adlandırıyoruz.

Fonksiyonlardaki çağrı fonksiyonları: callveapply

Yani evet, functions de Objects(ve aslında Javascript'teki birinci sınıf değişkenler) olduğundan, işlevlerin bile ... iyi, işlevlerin kendileri olan yöntemleri vardır.

Tüm fonksiyonlar küresel devralan Function, ve birçok yöntemden ikisidir callve applyve her ikisi de değerini manipüle etmek için kullanılabilir thisdedikleri edildiği işlevinde.

function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);

Bu tipik bir kullanım örneğidir call. Temel olarak ilk parametreyi alır ve thisişlevde fooreferans olarak ayarlanır thisArg. Diğer tüm parametreler callişleve fooargümanlar olarak iletilir .
Yukarıdaki kod {myObj: "is cool"}, [1, 2, 3]konsolda oturum açacaktır . thisHerhangi bir fonksiyonun değerini değiştirmek için oldukça güzel bir yol .

applycallyalnızca iki parametre aldığını kabul etmekle neredeyse aynıdır : thisArgve işleve iletilecek bağımsız değişkenleri içeren bir dizi. Yani yukarıdaki callçağrı şu şekilde tercüme edilebilir apply:

foo.apply(thisArg, [1,2,3])

Dikkat edin callve ikinci madde işaretinde tartıştığımız nokta yöntemi çağırma applyile thisset değerini geçersiz kılabilir . Yeterince basit :)

Sunum .... bind!

bindcallve kardeşidir apply. Ayrıca FunctionJavascript'te global yapıcıdan tüm fonksiyonlar tarafından miras alınan bir yöntemdir . bindVe call/ arasındaki fark apply, her ikisinin callve applyaslında işlevi çağıracağıdır. bind, öte yandan thisArgve ile argumentsönceden ayarlanmış yeni bir işlev döndürür . Bunu daha iyi anlamak için bir örnek alalım:

function foo (a, b) {
    console.log (this, arguments);
}
var thisArg = {myObj: "even more cool now"};
var bound = foo.bind(thisArg, 1, 2);
console.log (typeof bound); // logs `function`
console.log (bound);
/* logs `function () { native code }` */

bound(); // calling the function returned by `.bind`
// logs `{myObj: "even more cool now"}, [1, 2]`

Üçü arasındaki farkı görüyor musunuz? İnce ama farklı kullanılıyor. Gibi callve apply, nokta yöntemi çağırma bindile thisset değerini de aşacaktır.

Ayrıca, bu üç işlevden hiçbirinin orijinal işlevde herhangi bir değişiklik yapmadığını unutmayın. callve applyyeni yapılandırılmış işlevlerden değeri binddöndürürken, çağrılmaya hazır yeni yapılandırılmış işlevin kendisini döndürür.

Ekstra şeyler, bunu kopyala

Bazen, thiskapsamla, özellikle iç içe kapsamla değiştiği gerçeğini sevmezsiniz. Aşağıdaki örneğe bir göz atın.

var myObj = {
    hello: function () {
        return "world"
        },
    myMethod: function () {
        // copy this, variable names are case-sensitive
        var that = this;
        // callbacks ftw \o/
        foo.bar("args", function () {
            // I want to call `hello` here
            this.hello(); // error
            // but `this` references to `foo` damn!
            // oh wait we have a backup \o/
            that.hello(); // "world"
        });
    }
  };

Yukarıdaki kodda, thisiç içe kapsamla değiştirilen değerin değiştiğini görüyoruz , ancak thisorijinal kapsamdan değerini istiyorduk . Biz kopyaladı 'Yani thisetmek thatve kullanılan yerine kopyalamak this. Zeki, ha?

Dizin:

  1. thisVarsayılan olarak ne tutulur ?
  2. Fonksiyonu Object-dot gösterimi ile bir yöntem olarak çağırırsak ne olur?
  3. newAnahtar kelimeyi kullanırsak ne olur ?
  4. Nasıl değişiklik yapmıyoruz thisile callve apply?
  5. Kullanma bind.
  6. thisİç içe geçmiş sorunları çözmek için kopyalama .

47

"Bu" tamamen kapsamla ilgilidir. Her işlevin kendi kapsamı vardır ve JS'deki her şey bir nesne olduğundan, bir işlev bile "this" kullanarak bazı değerleri kendi içinde saklayabilir. OOP 101, "bunun" yalnızca bir nesnenin örnekleri için geçerli olduğunu öğretir . Bu nedenle, bir işlev her çalıştırıldığında, o işlevin yeni bir "örneği" nin yeni bir "bu" anlamı vardır.

Çoğu kişi, "anonim" gibi anonim kapatma işlevlerinin içinde "bu" kullanmaya çalıştıklarında kafası karışır:

(işlev (değer) {
    this.value = değer;
    $ ('. Bazı elementler). Her (fonksiyonu (ELT) {
        elt.innerHTML = this.value; // ah ah !! muhtemelen tanımsız
    });
}) (2);

Yani burada, her bir () içinde, "bu" beklediğiniz "değeri" içermez (

this.value = değer;
üzerinde). Yani, bu (cinas amaçlı değil) sorunu aşmak için bir geliştirici şunları yapabilir:

(işlev (değer) {
    var self = bu; // küçük değişim
    self.value = değer;
    $ ('. Bazı elementler). Her (fonksiyonu (ELT) {
        elt.innerHTML = özdeğer; // vay !! == 2
    });
}) (2);

Denemek; bu programlama modelini beğenmeye başlayacaksınız



6
İlkel değerlerin kendileri üzerinde String # substring (), Number # toString () vb. tüm prototiplenmiş, yani. String # substring () gerçekten: String.prototype.substring = function () {...}). Yanılıyorsam lütfen beni düzeltin.
arunjitsingh

12
thisAnahtar kelime kapsamı ile ilgisi yoktur. Ayrıca, nesnelerin özellikleri olmayan işlevlerde de bir anlamı vardır.
Bergi

1
@ arunjitsingh — bu konuda iki düşünce okulu var. " Her şey bir nesne, ama bazıları kolaylık için ilkellerle temsil edilebilir " diyen kişiyi seviyorum . ;-)
RobG

9
thiskapsam hakkında TÜM değildir. Kapsamla aynı şey olmayan yürütme bağlamıyla ilgili TÜMÜ. JavaScript sözlü olarak kapsamlıdır (anlam kapsamı kodun konumuna göre belirlenir), ancak thisonu içeren işlevin nasıl çağrıldığına göre belirlenir - bu işlevin bulunduğu yerde değil.
Scott Marcus

16

Bu iş parçacığı patladı beri, thiskonuya yeni okuyucular için birkaç puan derledik .

thisTespit edilen değer nasıl belirlenir?

Biz bu bizim İngilizce gibi doğal dilde bir niyetimiz benzer şekilde kullanın: “Çünkü John hızlı çalışıyorsa o treni yakalamak için çalışıyor.” Bunun yerine “… John treni yakalamaya çalışıyor” yazabilirdik.

var person = {    
    firstName: "Penelope",
    lastName: "Barrymore",
    fullName: function () {

    // We use "this" just as in the sentence above:
       console.log(this.firstName + " " + this.lastName);

    // We could have also written:
       console.log(person.firstName + " " + person.lastName);
    }
}

this bir nesne tanımlandığı işlevi çağırana kadar bir değer atanmaz . Global kapsamda, tüm global değişkenler ve fonksiyonlar windownesne üzerinde tanımlanır . Bu nedenle, thisglobal bir fonksiyonda global windownesneye atıfta bulunur (ve değerine sahiptir) .

Ne zaman use strict, thisglobal ve anonim fonksiyonlarda herhangi bir nesneye bağlı olmayan bir değeri tutar undefined.

thisAnahtar kelime en çok yanlış 1) kullanan bir yöntem alabilir: this, 2) kullanan bir yöntem seçilip thisbir değişkene, 3) bir fonksiyonu kullandığı this4 bir geri arama fonksiyonu olarak geçirilir ve) thisbir kapak içinde kullanılır - bir iç işlev. (2)

tablo

Geleceği neler tutar

ECMA Script 6'da tanımlanan ok fonksiyonları, thisbağlayıcı (fonksiyon veya global) kapsamdan bağlamayı benimser .

function foo() {
     // return an arrow function
     return (a) => {
     // `this` here is lexically inherited from `foo()`
     console.log(this.a);
  };
}
var obj1 = { a: 2 };
var obj2 = { a: 3 };

var bar = foo.call(obj1);
bar.call( obj2 ); // 2, not 3!

Ok işlevleri kullanıma bir alternatif sunsa da bind(), temelde geleneksel thismekanizmayı daha geniş bir şekilde anlaşılan sözlük kapsamı lehine devre dışı bıraktıklarını belirtmek önemlidir . (1)


Referanslar:

  1. Bu ve Nesne Prototipleri , Kyle Simpson. © 2014 Getify Çözümleri.
  2. javascriptissexy.com - http://goo.gl/pvl0GX
  3. Angus Croll - http://goo.gl/Z2RacU

16

thisJavaScript'te her zaman yürütülmekte olan işlevin 'sahibini' belirtir .

Açık bir sahip tanımlanmamışsa, en üstteki sahip olan pencere nesnesine başvurulur.

Eğer öyleysem

function someKindOfFunction() {
   this.style = 'foo';
}

element.onclick = someKindOfFunction;

thisöğe nesnesine atıfta bulunur. Ancak dikkatli olun, birçok insan bu hatayı yapar.

<element onclick="someKindOfFunction()">

İkinci durumda, yalnızca öğeye başvurmazsınız, işleve başvurursunuz. Bu nedenle, thispencere nesnesine atıfta bulunacaktır.


15

Javascript'teki her yürütme bağlamının şu parametresi vardır:

  1. İşlevin nasıl çağrıldığı (bir nesne yöntemi, çağrı ve uygulama kullanımı, yeni kullanım )
  2. Kullanımı bağlama
  3. Ok işlevleri için sözcüksel olarak ( dış yürütme bağlamının bunu benimserler )
  4. Kodun katı veya katı olmayan modda olup olmadığı
  5. Kod kullanılarak çağrılıp çağrılmadı eval

Sen değerini ayarlayabilirsiniz bu kullanarak func.call, func.applyya da func.bind.

Varsayılan olarak ve yeni başlayanların çoğunu şaşırtan şey, bir DOM öğesinde bir olay oluşturulduktan sonra bir dinleyici çağrıldığında , işlevin bu değeri DOM öğesidir.

jQuery bunu jQuery.proxy ile değiştirmeyi önemsiz kılar.


9
Her fonksiyon çağrısının bir kapsamı olduğunu söylemek biraz daha doğru . Başka bir deyişle, peki ya karıştıran thisJavaScript bunun olmasıdır değil işlevin kendisi içsel bir özelliği değil, işlevi çağrılır yolu bir obje.
Sivri

@pointy teşekkürler. js'de bu konuda en fazla karışıklığa neden olan şey, daha önce kullanılan tüm dillerde (c #, c ++), bu değiştirilemez n her zaman nesne örneğine işaret ederken, js'de bağımlıdır ve çağrılırken değiştirilebilir işlevleri kullanarak func.call, func.bindvb - Suşil
sushil

2
thisyok değil bir işlevin kapsamı referans. belirttiğiniz gibi veya kullanılarak değiştirilebilen thisbelirli bir nesneye (veya muhtemelen undefined) başvurur . Bir işlevin kapsamı (esas olarak, basitleştirildiğinde) hangi değişkenlere erişebileceğidir ve bu tamamen işlevin nerede bildirildiğine ve değiştirilemediğine bağlıdır. .call().apply()
nnnnnn

@Pointy: "Her işlev çağrısının bir kapsamı olduğunu söylemek biraz daha doğru." Daha doğru (şimdi ve bloklar) o işlevler var demek kapsamı , fonksiyon çağrıları var bağlamı . Kapsam, bu kapsamdaki kod tarafından kullanılabilen tanımlayıcıların ne olduğunu tanımlar. Bağlam, bu tanımlayıcıların neye bağlı olduğunu tanımlar.
TJ Crowder

1
"Bu kapsam ne olursa olsun," this "ile ifade edilir." Hayır thisve kapsamın ES5 ve öncesinde birbirleriyle hiçbir ilgisi yoktur (örneğin, bu cevabın yazıldığı zaman). (ES6 bilinir) ES2015, içinde thisve kapsamı ile ilgili olan bir işlevleri (ok wrt oldukça az bir şekilde thisbir ok işlevi olan parça kapsamından devralınır), ancak thisbir kapsamda belirtir olmadı.
TJ Crowder

10

İşte biri iyi kaynağıdır thisiçinde JavaScript.

İşte özet:

  • küresel bu

    Bir tarayıcıda, küresel kapsamda, thisolduğu windownesne

    <script type="text/javascript">
      console.log(this === window); // true
      var foo = "bar";
      console.log(this.foo); // "bar"
      console.log(window.foo); // "bar"

    In nodeRepl kullanarak, thisüst ad alanıdır. Ona başvurabilirsiniz global.

    >this
      { ArrayBuffer: [Function: ArrayBuffer],
        Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
        Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
        ...
    >global === this
     true

    Olarak node, bir komut yürütme thisküresel kapsamı boş bir nesne olarak başlar. İle aynı değilglobal

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
  • bunu işle

DOM olay işleyicileri dışında veya bir thisArgsağlandığında (aşağıya bakın), hem düğümde hem de tarayıcıda , genel kapsamın başvurularıyla thisçağrılmayan bir işlevi kullanma new

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();
    console.log(this.foo); //logs "foo"
</script>

Eğer kullanırsanız use strict;, bu durumda thisolacaktırundefined

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      "use strict";
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    testThis();  //Uncaught TypeError: Cannot set property 'foo' of undefined 
</script>

Eğer bir işlev çağırırsanız olacak yeni bağlamda, küresel referans olmayacaktır .newthisthis

<script type="text/javascript">
    foo = "bar";

    function testThis() {
      this.foo = "foo";
    }

    console.log(this.foo); //logs "bar"
    new testThis();
    console.log(this.foo); //logs "bar"

    console.log(new testThis().foo); //logs "foo"
</script>
  • bunu prototiple

Oluşturduğunuz işlevler işlev nesneleri haline gelir. Otomatik olarak özel bir prototypeözellik alırlar , bu da değer atayabileceğiniz bir şeydir. İşlevinizi çağırarak bir örnek oluşturduğunuzda new, prototypeözelliğe atadığınız değerlere erişebilirsiniz . Bu değerlere kullanarak erişirsiniz this.

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

Thing.prototype.foo = "bar";

var thing = new Thing(); //logs "bar"
console.log(thing.foo);  //logs "bar"

Üzerinde diziler veya nesneler atamak genellikle bir hatadır prototype. Her birinin örneklerinin kendi dizileri olmasını istiyorsanız, bunları prototipte değil işlevde oluşturun.

function Thing() {
    this.things = [];
}

var thing1 = new Thing();
var thing2 = new Thing();
thing1.things.push("foo");
console.log(thing1.things); //logs ["foo"]
console.log(thing2.things); //logs []
  • buna itiraz et

Sen kullanabilirsiniz thiso nesne üzerinde diğer özellikleri başvurmak için bir nesne üzerinde herhangi işlevinde. Bu, ile oluşturulan bir örnekle aynı değildir new.

var obj = {
    foo: "bar",
    logFoo: function () {
        console.log(this.foo);
    }
};

obj.logFoo(); //logs "bar"
  • DOM etkinliği bu

Bir HTML DOM olay işleyicisinde, thisher zaman etkinliğin eklendiği DOM öğesine bir referanstır

function Listener() {
    document.getElementById("foo").addEventListener("click",
       this.handleClick);
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs "<div id="foo"></div>"
}

var listener = new Listener();
document.getElementById("foo").click();

Siz bindbağlam olmadıkça

function Listener() {
    document.getElementById("foo").addEventListener("click", 
        this.handleClick.bind(this));
}
Listener.prototype.handleClick = function (event) {
    console.log(this); //logs Listener {handleClick: function}
}

var listener = new Listener();
document.getElementById("foo").click();
  • HTML bunu

JavaScript koyabileceğiniz HTML özniteliklerinin içindeki thisöğeye bir referanstır.

<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
  • bunu değerlendir

evalErişim için kullanabilirsiniz this.

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    eval("console.log(this.foo)"); //logs "bar"
}

var thing = new Thing();
thing.logFoo();
  • Bununla

Açık bir şekilde başvurmadan değerleri okumak ve yazmak için geçerli kapsama witheklemek thisiçin kullanabilirsiniz .thisthis

function Thing () {
}
Thing.prototype.foo = "bar";
Thing.prototype.logFoo = function () {
    with (this) {
        console.log(foo);
        foo = "foo";
    }
}

var thing = new Thing();
thing.logFoo(); // logs "bar"
console.log(thing.foo); // logs "foo"
  • jQuery bunu

jQuery birçok yerde thisbir DOM öğesine başvurur.

<div class="foo bar1"></div>
<div class="foo bar2"></div>
<script type="text/javascript">
$(".foo").each(function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").on("click", function () {
    console.log(this); //logs <div class="foo...
});
$(".foo").each(function () {
    this.click();
});
</script>

9

Daniel, harika bir açıklama! thisOlay işleyicileri durumunda bu ve yürütme bağlam işaretçisinin iyi bir listesi üzerinde birkaç kelime .

İki kelimeyle, thisJavaScript'te geçerli işlevin çalıştırıldığı (veya yürütme bağlamından) nesneyi işaret eder ve her zaman salt okunurdur, yine de ayarlayamazsınız (böyle bir girişim 'Geçersiz sol el ile sonuçlanır. ödev tarafı 'mesajı.

Olay işleyicileri için:<element onclick="foo"> daha önce ve daha önce eklenen diğer işleyicileri geçersiz kılmak gibi satır içi olay işleyicileri, bu yüzden dikkatli olun ve satır içi olay temsilcisinden uzak durmak daha iyidir. Ve muhalif bir tartışma yoluyla bana bu örnek listesine ilham veren Zara Alaverdyan sayesinde :)

  • el.onclick = foo; // in the foo - obj
  • el.onclick = function () {this.style.color = '#fff';} // obj
  • el.onclick = function() {doSomething();} // In the doSomething - Window
  • el.addEventListener('click',foo,false) // in the foo - obj
  • el.attachEvent('onclick, function () { // this }') // window, all the compliance to IE :)
  • <button onclick="this.style.color = '#fff';"> // obj
  • <button onclick="foo"> // In the foo - window, but you can <button onclick="foo(this)">

9

"Bu" anahtar kelimenin JavaScript'te nasıl yorumlandığı konusunda çok fazla kafa karışıklığı var . Umarım bu makale tüm bunları bir kez ve herkes için dinlendirir. Ve çok daha fazlası. Lütfen makalenin tamamını dikkatlice okuyun. Bu makalenin uzun olduğu unutulmamalıdır.

Hangi bağlamda kullanılırsa kullanılsın, "this" her zaman Javascript'teki "current object" e başvurur. Ancak, "mevcut nesnenin" ne olduğu bağlama göre değişir . Bağlam tam olabilir 1 ila 6 arasında aşağıdaki:

  1. Global (yani tüm fonksiyonların dışında)
  2. İçinde Doğrudan "Non Bound İşlev" Çağrı (gelmiştir yani bir işlev değil arayarak bağlı functionName.bind )
  3. İç Dolaylı "Sınırsız İşlev" içinde functionName.call ve functionName.apply aracılığıyla çağrı yapın
  4. "Bağlı Fonksiyon" Çağrısının içinde (yani functionName.bind çağrılarak bağlanmış bir fonksiyon )
  5. "Yeni" ile Nesne Yaratma
  6. Inside Inline DOM olay işleyicisi

Aşağıda bu bağlamların her biri tek tek açıklanmaktadır:

  1. Global Bağlam (yani tüm fonksiyonların dışında):

    Tüm fonksiyonların dışında (yani global bağlamda) "mevcut nesne" (ve dolayısıyla "bu" değeri ) her zaman tarayıcılar için "pencere" nesnesidir.

  2. Doğrudan Dahili "Sınırsız Fonksiyon" Çağrısı :

    Doğrudan "Sınırsız Fonksiyon" Çağrısının içinde, fonksiyon çağrısını çağıran nesne "mevcut nesne" (ve dolayısıyla "bu" değeri ) olur. Bir fonksiyon bir açık olmadan çağrılırsa akım nesnenin , akım nesne ya olan "pencere" (Non Sıkı Modu için) nesne veya tanımsız (Sıkı Modu için). Genel Bağlamda tanımlanan herhangi bir işlev (veya değişken) otomatik olarak "pencere" nesnesinin bir özelliği haline gelir. Örneğin, varsayalım Genel Bağlamda,

    function UserDefinedFunction(){
        alert(this)
        }

    sanki onu tanımlamış gibi pencere nesnesinin özelliği haline gelir

    window.UserDefinedFunction=function(){
      alert(this)
    }  

    "Katı Olmayan Mod" da, bu işlevi doğrudan "UserDefinedFunction ()" aracılığıyla çağırmak / çağırmak otomatik olarak "window.UserDefinedFunction () " olarak "geçerli nesne" olarak "pencere" yaparak (ve " Bu " ) " UserDefinedFunction " içinde. " Bu işlevi "Katı Olmayan Modda" çağırmak aşağıdakilerle sonuçlanacaktır

    UserDefinedFunction() // displays [object Window]  as it automatically gets invoked as window.UserDefinedFunction()

    "Sıkı Modu", Çağrı / doğrudan aracılığıyla işlevini çağırma olarak "UserDefinedFunction ()" olacak "DEĞİL" otomatik olarak o çağırmak / call "window.UserDefinedFunction ()" .Hence "geçerli nesne" (ve değeri "bu" ) içinde "UserDefinedFunction" tanımsız olacaktır . Bu işlevi "Sıkı Mod" a çağırmak aşağıdakilerle sonuçlanır:

    UserDefinedFunction() // displays undefined

    Ancak, pencere nesnesi kullanılarak açıkça çağrılması aşağıdakilerle sonuçlanır:

    window.UserDefinedFunction() // "always displays [object Window]   irrespective of mode."

    Başka bir örneğe bakalım. Lütfen aşağıdaki koda bakın

     function UserDefinedFunction()
        {
            alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
        }
    
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
          }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    o1.f() // Shall display 1,2,undefined,undefined
    o2.f() // Shall display undefined,undefined,3,4

    Yukarıdaki örnekte, "UserDefinedFunction" o1 aracılığıyla çağrıldığında , "this" in o1 değerini ve "a" ve "b" özelliklerinin değerini görüntülediğini görüyoruz . Değeri "c" ve "d" olarak gösterilen tanımlanmamış olarak o1 bu özellikleri tanımlamaz

    Benzer şekilde "UserDefinedFunction" ile başlatıldığı o2 , "Bu" değerini alır o2 ve özellikleri değerini "C" ve "D" arasında displayed.The değerini almak , "a" ve "b" olarak gösterildi tanımlanmamış olarak o2 yapar bu özellikleri tanımlamaz.

  3. İç Dolaylı "Sınırsız İşlev" içinde functionName.call ve functionName.apply aracılığıyla çağrı yapın :

    Bir zaman "bağlanmamış işlev" ile adlandırılır functionName.call veya functionName.apply , "geçerli nesne" (ve böylece değerini , "Bu" ) değerine ayarlanır , "Bu" iletilen parametre (ilk parametre) çağrı / uygula . Aşağıdaki kod aynı şeyi gösterir.

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
                a:1,
                b:2,
                f:UserDefinedFunction
           }
    var o2={
                c:3,
                d:4,
                f:UserDefinedFunction
           }
    
    UserDefinedFunction.call(o1) // Shall display 1,2,undefined,undefined
    UserDefinedFunction.apply(o1) // Shall display 1,2,undefined,undefined
    
    UserDefinedFunction.call(o2) // Shall display undefined,undefined,3,4
    UserDefinedFunction.apply(o2) // Shall display undefined,undefined,3,4
    
    o1.f.call(o2) // Shall display undefined,undefined,3,4
    o1.f.apply(o2) // Shall display undefined,undefined,3,4
    
    o2.f.call(o1) // Shall display 1,2,undefined,undefined
    o2.f.apply(o1) // Shall display 1,2,undefined,undefined

    Yukarıdaki kod, herhangi bir "NON Bound Fonksiyonu" için "bu" değerin çağrı / uygulama yoluyla değiştirilebileceğini açıkça göstermektedir . Ayrıca, "this" parametresi çağrı / uygulamaya açıkça geçirilmezse , "geçerli nesne" (ve bu nedenle "this" değeri) Katı olmayan modda "pencere" ve katı modda "tanımsız" olarak ayarlanır .

  4. "Bağlı Fonksiyon" Çağrısının içinde (yani functionName.bind çağrılarak bağlanan bir fonksiyon ):

    Bağlı işlev, "bu" değeri sabit olan bir işlevdir . Aşağıdaki kod , bağlı işlev durumunda "bu" nasıl çalıştığını gösterdi

    function UserDefinedFunction()
    {
        alert(this.a + ","  + this.b + ","  + this.c  + ","  + this.d)
    }
    var o1={
              a:1,
              b:2,
              f:UserDefinedFunction,
              bf:null
           }
    var o2={
               c:3,
               d:4,
               f:UserDefinedFunction,
               bf:null
            }
    
    var bound1=UserDefinedFunction.bind(o1); // permanantly fixes "this" value of function "bound1" to Object o1
    bound1() // Shall display 1,2,undefined,undefined
    
    var bound2=UserDefinedFunction.bind(o2); // permanantly fixes "this" value of function "bound2" to Object o2
    bound2() // Shall display undefined,undefined,3,4
    
    var bound3=o1.f.bind(o2); // permanantly fixes "this" value of function "bound3" to Object o2
    bound3() // Shall display undefined,undefined,3,4
    
    var bound4=o2.f.bind(o1); // permanantly fixes "this" value of function "bound4" to Object o1
    bound4() // Shall display 1,2,undefined,undefined
    
    o1.bf=UserDefinedFunction.bind(o2) // permanantly fixes "this" value of function "o1.bf" to Object o2
    o1.bf() // Shall display undefined,undefined,3,4
    
    o2.bf=UserDefinedFunction.bind(o1) // permanantly fixes "this" value of function "o2.bf" to Object o1
    o2.bf() // Shall display 1,2,undefined,undefined
    
    bound1.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    
    bound1.apply(o2) // Shall still display 1,2,undefined,undefined. "apply" cannot alter the value of "this" for bound function
    
    o2.bf.call(o2) // Shall still display 1,2,undefined,undefined. "call" cannot alter the value of "this" for bound function
    o2.bf.apply(o2) // Shall still display 1,2,undefined,undefined."apply" cannot alter the value of "this" for bound function

    Yukarıdaki kodda verildiği gibi, herhangi bir "Bağlı Fonksiyon" için "bu" değer çağrı / uygulama yoluyla değiştirilemez . Ayrıca, "this" parametresi bağlamaya açık bir şekilde geçirilmezse, "current object" (ve dolayısıyla "this" değeri ) Kesin olmayan modda "window" ve katı modda "undefined" olarak ayarlanır . Bir şey daha. Zaten bağlı bir işlevin bağlanması "this" değerinin değerini değiştirmez . İlk bağlama fonksiyonu tarafından ayarlanan değer olarak ayarlanmış olarak kalır.

  5. "Yeni" ile Nesne Oluşturma :

    Bir yapıcı işlevinin içinde, "geçerli nesne" (ve dolayısıyla "bu" değeri ) , işlevin bağlama durumundan bağımsız olarak şu anda "yeni" aracılığıyla oluşturulan nesneyi ifade eder. Ancak yapıcı bağlı bir işlevse, bağlı işlev için ayarlandığı gibi önceden tanımlanmış bağımsız değişkenler kümesi ile çağrılır.

  6. Dahili Satır İçi DOM olay işleyicisi :

    Lütfen aşağıdaki HTML Snippet'ine bakın

    <button onclick='this.style.color=white'>Hello World</button>
    <div style='width:100px;height:100px;' onclick='OnDivClick(event,this)'>Hello World</div>

    "Bu" Yukarıdaki örnekler sırasıyla "düğmesi" eleman ve "div" öğesine referans içinde.

    İlk örnekte, düğmenin yazı tipi rengi tıklatıldığında beyaz olarak ayarlanmalıdır.

    İkinci örnekte, "div" öğesi tıklatıldığında , ikinci parametresi, tıklanan div öğesine başvuruda bulunan OnDivClick işlevini çağırır . Ancak, OnDivClick içindeki "this" değeri , tıklanan div öğesine DEĞİLDİR . Sanki kurulacaktır "pencere nesnesinin" veya "tanımsız" in Olmayan sıkı ve sıkı Modları (eğer sırasıyla OnDivClick bir olan bağlanmamış fonksiyonu bir önceden tanımlanmış Bound değere) ya da sette (eğer OnDivClick bir olduğunu bağlı fonksiyon )

Aşağıda makalenin tamamı özetlenmektedir

  1. Genel Bağlamda "bu" her zaman "pencere" nesnesini ifade eder

  2. Bir işlev çağrıldığında, bir nesne bağlamında ( "geçerli nesne" ) çağrılır . Eğer geçerli nesne açıkça sağlanmaz, şimdiki nesne ise "pencere nesnesi" in OLMAYAN Sıkı Modu ve "tanımsız" varsayılan olarak sıkı modda.

  3. Sınırsız bir fonksiyon içindeki "this" değeri , fonksiyonun çağrıldığı bağlamda nesneye yapılan referanstır ( "geçerli nesne" )

  4. Sınırsız bir fonksiyon içindeki "this" değeri, çağrılarak ve fonksiyonun yöntemlerini uygulayarak geçersiz kılınabilir .

  5. " This " değeri bir Bound işlevi için sabittir ve işlevin çağrı ve uygulama yöntemleriyle geçersiz kılınamaz .

  6. Bağlama ve zaten bağlı olan fonksiyon "this" değerini değiştirmez. İlk bağlama fonksiyonu tarafından ayarlanan değer olarak ayarlanmış olarak kalır.

  7. Bir kurucu içindeki "this" değeri yaratılan ve başlatılan nesnedir

  8. Satır içi DOM olay işleyicisi içindeki "this" değeri, olay işleyicisinin verildiği öğeye başvurur.


9

Muhtemelen en ayrıntılı ve kapsamlı makale thisşöyledir:

JavaScript'te 'this' anahtar kelimesinin nazik açıklaması

Buradaki fikir this, işlev çağırma türlerinin thisdeğer belirlemede büyük önem taşıdığını anlamaktır .


Sıkıntılar belirlenmesi sahip olduğunda this, yok kendinize sorun:

Nereden thisalınır ?

ama do kendinize sorun:

İşlev nasıl başlatılır ?

Bir ok işlevi için (özel bağlam şeffaflığı örneği) kendinize şunları sorun:

thisOk işlevinin tanımlandığı yerde hangi değer vardır ?

Bu zihniyet, uğraşırken doğrudur thisve sizi baş ağrısından kurtaracaktır.


Blogunuza bağlantı vermenin yanı sıra, bu soruları sormanın birisinin thisanahtar kelimeyi anlamasına nasıl yardımcı olabileceği konusunda biraz daha derinlemesine araştırma yapabilirsiniz ?
Magnus Lind Oxlund

7

Bu gördüğüm en iyi açıklama JavaScripts anlayın bu Clarity ile

Bu başvuru her zaman anlamına gelir (ve değerini içerir) küresel kapsamı bir fonksiyonu dışında da kullanılabilir, ancak, bir nesne bir tekil nesne ve genellikle bir fonksiyonu ya da bir usul içinde kullanılmaktadır. Sıkı modu kullandığımızda, bunun global işlevlerde ve herhangi bir nesneye bağlı olmayan anonim işlevlerde tanımsız değerini tuttuğunu unutmayın.

Dört Senaryolar vardır bu kafa karıştırıcı olabilir:

  1. Biz (kullanan bir yöntemi başarılı olduğunda , bu , bağımsız değişken olarak) bir geri arama fonksiyonu olarak kullanılır.
  2. Bir iç işlev (kapak) kullandığımızda. Kapatmaların bu anahtar sözcüğü kullanarak dış işlevin bu değişkenine erişemediğine dikkat etmek önemlidir, çünkü bu değişkene iç işlevler tarafından değil, yalnızca işlevin kendisi tarafından erişilebilir.
  3. Dayanan bir yöntem zaman bu durumda bağlamlarda genelinde bir değişkene, atanan bu başlangıçta öngörülenden daha referanslar başka nesne.
  4. Kullanırken bu bağlama ile birlikte uygulamak ve arama yöntemleri.

Çok yararlı olduğunu düşündüğüm kod örnekleri, açıklamalar ve çözümler veriyor.


6

Sözde terimlerle ifade etmek gerekirse, birçok dersin 'this' anahtar sözcüğünü öğretme şekli, bir sınıf veya nesne kurucu tarafından başlatılan bir nesne gibidir. Bir sınıftan her yeni nesne oluşturulduğunda, başlık altında yerel bir 'bu' nesnenin örneğinin oluşturulduğunu ve döndürüldüğünü hayal edin. Böyle öğretildiğini hatırlıyorum:

function Car(make, model, year) {
var this = {}; // under the hood, so to speak
this.make = make;
this.model = model;
this.year = year;
return this; // under the hood
}

var mycar = new Car('Eagle', 'Talon TSi', 1993);
// ========= under the hood
var this = {};
this.make = 'Eagle';
this.model = 'Talon TSi';
this.year = 1993;
return this;

5

thisJavaScript'te yanlış anlaşılan kavramlardan biridir, çünkü bir yerden bir yere biraz farklı davranır. Basitçe, şu anda yürütmekte olduğumuz işlevin "sahibine"this atıfta bulunur .

thisbirlikte çalıştığımız mevcut nesnenin (yürütme bağlamı olarak da bilinir) elde edilmesine yardımcı olur. Geçerli işlevin hangi nesnede yürütüldüğünü anlarsanız, akımın ne thisolduğunu kolayca anlayabilirsiniz

var val = "window.val"

var obj = {
    val: "obj.val",
    innerMethod: function () {
        var val = "obj.val.inner",
            func = function () {
                var self = this;
                return self.val;
            };

        return func;
    },
    outerMethod: function(){
        return this.val;
    }
};

//This actually gets executed inside window object 
console.log(obj.innerMethod()()); //returns window.val

//Breakdown in to 2 lines explains this in detail
var _inn = obj.innerMethod();
console.log(_inn()); //returns window.val

console.log(obj.outerMethod()); //returns obj.val

Yukarıda aynı isimde 'val' ile 3 değişken oluşturuyoruz. Biri küresel bağlamda, biri objenin içinde diğeri ise objektifin içinde. JavaScript, kapsam zincirini yerel global hale getirerek belirli bir bağlamdaki tanımlayıcıları çözer.


thisFarklılaştırılabilecek birkaç yer

Bir nesnenin yöntemini çağırma

var status = 1;
var helper = {
    status : 2,
    getStatus: function () {
        return this.status;
    }
};

var theStatus1 = helper.getStatus(); //line1
console.log(theStatus1); //2

var theStatus2 = helper.getStatus;
console.log(theStatus2()); //1

Satırı1 yürütüldüğünde, JavaScript ayarı, işlev çağrısı için yürütme bağlamı (AK) kurar thisiçin son önce gelen ne olursa olsun tarafından başvurulan nesne "" . bu yüzden son satırda a()bunun küresel bağlamda yürütüldüğünü anlayabilirsiniz window.

Yapıcı ile

this yaratılan nesneye atıfta bulunmak için kullanılabilir

function Person(name){
    this.personName = name;
    this.sayHello = function(){
        return "Hello " + this.personName;
    }
}

var person1 = new Person('Scott');
console.log(person1.sayHello()); //Hello Scott

var person2 = new Person('Hugh');
var sayHelloP2 = person2.sayHello;
console.log(sayHelloP2()); //Hello undefined

Yeni Person()yürütüldüğünde, tamamen yeni bir nesne oluşturulur. Personçağrılır ve thisyeni nesneye başvurmak üzere ayarlanır.

İşlev çağrısı

function testFunc() {
    this.name = "Name";
    this.myCustomAttribute = "Custom Attribute";
    return this;
}

var whatIsThis = testFunc();
console.log(whatIsThis); //window

var whatIsThis2 = new testFunc();
console.log(whatIsThis2);  //testFunc() / object

console.log(window.myCustomAttribute); //Custom Attribute 

newAnahtar kelimeyi kaçırırsak whatIsThis, bulabileceği en global içeriğe başvurur ( window)

Olay işleyicileriyle

Olay işleyici satır içi ise, thisgenel nesneye başvurur

<script type="application/javascript">
    function click_handler() {
        alert(this); // alerts the window object
    }
</script>

<button id='thebutton' onclick='click_handler()'>Click me!</button>

JavaScript aracılığıyla olay işleyici eklerken, etkinliği thisoluşturan DOM öğesine başvurur.



5

"This" değeri, işlevin yürütüldüğü "bağlam" a bağlıdır. Bağlam herhangi bir nesne veya genel nesne, yani pencere olabilir.

Yani "bu" anlambilimi, geleneksel OOP dillerinden farklıdır. Ve sorunlara neden olur: 1. bir işlev başka bir değişkene geçirildiğinde (büyük olasılıkla geri arama); ve 2. bir sınıfın üye yönteminden bir kapatma çağrıldığında.

Her iki durumda da, bu pencere olarak ayarlanır.


3

Bu kim yardımcı olabilir? (Javascript'teki 'bu' kelimesinin çoğu karışıklığı, genellikle nesnenize değil, mevcut yürütme kapsamına bağlı olmasından kaynaklanmaktadır - bu tam olarak nasıl çalışmayabilir, ancak her zaman bana öyle geliyor - tam bir açıklama için makaleye bakın)


1
" Mevcut yürütme bağlamıyla " bağlantılı olduğunu söylemek daha iyi olur . ES6 (taslak) hariç, dış işlev bağlamında çözüldüğü ok işlevleriyle değişir.
RobG

3

Bu anahtar kelime hakkında biraz bilgi

Hadi günlüğü thisartık kod olmadan küresel kapsamda konsola kelime ama

console.log(this)

In Client / Tarayıcı this anahtar küresel bir nesnedirwindow

console.log(this === window) // true

ve

In Sunucu / Düğüm / JavaScript çalışma zamanı this anahtar kelimedir küresel nesne demodule.exports

console.log(this === module.exports) // true
console.log(this === exports) // true

Unutmayın exports, sadece bir referanstırmodule.exports


1

Scope için bu kullanım aynen böyle

  <script type="text/javascript" language="javascript">
$('#tbleName tbody tr').each(function{
var txt='';
txt += $(this).find("td").eq(0).text();
\\same as above but synatx different
var txt1='';
 txt1+=$('#tbleName tbody tr').eq(0).text();
alert(txt1)
});
</script>

Yukarıdaki örnekte txt1 ve txt değeri aynıdır $ (this) = $ ('# tbleName tbody tr') Aynı


1

Farklı bir yaklaşımım var thisYararlı olduğunu umduğum diğer cevaplardan .

JavaScript'e bakmanın bir yolu, bir işlev 1'i çağırmanın yalnızca 1 yolunun olduğunu görmektir . Bu

functionObject.call(objectForThis, arg0, arg1, arg2, ...);

Her zaman bir miktar değer verilir objectForThis.

Diğer her şey sözdizimsel şeker functionObject.call

Böylece, diğer her şey nasıl tercüme edildiğiyle açıklanabilir functionObject.call.

Bir işlevi çağırırsanız this, tarayıcıda pencere olan "global nesne"

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

foo();  // this is the window object

Başka bir deyişle,

foo();

etkili bir şekilde çevrildi

foo.call(window);

Sıkı mod kullanırsanız this,undefined

'use strict';

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

foo();  // this is the window object

bunun anlamı

Başka bir deyişle,

foo();

etkili bir şekilde çevrildi

foo.call(undefined);

JavaScript'te +ve -ve gibi operatörler vardır *. Ayrıca nokta operatörü var.

.Sağda bir fonksiyonu, sol bir nesne ile birlikte kullanıldığında kullanıcı etkili bir şekilde "geçiş nesnesi olarak anlamıthis işlevine.

Misal

const bar = {
  name: 'bar',
  foo() { 
    console.log(this); 
  },
};

bar.foo();  // this is bar

Başka bir deyişle bar.foo()çevirirconst temp = bar.foo; temp.call(bar);

İşlevin nasıl oluşturulduğu önemli değildir (çoğunlukla ...). Bunların hepsi aynı sonuçları verecektir

const bar = {
  name: 'bar',
  fn1() { console.log(this); },
  fn2: function() { console.log(this); },
  fn3: otherFunction,
};

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

bar.fn1();  // this is bar
bar.fn2();  // this is bar
bar.fn3();  // this is bar

Yine bunların hepsi sadece sözdizimsel şeker

{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }

Bir diğer kırışıklık da prototip zinciridir. a.bJavaScript kullandığınızda, ilk olarak doğrudan amülk için başvurulan nesneye bakar b. Eğer bnesne üzerinde bulunmazsa daha sonra JavaScript bulmak için nesnenin prototip görüneceğini b.

Bir nesnenin prototipini tanımlamanın çeşitli yolları vardır, 2019'da en yaygın olanı classanahtar kelimedir. thisGerçi amaçlar için önemli değil. Önemli olan nesnede göründüğü olmasıdır aözellik için bo özelliği bulursa beğer nesne üzerinde veya 's prototip zincirinde bbir fonksiyonu olduğu kadar uçları daha sonra aynı kurallar yukarıda kavrayış. İşlev bbaşvuruları callyöntem kullanılarak çağrılır ve abu cevabın üst kısmında gösterildiği gibi objectForThis olarak iletilir.

Şimdi. thisBaşka bir işlevi çağırmadan önce açıkça ayarlanan bir işlevi yaptığımızı ve sonra .(nokta) operatörü ile çağırdığımızı düşünelim

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

function bar() {
  const objectForThis = {name: 'moo'}
  foo.call(objectForThis);  // explicitly passing objectForThis
}

const obj = {
  bar,
};

obj.bar();  

Kullanımına çevirisini takiben call, obj.bar()olur const temp = obj.bar; temp.call(obj);. Biz girdiğinizde barişlevini dediğimiz foobiz foo varmak yüzden zaman ama biz açıkça objectForThis için başka bir nesneye geçirilenthis bu iç nesnedir.

Bu, hem ne bindve =>işlevleri etkin bir yap. Daha sözdizimsel şekerdir. Bunlar, tam olarak baryukarıdaki gibi this, belirtilen herhangi bir işlevi çağırmadan önce açıkça ayarlanan yeni bir görünmez işlev oluştururlar . Bağlama durumunda, thisgeçtiğiniz her şeye ayarlanır bind.

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

const bar = foo.bind({name: 'moo'});

// bind created a new invisible function that calls foo with the bound object.

bar();  

// the objectForThis we are passing to bar here is ignored because
// the invisible function that bind created will call foo with with
// the object we bound above

bar.call({name: 'other'});

Eğer functionObject.bindböyle bir şey olmasaydı kendimizi böyle yapabiliriz

function bind(fn, objectForThis) {
  return function(...args) {
    return fn.call(objectForthis, ...args);
  };
}

ve sonra böyle diyebiliriz

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

const bar = bind(foo, {name:'abc'});

Ok fonksiyonları, =>operatör bağlama için sözdizimsel şekerdir

const a = () => {console.log(this)};

aynıdır

const tempFn = function() {console.log(this)}; 
const a = tempFn.bind(this);

Tıpkı bind, olduğu gibi , verilen işlevi sınırlanmış bir değerle çağıran, objectForThisancak bindbağlanacak nesnenin aksine yeni bir görünmez işlev oluşturulur . Ne thiszaman olursa olsun=>Operatör kullanıldığında .

Yani, yukarıdaki kurallar gibi

const a = () => { console.log(this); }  // this is the global object
'use strict';
const a = () => { console.log(this); }  // this is undefined
function foo() {
  return () => { console.log(this); }
}

const obj = {
  foo,
};
const b = obj.foo();
b();

obj.foo()çevirir const temp = obj.foo; temp.call(obj);ok operatörü içine anlamına gelir foobağlayacaktır objyeni görünmez işlevine ve atanan yeni görünmez işlev döndürecek b. b()her zaman olduğu gibi b.call(window)veya oluşturulan b.call(undefined)yeni görünmez işlevi çağırır foo. Bu görünmez işlev, kendisine thisgeçirileni yok sayar objve ok işlevine objectForThis` olarak geçer .

Yukarıdaki kod,

function foo() {
  function tempFn() {
    console.log(this);
  }
  return tempFn.bind(this);
}

const obj = {
  foo,
};
const b = obj.foo();
b.call(window or undefined if strict mode);

1apply , şuna benzer başka bir işlevdir:call

functionName.apply(objectForThis, arrayOfArgs);

Ancak ES6'dan itibaren kavramsal olarak bunu

functionName.call(objectForThis, ...arrayOfArgs);

0

Özet thisJavascript:

  • Değeri thisDİR tarafından belirlenen işlev değil çağrılır nasıl oluşturulduğu yerde!
  • Genellikle değeri thisnoktanın solundaki Nesne tarafından belirlenir. ( windowküresel alanda)
  • Olay dinleyicilerinde değeri this , etkinliğin çağrıldığı DOM öğesine karşılık gelir.
  • Fonksiyonunda newanahtar kelimeyle çağrıldığında , değeri thisyeni oluşturulan nesneyi ifade eder
  • Sen değerini manipüle edebilir thisfonksiyonları ile: call, apply,bind

Misal:

let object = {
  prop1: function () {console.log(this);}
}

object.prop1();   // object is left of the dot, thus this is object

const myFunction = object.prop1 // We store the function in the variable myFunction

myFunction(); // Here we are in the global space
              // myFunction is a property on the global object
              // Therefore it logs the window object
              
             

Örnek olay dinleyicileri:

document.querySelector('.foo').addEventListener('click', function () {
  console.log(this);   // This refers to the DOM element the eventListener was invoked from
})


document.querySelector('.foo').addEventListener('click', () => {
  console.log(this);  // Tip, es6 arrow function don't have their own binding to the this v
})                    // Therefore this will log the global object
.foo:hover {
  color: red;
  cursor: pointer;
}
<div class="foo">click me</div>

Örnek kurucu:

function Person (name) {
  this.name = name;
}

const me = new Person('Willem');
// When using the new keyword the this in the constructor function will refer to the newly created object

console.log(me.name); 
// Therefore, the name property was placed on the object created with new keyword.


0

"Bunu" doğru anlamak için, bağlamı, kapsamı ve aralarındaki farkı anlamak gerekir.

Kapsam : Javascript kapsamı değişkenlerin görünürlüğü ile ilgilidir, kapsam fonksiyonun kullanılmasıyla elde edilir. (Kapsam hakkında daha fazla bilgi edinin)

Bağlam : Bağlam nesnelerle ilişkilidir. Bir işlevin ait olduğu nesneyi ifade eder. JavaScript “this” anahtar sözcüğünü kullandığınızda, işlevin ait olduğu nesneyi ifade eder. Örneğin, bir işlevin içinde, “this.accoutNumber” dediğinizde, bu işlevin ait olduğu nesneye ait olan “accoutNumber” özelliğine başvuruyorsunuz.

“MyObj” nesnesinin “getMyName” adlı bir yöntemi varsa, “getMyName” içinde “this” JavaScript anahtar kelimesi kullanıldığında, “myObj” anlamına gelir. “GetMyName” işlevi genel kapsamda yürütüldüyse, “this” pencere nesnesini ifade eder (katı mod hariç).

Şimdi bazı örneklere bakalım:

    <script>
        console.log('What is this: '+this);
        console.log(this);
    </script>

Tarayıcı çıktısında yukarıdaki kod çalıştırma: resim açıklamasını buraya girin

Pencere nesnesinin bağlamının içinde olduğunuz çıktıya göre, pencere prototipinin Nesneye başvurduğu da görülebilir.

Şimdi bir fonksiyonun içinde deneyelim:

    <script>
        function myFunc(){
            console.log('What is this: '+this);
            console.log(this);
        }
        myFunc();
    </script>

Çıktı:

resim açıklamasını buraya girin Çıktı aynıdır, çünkü global kapsamda 'bu' değişkeni ve fonksiyonel kapsamda oturum açtık, bağlamı değiştirmedik. Her iki durumda da, dul nesnesiyle ilgili bağlam aynıydı .

Şimdi kendi neslimizi yaratalım. Javascript'te, birçok yönden bir nesne oluşturabilirsiniz.

 <script>
        var firstName = "Nora";
        var lastName = "Zaman";
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printNameGetContext:function(){
                console.log(firstName + " "+lastName);
                console.log(this.firstName +" "+this.lastName);
                return this;
            }
        }

      var context = myObj.printNameGetContext();
      console.log(context);
    </script>

Çıktı: resim açıklamasını buraya girin

Yukarıdaki örnekten, 'this' anahtar kelimesinin myObj ile ilgili yeni bir bağlama atıfta bulunduğunu ve myObject öğesinin de Object için prototip zincirine sahip olduğunu bulduk.

Hadi başka bir örnek atalım:

<body>
    <button class="btn">Click Me</button>
    <script>
        function printMe(){
            //Terminal2: this function declared inside window context so this function belongs to the window object.
            console.log(this);
        }
        document.querySelector('.btn').addEventListener('click', function(){
            //Terminal1: button context, this callback function belongs to DOM element 
            console.log(this);
            printMe();
        })
    </script>
</body>

Çıktı: Doğru mu? (yorumları oku) resim açıklamasını buraya girin

Yukarıdaki örneği anlamakta güçlük çekiyorsanız, kendi geri aramamızı deneyelim;

<script>
        var myObj = {
            firstName:"Lord",
            lastName:'Baron',
            printName:function(callback1, callback2){
                //Attaching callback1 with this myObj context
                this.callback1 = callback1;
                this.callback1(this.firstName +" "+this.lastName)
                //We did not attached callback2 with myObj so, it's reamin with window context by default
                callback2();
                /*
                 //test bellow codes
                 this.callback2 = callback2;
                 this.callback2();
                */
            }
        }
        var callback2 = function (){
            console.log(this);
        }
        myObj.printName(function(data){
            console.log(data);
            console.log(this);
        }, callback2);
    </script>

çıktı: resim açıklamasını buraya girin

Şimdi Kapsam, Benlik, IIFE ve BU'nun nasıl davrandığını anlayalım

       var color = 'red'; // property of window
       var obj = {
           color:'blue', // property of window
           printColor: function(){ // property of obj, attached with obj
               var self = this;
               console.log('In printColor -- this.color: '+this.color);
               console.log('In printColor -- self.color: '+self.color);
               (function(){ // decleard inside of printColor but not property of object, it will executed on window context.
                    console.log(this)
                    console.log('In IIFE -- this.color: '+this.color);
                    console.log('In IIFE -- self.color: '+self.color); 
               })();

               function nestedFunc(){// decleard inside of printColor but not property of object, it will executed on window context.
                    console.log('nested fun -- this.color: '+this.color);
                    console.log('nested fun -- self.color: '+self.color);
               }

               nestedFunc(); // executed on window context
               return nestedFunc;
           }
       };

       obj.printColor()(); // returned function executed on window context
   </script> 

Çıktı oldukça harika değil mi? resim açıklamasını buraya girin


-1

Basit cevap:

"this" anahtar kelimesi her zaman çağırma bağlamına bağlıdır. Bunlar aşağıda belirtilmiştir.

  1. FONKSİYON YENİ ANAHTAR KELİME İLE ÇAĞRI

    İşlev NEW anahtar sözcüğü ile çağrılırsa, THIS yeni oluşturulan nesneye bağlanır.

    function Car(){
      this.name="BMW";
    }
    const myCar=new Car();
    myCar.name; // output "BMW"

    Yukarıda bu 'myCar' nesnesine bağlı olacaktır

  2. ÇAĞRI VE UYGULAMA YÖNTEMLERİ KULLANILAN FONKSİYON ÇAĞIRILIR.

    Bu durumda, BU, işleve açıkça geçirilen nesneye bağlanır.

    var obj1={"name":"bond"};
    function printMessage(msg){
        return msg+" "+this.name;
    }
    const message=printMessage.call(obj1,"my name is ");
    console.log(message); //HERE THIS WILL BE BOUND TO obj1 WHICH WE PASSED EXPLICITLY. SAME FOR APPLY METHOD ALSO.
  3. FONKSİYON KESİNLİKLE NESNE İLE ÇAĞIRILIRSA, BU NESNEYE AİT OLACAK

    var obj1={
       "name":"bond",
        getName: function () {
                    return this.name;
                 }
    };
    const newname=obj1.getName();
    console.log(newname); //HERE THIS WILL BE BOUND TO obj1(WHITCHEVER OBJECT IS MENTIONED BEFORE THE DOT THIS WILL BE BOUND TO THAT)
  4. FONKSİYON HERHANGİ BİR BAĞLAMSIZ ÇAĞRILIRKEN BU KÜRESEL NESNE BAĞLANACAKTIR

    const util = {
       name: 'Utility',
       getName: function () {
                    return this.name;
    };
    
    const getName=util.getName;
    const newName=getName();
    console.log(newName); // IF THIS EXECUTED IN BROWSER THIS WILL BE  BOUND TO WINDOW OBJECT. IF THIS EXECUTED IN SERVER THIS WILL BE BOUND TO GLOBAL OBJECT
  5. ÇOK MODDA BU TANIMLANMAYACAKTIR

    function setName(name){
        "use strict"
        return this.name;
    }
    setName(); //WILL BE ERROR SAYING name IS UNDEFINED. 
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.