JavaScript'te bu ve ben arasındaki fark


118

Herkes farkında thisjavascript ama örnekleri de vardır selfvahşi karşılaşılan gibi, burada

Peki, JavaScript arasındaki thisve selfiçindeki fark nedir?



8
@dystroy: Bir tane var: window.self( === window). OP muhtemelen önemsiz bir değişken adı anlamına gelse de…
Bergi

2
@dystroy: Aslında bunu gerçekten kastetebileceğini düşünmemiştim, ama aslında küresel anlamda (ve bir tarayıcı ortamında) this === selfdoğru :-)
Bergi 13

2
Kenara sübjektif: örtüşme thisiçin self's ortak asenkron programlama sonucunda, geri arama yuvalama birçok (iyi, birden fazla kötü yeterlidir) düzeyleri ile koduna sahip ne zaman büyük bir uygulamadır günümüzde değil. Bunun yerine daha açıklayıcı bir ad kullanın. Nesnel olarak konuşmak gerekirse, adın thiskendisi hiçbir bilgi taşımaz ve yalnızca kötü olmayan bir ad seçimidir çünkü bir sınıf tanımının sözcüksel bağlamı onu nitelendirir.
millimoose

2
bu geçerli ve faydalı bir sorudur, tekrar açılmalıdır
danza

Yanıtlar:


127

Başka yerde set sürece, değeri selfolduğu window, çünkü JavaScript herhangi özelliğine erişmenizi sağlar xve windowbasit bir şekilde xyerine, window.x. Bu nedenle, selfgerçekten window.selffarklı olan this.

window.self === window; // true

Genel kapsamda yürütülen ve katı modda olmayan bir işlev kullanıyorsanız, thisvarsayılan olarak windowve dolayısıyla

function foo() {
    console.log(
        window.self === window, // is self window?
        window.self === this,   // is self this?
        this === window         // is this window?
    );
}
foo(); // true true true

Bir işlevi farklı bir bağlamda kullanıyorsanız, thiso bağlama başvuracak, ancak selfyine de olacaktır window.

// invoke foo with context {}
foo.call({}); // true false false

Burada W3C 2006 çalışma taslağında Pencere Nesnesi içinwindow.self tanımları bulabilirsiniz .


34
Bütünlüğü sağlamak için, selfcam erişilebilir olduğunda (WebWorker bağlamında yararlı olan developer.mozilla.org/en-US/docs/Web/Guide/Performance/... ). selfBunun yerine kullanmak window, global nesneye taşınabilir bir şekilde erişmenizi sağlar.
lqc

24

İnsanlar bununla hizmet çalışanları bağlamında karşılaşabileceğinden buna küçük bir ekleme, bu durumda biraz farklı bir anlama gelir.

Bunu bir servis çalışanı modülünde görebilirsiniz:

self.addEventListener('install', function(e) {
  console.log('[ServiceWorker] Install');
});

Burada self , WorkerGlobalScope'a atıfta bulunur ve bu, olay dinleyicilerini ayarlamak için standart yöntemdir.

Gönderen Mozilla docs :

Self'i kullanarak, genel kapsama yalnızca bir pencere bağlamında değil (self, window.self olarak çözülür) aynı zamanda bir işçi bağlamında da (self daha sonra WorkerGlobalScope.self'e çözümlenir) çalışacak bir şekilde başvurabilirsiniz.


Teşekkürler ! Cevabı arıyordum :)
agpt

23

Burada geç kalmama rağmen, thisdaha fazla anlamamıza yardımcı olabilecek bir örnekle karşılaştım :

var myObject = {
 foo: "bar",
 func: function() {
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    (function() {
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    }());
  }
};
myObject.func();

O / P

outer func:  this.foo = bar
outer func:  self.foo = bar
inner func:  this.foo = undefined
inner func:  self.foo = bar

ECMA 5'ten önce this, iç işlevde genel pencere nesnesine atıfta bulunulacaktır; oysa ECMA 5 itibariyle this, iç işlevde tanımsız olacaktır.


bu her zaman kendi bağlamında tanımlanır. Tanımsız olan this.foo. Bu çok büyük bir fark ve ECMA 5'ten önce var olduğundan bahsettiğiniz davranışı elde etmek için, ok fonksiyonları kullanılabilir veya kendi belirlediğiniz gibi, kendi iç fonksiyonun dışında bu şekilde atama ve bunun yerine kendini içeride kullanma, daha açık olan yol ok fonksiyonudur. .
Dejazmach

2

ECMA 5 referansının açıklığa kavuşturulması gerekiyor.

ECMA-262 Edition 5 anlamına geldiğini varsayıyorum. ECMA-262'nin (diğer adıyla ECMAScript veya daha az doğru olarak Javascript) İnternet Tarayıcılarında uygulanan genel bir komut dosyası dili olduğu unutulmamalıdır . Sürüm 5.1 standardından:

Aşağıdaki adımlar, denetim F işlev nesnesinde bulunan işlev kodu için yürütme bağlamına girdiğinde, thisArg sağlanan bir çağırıcı ve argumentsList sağlayan bir çağırıcı tarafından gerçekleştirilir:

  1. İşlev kodu katı kodsa, ThisBinding'i thisArg olarak ayarlayın.
  2. ThisArg null veya undefined ise, ThisBinding'i genel nesneye ayarlayın.
  3. Aksi takdirde, Type (thisArg) Object değilse, ThisBinding'i ToObject (thisArg) olarak ayarlayın.
  4. Else ThisBinding'i thisArg olarak ayarlayın
  5. ... ("bu" hakkında değil)

"Global nesne" terimi, kapsam zincirinin tepesindeki nesneyi ifade eder. Tarayıcılar için bu "pencere" nesnesi olabilir, ancak bu bir uygulama seçeneğidir (Windows Komut Dosyası Ana Bilgisayarı görünmez bir genel nesneye sahiptir ancak katı modu yoktur, bu nedenle niteliksiz referanslar özelliklerine erişir ve genel "kendilik" yoktur). Ayrıca, "katı mod" açıkça etkinleştirilmelidir, aksi takdirde aktif değildir (standardın 14.1 bölümü). Bu nedenle, tanımlanmamış bir "bu", katı mod etkin olmayan "ECMA 5 "'teki genel nesneye (pencere) hala çözümlenecektir.

Yani sorunun cevabı şu:

"bu" her zaman işlevi çağıran nesneyi ifade eder. İşlev bir nesne tarafından çağrılmadıysa (yani bir yöntem çağrısı değil), "bu" (işleve iletildiği şekliyle) "tanımsız" dır. Bununla birlikte, katı modu KULLANMAZSA, global nesne olarak tanımlanmamış bir "bu" ayarlanır (yukarıdaki kural 2).

"ben" in özel bir sözdizimsel anlamı yoktur, sadece bir tanımlayıcıdır. Tarayıcılar window.self (yalnızca global pencere nesnesinin bir özelliği) = window tanımlama eğilimindedir. Bu, "kendilik" ifadesinin, "pencere" DEĞİL "öz" ile aynı olan niteliksiz referansların, kapsayıcı bir kapsam dahilinde yeniden tanımlanmasına neden olur (yukarıdaki "var self = this;" tarafından olduğu gibi. "Bunu" yeniden tanımlarken iyi şanslar.)

Yani yukarıdaki örneğin tam açıklaması şu şekildedir:

outer func:  this.foo = bar
// "this" refers to the invoking object "myObject"
outer func:  self.foo = bar
// "self" resolves to the variable in the local scope which has been set to "this" so it is also "myObject"
inner func:  this.foo = undefined
// "this" refers to the invoking object (none) and so is replaced by the global object (strict mode must be off). "window" has no foo property so its "value" is undefined.
inner func:  self.foo = bar
// self resolves to the variable in the enclosing scope which is still "myObject"

Örneğin ilginç bir varyasyonu, iç işleve bir referans döndürerek bir kapanış yaratır.

var myObject = {
 foo: "bar",
 func: function() {
    var self = this;
    console.log("outer func:  this.foo = " + this.foo);
    console.log("outer func:  self.foo = " + self.foo);
    return function() {
        console.log("inner func:  this.foo = " + this.foo);
        console.log("inner func:  self.foo = " + self.foo);
    };
  }
};
var yourObject = {
 foo: "blat",
 func: myObject.func() // function call not function object
};
console.log("----");
yourObject.func();

üreten

outer func:  this.foo = bar
outer func:  self.foo = bar
----
inner func:  this.foo = blat
inner func:  self.foo = bar

YourObject tarafından çağrılana kadar iç işlevin nasıl çağrılmadığına dikkat edin. Yani this.foo artık yourObject.foo'dur, ancak self hala kapsama alanındaki değişkene çözümlenir, bu değişken iç işlev nesnesi döndürüldüğünde (ve sonuçta sonuçta hala myObject'tir). Dolayısıyla, iç işlev içinde, "bu" iç işlevi çağıran nesneyi ifade ederken, "öz", iç işleve referans oluşturmak için dış işlevi çağıran nesneyi ifade eder.

Özetin özetini özetlemek gerekirse, "bu" dil standardı tarafından tanımlanır, "öz" onu tanımlayan kişi tarafından tanımlanır (çalışma zamanı uygulayıcısı veya son programlayıcı).


0

Nereden bahsettiğini görmek için genel kapsamdaki (tarayıcı ortamı) 'pencere', 'kendi' ve 'bu' konsol çıktılarının bazı kombinasyonlarını aşağıda bulun.

console.log( window ); // Window {…}
console.log( self );   // Window {…}
console.log( this );   // Window {…}

console.log( window.window ); // Window {…}
console.log( window.self );   // Window {…}
console.log( window.this );   // undefined  

console.log( self.self );     // Window {…}
console.log( self.window );   // Window {…}
console.log( self.this );     // undefined

console.log( this.this );     // undefined
console.log( this.window );   // Window {…}
console.log( this.self );     // Window {…}

console.log( window.window.window );    // Window {…}
console.log( self.self.self );          // Window {…}
console.log( window.self.window.self ); // Window {…}
console.log( self.window.self.window ); // Window {…}
console.log( this.this );               // 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.