Bagaimana cara kerja kata kunci "ini"?

1309

Saya perhatikan bahwa tampaknya tidak ada penjelasan yang jelas tentang apa thiskata kunci itu dan bagaimana kata kunci itu benar (dan salah) digunakan dalam JavaScript di situs Stack Overflow.

Saya telah menyaksikan beberapa perilaku yang sangat aneh dengannya dan gagal memahami mengapa hal itu terjadi.

Bagaimana cara thiskerjanya dan kapan harus digunakan?

Maxim Gershkovich
sumber
6
Saya menemukan ini ketika saya googled "this" quirksmode.org/js/this.html
Wai Wong
Beberapa pertanyaan terkait yang bermanfaat * jQuery / JavaScript "pointer" kebingungan * Dalam Javascript, mengapa operator "ini" tidak konsisten? dan langgan yang bagus di sini * ruang lingkup / konteks dalam javascript
Paul Dixon
2
Peter Michaux menganjurkan menentang penggunaan this peter.michaux.ca/articles/javascript-widgets-without-this
Marcel Korpel
1
Gambaran umum MDN tidak setengah buruk ... developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/…
dat
2
Penjelasan thiskata kunci yang menarik: rainsoft.io/gentle-explanation-of-this-in-javascript
Dmitri Pavlutin

Jawaban:

1350

Saya sarankan membaca Mike Barat 's artikel Ruang Lingkup dalam JavaScript ( cermin ) pertama. Ini adalah pengantar yang luar biasa, ramah untuk konsep thisdan rantai cakupan dalam JavaScript.

Setelah Anda mulai terbiasa this, aturan sebenarnya cukup sederhana. Standar ECMAScript 5.1 mendefinisikan this:

§11.1.1 Kata thiskunci

Kata thiskunci mengevaluasi nilai dari ThisBinding dari konteks eksekusi saat ini

Penjilidan ini adalah sesuatu yang dipertahankan oleh penerjemah JavaScript saat mengevaluasi kode JavaScript, seperti register CPU khusus yang menyimpan referensi ke suatu objek. Interpreter memperbarui ThisBinding kapan pun membangun konteks eksekusi dalam satu dari hanya tiga kasus yang berbeda:

1. Konteks eksekusi global awal

Ini adalah kasus untuk kode JavaScript yang dievaluasi di tingkat atas, misalnya ketika langsung di dalam <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>

Saat mengevaluasi kode dalam konteks eksekusi global awal, Penjilidan Ini diatur ke objek global, window( §10.4.1.1 ).

Memasukkan kode eval

  • ... dengan panggilan langsung ke eval() ThisBinding dibiarkan tidak berubah; ini adalah nilai yang sama dengan ThisBinding dari konteks eksekusi panggilan ( §10.4.2 (2) (a)).

  • ... jika tidak dengan panggilan langsung ke eval()
    ThisBinding diatur ke objek global seolah-olah mengeksekusi dalam konteks eksekusi global awal ( §10.4.2 (1)).

§15.1.2.1.1 mendefinisikan apa panggilan langsung eval()itu. Pada dasarnya, eval(...)adalah panggilan langsung sedangkan sesuatu seperti (0, eval)(...)atau var indirectEval = eval; indirectEval(...);merupakan panggilan tidak langsung eval(). Lihat jawaban chuckj untuk (1, eval) ('this') vs eval ('this') dalam JavaScript? dan ECMA-262-5 karya Dmitry Soshnikov secara rinci. Bab 2. Mode Ketat. ketika Anda mungkin menggunakan eval()panggilan tidak langsung .

Memasukkan kode fungsi

Ini terjadi ketika memanggil suatu fungsi. Jika fungsi dipanggil pada objek, seperti dalam obj.myMethod()atau yang setara obj["myMethod"](), maka Penjilidan Ini diatur ke objek ( objdalam contoh; §13.2.1 ). Dalam sebagian besar kasus lain, Penjilidan Ini diatur ke objek global ( §10.4.3 ).

Alasan untuk menulis "dalam kebanyakan kasus lain" adalah karena ada delapan fungsi built-in ECMAScript 5 yang memungkinkan ThisBinding untuk ditentukan dalam daftar argumen. Fungsi-fungsi khusus ini mengambil apa yang disebut thisArgdengan ThisBinding ketika memanggil fungsi ( §10.4.3 ).

Fungsi bawaan khusus ini adalah:

  • 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 ] )

Dalam hal Function.prototypefungsi, mereka dipanggil pada objek fungsi, tetapi daripada mengatur ThisBinding ke objek fungsi, ThisBinding diatur ke thisArg.

Dalam hal Array.prototypefungsi, yang diberikan callbackfndisebut dalam konteks eksekusi di mana ThisBinding diatur ke thisArgjika disediakan; jika tidak, ke objek global.

Itulah aturan untuk JavaScript biasa. Ketika Anda mulai menggunakan pustaka JavaScript (mis. JQuery), Anda mungkin menemukan bahwa fungsi pustaka tertentu memanipulasi nilai this. Pengembang pustaka JavaScript melakukan ini karena cenderung mendukung kasus penggunaan yang paling umum, dan pengguna perpustakaan biasanya menemukan perilaku ini lebih nyaman. Saat melewati fungsi panggilan balik yang merujuk thiske fungsi pustaka, Anda harus merujuk ke dokumentasi untuk jaminan apa pun tentang nilai dari thissaat fungsi dipanggil.

Jika Anda bertanya-tanya bagaimana perpustakaan JavaScript memanipulasi nilai this, perpustakaan hanya menggunakan salah satu fungsi JavaScript bawaan yang menerima a thisArg. Anda juga dapat menulis fungsi Anda sendiri menggunakan fungsi panggilan balik dan thisArg:

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

Ada kasus khusus yang belum saya sebutkan. Saat membuat objek baru melalui newoperator, penerjemah JavaScript membuat objek baru yang kosong, menetapkan beberapa properti internal, dan kemudian memanggil fungsi konstruktor pada objek baru. Jadi, ketika suatu fungsi dipanggil dalam konteks konstruktor, nilai dari thisadalah objek baru yang dibuat oleh interpreter:

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

Fungsi panah

Fungsi panah (diperkenalkan pada ECMA6) mengubah ruang lingkup this. Lihat pertanyaan kanonik yang ada, Deklarasi / ekspresi fungsi vs. fungsi: Apakah setara / dapat dipertukarkan? untuk informasi lebih lanjut. Namun singkatnya:

Fungsi panah tidak memiliki thisikatan .... sendiri . Sebaliknya, pengidentifikasi tersebut diselesaikan dalam ruang lingkup leksikal seperti variabel lainnya. Itu berarti bahwa di dalam fungsi panah, this... rujuk ke nilai-nilai thisdi lingkungan fungsi panah didefinisikan.

Hanya untuk bersenang-senang, uji pemahaman Anda dengan beberapa contoh

Untuk mengungkapkan jawabannya, arahkan mouse ke kotak abu-abu muda.

  1. Berapa nilai thispada baris yang ditandai? Mengapa?

    window - Baris yang ditandai dievaluasi dalam konteks eksekusi global awal.

    if (true) {
        // What is `this` here?
    }
  2. Berapakah nilai thispada baris yang ditandai saat obj.staticFunction()dijalankan? Mengapa?

    obj - Saat memanggil fungsi pada objek, Penjilidan Ini diatur ke objek.

    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. Berapa nilai thispada baris yang ditandai? Mengapa?

    window

    Dalam contoh ini, penerjemah JavaScript memasukkan kode fungsi, tetapi karena myFun/ obj.myMethodtidak dipanggil pada objek, ThisBinding diatur ke window.

    Ini berbeda dari Python, di mana mengakses metode ( obj.myMethod) membuat objek metode terikat .

    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. Berapa nilai thispada baris yang ditandai? Mengapa?

    window

    Yang ini rumit. Ketika mengevaluasi kode eval, thisadalah obj. Namun, dalam kode eval, myFuntidak dipanggil pada objek, jadi ThisBinding diatur ke windowuntuk panggilan.

    function myFun() {
        return this; // What is `this` here?
    }
    var obj = {
        myMethod: function () {
            eval("myFun()");
        }
    };
  5. Berapa nilai thispada baris yang ditandai? Mengapa?

    obj

    Baris myFun.call(obj);menggunakan fungsi built-in khusus Function.prototype.call(), yang menerima thisArgsebagai argumen pertama.

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

Daniel Trebbien
sumber
6
@ Ali: Mereka adalah referensi ke bagian dalam edisi 5.1 dari ECMAScript Standard, ECMA-262 . Saya menyediakannya sehingga Anda dapat membaca Standar untuk detail teknis jika Anda mau.
Daniel Trebbien
1
Saya pikir @supertonsky benar tentang # 2 - jika myFun () dipanggil dari ruang lingkup global, dan bukan sebagai metode pada objek, "ini" akan menjadi objek global, jadi ungkapan pertanyaan itu penting. btw - Saya sangat suka ide menggunakan mouseover untuk mendapatkan jawaban untuk sesuatu seperti ini.
user655489
2
Tapi, jsfiddle.net/H4LYm/2 menunjukkan bahwa setTimeoutcontoh memiliki thisdari window(global).
Kevin Meredith
2
datang dari Python orang akan membayangkan tingkat frustrasi yang saya miliki ketika saya bertemu dengan contoh 3 .. smh
Marius Mucenicu
1
Jawaban ini mungkin harus diperbarui untuk mencerminkan realitas ES2020, bahkan jika perubahannya hanya terminologis.
Ben Aston
156

Kata thiskunci berperilaku berbeda dalam JavaScript dibandingkan dengan bahasa lain. Dalam bahasa Berorientasi Objek, thiskata kunci mengacu pada instance kelas saat ini. Dalam JavaScript nilai thisditentukan oleh konteks fungsi invokasi ( context.function()) dan di mana ia disebut.

1. Ketika digunakan dalam konteks global

Ketika Anda menggunakan thisdalam konteks global, itu terikat ke objek global ( windowdi browser)

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

Ketika Anda menggunakan thisdi dalam suatu fungsi yang didefinisikan dalam konteks global, thismasih terikat pada objek global karena fungsi tersebut sebenarnya merupakan metode konteks global.

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

Di atas f1dibuat metode objek global. Dengan demikian kita juga dapat menyebutnya pada windowobjek sebagai berikut:

function f()
{
    return this;
}

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

2. Saat digunakan di dalam metode objek

Saat Anda menggunakan thiskata kunci di dalam metode objek, thisterikat ke objek terlampir "langsung".

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

Di atas saya telah menempatkan kata langsung dalam tanda kutip ganda. Ini untuk membuat titik bahwa jika Anda bersarang objek di dalam objek lain, maka thisterikat ke induk langsung.

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

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

Bahkan jika Anda menambahkan fungsi secara eksplisit ke objek sebagai metode, itu masih mengikuti aturan di atas, yang thismasih menunjuk ke objek induk langsung.

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. Saat menjalankan fungsi konteks-kurang

Ketika Anda menggunakan thisfungsi di dalam yang dipanggil tanpa konteks apa pun (yaitu tidak pada objek apa pun), itu terikat ke objek global ( windowdi browser) (bahkan jika fungsi tersebut didefinisikan di dalam objek).

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 

Mencoba semuanya dengan fungsi

Kita dapat mencoba poin di atas dengan fungsi juga. Namun ada beberapa perbedaan.

  • Di atas kami menambahkan anggota ke objek menggunakan notasi objek literal. Kami dapat menambahkan anggota ke fungsi dengan menggunakan this. untuk menentukannya.
  • Notasi objek literal membuat instance objek yang dapat kita gunakan segera. Dengan fungsi, kita mungkin perlu membuat instance terlebih dahulu menggunakan newoperator.
  • Juga dalam pendekatan literal objek, kita dapat secara eksplisit menambahkan anggota ke objek yang sudah didefinisikan menggunakan operator titik. Ini ditambahkan ke contoh khusus saja. Namun saya telah menambahkan variabel ke prototipe fungsi sehingga akan tercermin dalam semua contoh fungsi.

Di bawah ini saya mencoba semua hal yang kami lakukan dengan Object dan di thisatas, tetapi dengan terlebih dahulu membuat fungsi alih-alih secara langsung menulis objek.

/********************************************************************* 
  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. Saat digunakan di dalam fungsi konstruktor .

Ketika fungsi digunakan sebagai konstruktor (saat itu disebut dengan newkata kunci), thisfungsi tubuh bagian dalam menunjuk ke objek baru yang sedang dibangun.

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. Saat digunakan di dalam fungsi yang didefinisikan pada rantai prototipe

Jika metode ini pada rantai prototipe objek, thisdi dalam metode tersebut merujuk ke objek metode dipanggil, seolah-olah metode tersebut didefinisikan pada objek.

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. Panggilan dalam (), fungsi berlaku () dan ikat ()

  • Semua metode ini didefinisikan pada Function.prototype.
  • Metode-metode ini memungkinkan untuk menulis suatu fungsi sekali dan memintanya dalam konteks yang berbeda. Dengan kata lain, mereka memungkinkan untuk menentukan nilai thisyang akan digunakan saat fungsi sedang dieksekusi. Mereka juga mengambil parameter apa saja untuk diteruskan ke fungsi asli ketika dipanggil.
  • fun.apply(obj1 [, argsArray])Tetapkan obj1sebagai nilai thisdi dalam fun()dan memanggil fun()elemen lewat argsArraysebagai argumennya.
  • fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Ditetapkan obj1sebagai nilai dari thisdalam fun()dan panggilan fun()lewat arg1, arg2, arg3, ...sebagai argumennya.
  • fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])- Mengembalikan referensi ke fungsi fundengan thisfun di dalam terikat obj1dan parameter funterikat ke parameter yang ditentukan arg1, arg2, arg3,....
  • Sekarang perbedaan antara apply, calldan bindpasti menjadi jelas. applymemungkinkan untuk menentukan argumen untuk berfungsi sebagai objek seperti array yaitu objek dengan lengthproperti numerik dan properti integer non-negatif yang sesuai. Sedangkan callmemungkinkan untuk menentukan argumen ke fungsi secara langsung. Keduanya applydan callsegera memanggil fungsi dalam konteks yang ditentukan dan dengan argumen yang ditentukan. Di sisi lain, bindcukup mengembalikan fungsi terikat ke nilai yang ditentukan thisdan argumen. Kami dapat menangkap referensi ke fungsi yang dikembalikan ini dengan menetapkannya ke variabel dan kemudian kami dapat memanggilnya kapan saja.
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. thisdalam event handler

  • Saat Anda menetapkan fungsi langsung ke penangan peristiwa suatu elemen, penggunaan thislangsung di dalam fungsi penanganan acara mengacu pada elemen yang sesuai. Penugasan fungsi langsung semacam itu dapat dilakukan dengan menggunakan addeventListenermetode atau melalui metode pendaftaran acara tradisional seperti onclick.
  • Demikian pula, ketika Anda menggunakan thislangsung di dalam properti acara (seperti <button onclick="...this..." >) elemen, itu merujuk ke elemen.
  • Namun penggunaan thissecara tidak langsung melalui fungsi lain yang disebut di dalam fungsi penanganan acara atau properti acara diselesaikan ke objek global window.
  • Perilaku di atas yang sama dicapai ketika kami melampirkan fungsi ke pengendali acara menggunakan metode model Pendaftaran Acara Microsoft attachEvent. Alih-alih menugaskan fungsi ke pengendali acara (dan dengan demikian membuat metode fungsi elemen), ia memanggil fungsi pada acara tersebut (secara efektif memanggilnya dalam konteks global).

Saya merekomendasikan untuk mencoba ini dengan lebih baik di JSFiddle .

<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. thisdalam fungsi panah ES6

Dalam fungsi panah, thisakan berperilaku seperti variabel umum: itu akan diwarisi dari ruang lingkup leksikalnya. Fungsi this, di mana fungsi panah didefinisikan, akan menjadi fungsi panah this.

Jadi, itu perilaku yang sama dengan:

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

Lihat kode berikut:

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 
Mahesha999
sumber
"Ketika Anda menggunakan ini di dalam fungsi yang didefinisikan dalam konteks global, ini masih terikat pada objek global karena fungsi tersebut sebenarnya merupakan metode konteks global." salah. ini diatur oleh bagaimana suatu fungsi dipanggil atau oleh bind , bukan oleh di mana ia didefinisikan. Memanggil fungsi apa pun tanpa referensi dasar ("konteks") akan default ini ke objek global atau tetap tidak ditentukan dalam mode ketat.
RobG
@RobG hmm mungkin, tapi saya menemukan ini di MDN : Dalam hal ini, nilai thistidak ditentukan oleh panggilan. Karena kode tidak dalam mode ketat, nilai thisharus selalu menjadi objek sehingga default ke objek global. Dan sebenarnya itu sebabnya saya pikir kita bisa langsung melakukan panggilan window.f1(), sehingga berarti f1()sudah terlampir pada windowobjek, maksud saya sebelum doa. Apakah saya salah?
Mahesha999
Saya berkomentar (mungkin tidak jelas) pada Anda menghubungkan pengaturan ini dengan "fungsi sebenarnya membuat metode konteks global", seolah-olah itu semacam panggilan window.fn, yang bukan. ini default ke objek global karena tidak ada referensi dasar yang digunakan dalam panggilan, bukan karena di mana fungsi didefinisikan (jadi ini masih diatur oleh bagaimana fungsi dipanggil). Jika Anda secara eksplisit menyebutnya menggunakan window.fn, maka Anda mengatur ini ke jendela . Hasil yang sama, cara yang berbeda untuk melakukannya. :-)
RobG
"di atas, saya telah menempatkan kata langsung ..." tidak Anda tidak. Bisakah Anda merevisi ini sehingga kesalahan diperbaiki? Tampaknya semantik untuk jawabannya dan karenanya saya tidak dapat melanjutkan membaca sampai kesalahan diperbaiki karena takut mempelajari sesuatu yang salah.
TylerH
@ TylerH lakukan Ctrl + F pada halaman ini di browser Anda untuk menemukan string "segera" (termasuk tanda kutip ganda) Saya pikir itu ada jika saya salah
paham
64

Javascript this

Doa fungsi sederhana

Pertimbangkan fungsi berikut:

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

Perhatikan bahwa kami menjalankan ini dalam mode normal, yaitu mode ketat tidak digunakan.

Saat berjalan di browser, nilai thisakan dicatat sebagai window. Ini karena windowmerupakan variabel global dalam cakupan browser web.

Jika Anda menjalankan bagian kode yang sama di lingkungan seperti node.js, thisakan merujuk ke variabel global di aplikasi Anda.

Sekarang jika kita menjalankan ini dalam mode ketat dengan menambahkan pernyataan "use strict";ke awal deklarasi fungsi, thistidak akan lagi merujuk ke variabel global di salah satu lingkungan. Ini dilakukan untuk menghindari kebingungan dalam mode ketat. thisakan, dalam hal ini hanya login undefined, karena memang seperti itu, tidak didefinisikan.

Dalam kasus berikut, kita akan melihat bagaimana memanipulasi nilai this.

Memanggil fungsi pada objek

Ada berbagai cara untuk melakukan ini. Jika Anda telah memanggil metode asli dalam Javascript seperti forEachdan slice, Anda harus sudah tahu bahwa thisvariabel dalam kasus itu merujuk Objectpada yang Anda panggil fungsi itu (Perhatikan bahwa dalam javascript, hampir semua adalah Object, termasuk Arrays dan Functions). Ambil kode berikut sebagai contoh.

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

Jika suatu Objectberisi properti yang menyimpan a Function, properti itu disebut metode. Metode ini, ketika dipanggil, akan selalu memiliki thisset variabel untuk Objectdikaitkan dengan itu. Ini berlaku untuk mode ketat dan non-ketat.

Perhatikan bahwa jika suatu metode disimpan (atau lebih tepatnya, disalin) dalam variabel lain, referensi ke thistidak lagi dipertahankan dalam variabel baru. Sebagai contoh:

// continuing with the previous code snippet

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

Mempertimbangkan skenario yang lebih umum:

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

Kata newkunci

Pertimbangkan fungsi konstruktor dalam Javascript:

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`

Bagaimana cara kerjanya? Baiklah, mari kita lihat apa yang terjadi ketika kita menggunakan newkata kunci.

  1. Memanggil fungsi dengan newkata kunci akan segera menginisialisasi Objecttipe Person.
  2. Konstruktor ini Objectmengatur konstruktornya Person. Juga, perhatikan bahwa hanya typeof awalakan kembali Object.
  3. Ini baru Objectakan diberi prototipe Person.prototype. Ini berarti bahwa setiap metode atau properti dalam Personprototipe akan tersedia untuk semua kejadian Person, termasuk awal.
  4. Fungsi Personitu sendiri sekarang dipanggil; thismenjadi referensi ke objek yang baru dibangun awal.

Cukup mudah, eh?

Perhatikan bahwa spesifikasi ECMAScript resmi tidak menyatakan bahwa jenis fungsi tersebut adalah constructorfungsi sebenarnya . Mereka hanya fungsi normal, dan newdapat digunakan pada fungsi apa pun. Hanya saja kami menggunakannya seperti itu, dan kami menyebutnya begitu saja.

Memanggil fungsi pada Fungsi: calldanapply

Jadi ya, karena functions juga Objects(dan sebenarnya variabel kelas pertama dalam Javascript), bahkan fungsi memiliki metode yang ... yah, fungsi itu sendiri.

Semua fungsi mewarisi dari global Function, dan dua dari banyak metodenya adalah calldan apply, dan keduanya dapat digunakan untuk memanipulasi nilai thisdalam fungsi yang mereka panggil.

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

Ini adalah contoh khas penggunaan call. Ini pada dasarnya mengambil parameter pertama dan menetapkan thisfungsi foosebagai referensi thisArg. Semua parameter lain yang diteruskan ke callditeruskan ke fungsi foosebagai argumen.
Jadi kode di atas akan masuk {myObj: "is cool"}, [1, 2, 3]konsol. Cara yang cukup bagus untuk mengubah nilai thisdalam fungsi apa pun.

applyhampir sama dengan callaccept yang hanya membutuhkan dua parameter: thisArgdan array yang berisi argumen untuk diteruskan ke fungsi. Jadi callpanggilan di atas dapat diterjemahkan menjadi applyseperti ini:

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

Catat itu calldan applydapat menimpa nilai thisset oleh metode titik yang kita bahas dalam butir kedua. Cukup sederhana :)

Mempresentasikan .... bind!

bindadalah saudara dari calldan apply. Ini juga merupakan metode yang diwarisi oleh semua fungsi dari Functionkonstruktor global di Javascript. Perbedaan antara binddan call/ applyadalah keduanya calldan applyakan benar-benar memanggil fungsi. bind, di sisi lain, mengembalikan fungsi baru dengan thisArgdan argumentssebelumnya. Mari kita ambil contoh untuk lebih memahami ini:

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]`

Lihat perbedaan antara ketiganya? Itu halus, tetapi mereka digunakan secara berbeda. Sukai calldan apply, bindjuga akan menunggangi nilai thisset oleh metode dot-method.

Perhatikan juga bahwa tidak satu pun dari ketiga fungsi ini melakukan perubahan pada fungsi aslinya. calldan applyakan mengembalikan nilai dari fungsi yang baru dibangun sementara bindakan mengembalikan fungsi yang baru dibangun itu sendiri, siap dipanggil.

Barang ekstra, salin ini

Terkadang, Anda tidak suka fakta yang thisberubah dengan cakupan, terutama cakupan bersarang. Lihatlah contoh berikut.

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

Dalam kode di atas, kita melihat bahwa nilai thisberubah dengan cakupan bersarang, tetapi kami menginginkan nilai dari thislingkup asli. Jadi kami 'menyalin' thiske thatdan menggunakan salinannya sebagai ganti this. Pintar, eh?

Indeks:

  1. Apa yang ditahan thissecara default?
  2. Bagaimana jika kita memanggil fungsi sebagai metode dengan notasi Object-dot?
  3. Bagaimana jika kita menggunakan newkata kunci?
  4. Bagaimana cara kita memanipulasi thisdengan calldan apply?
  5. Menggunakan bind.
  6. Menyalin thisuntuk memecahkan masalah ruang lingkup bersarang.
pengguna3459110
sumber
47

"Ini" adalah tentang ruang lingkup. Setiap fungsi memiliki cakupannya sendiri, dan karena segala sesuatu di JS adalah objek, bahkan fungsi dapat menyimpan beberapa nilai ke dalam dirinya sendiri menggunakan "ini". OOP 101 mengajarkan bahwa "ini" hanya berlaku untuk instance objek. Oleh karena itu, setiap kali fungsi dijalankan, "instance" baru dari fungsi tersebut memiliki arti baru "ini".

Kebanyakan orang menjadi bingung ketika mereka mencoba menggunakan "ini" di dalam fungsi penutupan anonim seperti:

(fungsi (nilai) {
    this.value = value;
    $ ('. beberapa elemen'). masing-masing (fungsi (elt) {
        elt.innerHTML = this.value; // uh oh!! mungkin tidak terdefinisi
    });
}) (2);

Jadi di sini, di dalam setiap (), "ini" tidak memiliki "nilai" yang Anda harapkan (dari

this.value = value;
diatasnya). Jadi, untuk mengatasi masalah ini (tidak ada permainan kata-kata), pengembang dapat:

(fungsi (nilai) {
    var self = ini; // perubahan kecil
    self.value = value;
    $ ('. beberapa elemen'). masing-masing (fungsi (elt) {
        elt.innerHTML = self.value; // Fiuh !! == 2
    });
}) (2);

Cobalah; Anda akan mulai menyukai pola pemrograman ini

arunjitsingh
sumber
6
"semua yang ada di JS adalah objek" tidak benar, JavaScript juga memiliki nilai primitif, lihat bclary.com/2004/11/07/#a-4.3.2
Marcel Korpel
6
Nilai-nilai primitif tampaknya memiliki beberapa metode pada diri mereka sendiri, seperti String # substring (), Number # toString (), dll. Jadi, mungkin tidak dengan nomenklatur yang sama dengan artikel itu, mereka benar-benar berperilaku seolah-olah mereka adalah objek (mereka adalah semua prototyped, mis. String # substring () benar-benar: String.prototype.substring = function () {...}). Harap perbaiki saya jika saya salah.
arunjitsingh
12
Kata thiskunci tidak ada hubungannya dengan ruang lingkup. Selain itu, ia memiliki arti juga dalam fungsi-fungsi yang bukan properti objek.
Bergi
1
@ arunjitsingh — ada dua aliran pemikiran tentang itu. Saya suka yang mengatakan " semuanya adalah objek, tetapi beberapa dapat diwakili oleh primitif untuk kenyamanan ". ;-)
RobG
9
thistidak SEMUA tentang ruang lingkup. Ini adalah SEMUA tentang konteks eksekusi, yang tidak sama dengan ruang lingkup. JavaScript dibatasi secara leksikal (ruang lingkup makna ditentukan oleh lokasi kode), tetapi thisditentukan oleh bagaimana fungsi yang memuatnya dipanggil - bukan di mana fungsi itu berada.
Scott Marcus
16

Karena utas ini telah meningkat, saya telah mengumpulkan beberapa poin untuk pembaca yang baru dalam thistopik.

Bagaimana nilai thisditentukan?

Kami menggunakan ini mirip dengan cara kami menggunakan kata ganti dalam bahasa alami seperti bahasa Inggris: "John berlari cepat karena ia mencoba untuk naik kereta." Sebaliknya kita bisa menulis "... John sedang mencoba untuk menangkap kereta".

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 tidak diberi nilai sampai suatu objek memanggil fungsi di mana ia didefinisikan. Dalam lingkup global, semua variabel dan fungsi global didefinisikan pada windowobjek. Oleh karena itu, thisdalam fungsi global mengacu pada (dan memiliki nilai) windowobjek global .

Ketika use strict, thisdalam fungsi global dan anonim yang tidak terikat pada objek apa pun memegang nilai undefined.

Kata thiskunci paling disalahpahami ketika: 1) kami meminjam metode yang menggunakan this, 2) kami menetapkan metode yang digunakan thisuntuk variabel, 3) fungsi yang digunakan thisdilewatkan sebagai fungsi panggilan balik, dan 4) thisdigunakan di dalam penutupan - fungsi batin. (2)

meja

Apa yang memegang masa depan

Didefinisikan dalam ECMA Script 6 , fungsi panah mengadopsi thispengikatan dari lingkup melampirkan (fungsi atau global).

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!

Sementara fungsi panah memberikan alternatif untuk digunakan bind(), penting untuk dicatat bahwa mereka pada dasarnya menonaktifkan thismekanisme tradisional demi pelingkupan leksikal yang lebih luas dipahami. (1)


Referensi:

  1. this & Object Prototypes , oleh Kyle Simpson. © 2014 Getify Solutions.
  2. javascriptissexy.com - http://goo.gl/pvl0GX
  3. Angus Croll - http://goo.gl/Z2RacU
carlodurso
sumber
16

thisdalam JavaScript selalu mengacu pada 'pemilik' fungsi yang sedang dijalankan .

Jika tidak ada pemilik eksplisit yang didefinisikan, maka pemilik paling atas, objek jendela, direferensikan.

Jadi jika saya lakukan

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

element.onclick = someKindOfFunction;

thisakan merujuk ke objek elemen. Tapi hati-hati, banyak orang membuat kesalahan ini.

<element onclick="someKindOfFunction()">

Dalam kasus terakhir, Anda hanya mereferensikan fungsi, bukan menyerahkannya ke elemen. Karena itu, thisakan merujuk ke objek jendela.

Seph
sumber
15

Setiap konteks eksekusi di javascript memiliki parameter ini yang ditetapkan oleh:

  1. Bagaimana fungsi dipanggil (termasuk sebagai metode objek, penggunaan panggilan dan penerapan , penggunaan baru )
  2. Penggunaan bind
  3. Leksikal untuk fungsi panah (mereka mengadopsi ini dari konteks eksekusi luar mereka)
  4. Apakah kode dalam mode ketat atau tidak ketat
  5. Apakah kode itu dipanggil menggunakan atau tidak eval

Anda dapat mengatur nilai ini menggunakan func.call, func.applyatau func.bind.

Secara default, dan apa yang membingungkan kebanyakan pemula, ketika pendengar disebut setelah acara dimunculkan pada elemen DOM, yang ini nilai fungsi adalah elemen DOM.

jQuery membuat ini sepele untuk berubah dengan jQuery.proxy.

orang dungu
sumber
9
Sedikit lebih benar untuk mengatakan bahwa setiap panggilan fungsi memiliki cakupan. Dengan kata lain, yang membingungkan tentang thisJavascript adalah bahwa itu bukan properti intrinsik dari fungsi itu sendiri, tetapi lebih merupakan artefak dari cara fungsi dipanggil.
Runcing
@ sangat berterima kasih. apa yang paling menyebabkan kebingungan tentang ini dalam js adalah kenyataan bahwa dalam semua bahasa yang digunakan sebelumnya (c #, c ++), - ini tidak dapat dimanipulasi n selalu menunjuk ke objek contoh sedangkan di js itu tergantung dan dapat diubah ketika memanggil fungsi menggunakan func.call, func.binddll. - Sushil
Sushil
2
thistidak tidak referensi lingkup fungsi ini. thisakan mereferensikan objek tertentu (atau mungkin undefined), yang seperti telah Anda katakan dapat diubah menggunakan .call()atau .apply(). Ruang lingkup fungsi adalah (pada dasarnya, ketika disederhanakan) variabel mana yang memiliki akses, dan ini sepenuhnya tergantung pada di mana fungsi tersebut dinyatakan dan tidak dapat diubah.
nnnnnn
@Pointy: "Sedikit lebih tepat untuk mengatakan bahwa setiap panggilan fungsi memiliki ruang lingkup." Bahkan lebih tepat untuk mengatakan bahwa fungsi (dan sekarang blok) memiliki ruang lingkup , panggilan fungsi memiliki konteks . Lingkup mendefinisikan apa pengidentifikasi yang dapat digunakan oleh kode dalam lingkup itu. Konteks menentukan apa yang terikat oleh pengidentifikasi tersebut.
TJ Crowder
1
"Apa pun ruang lingkup itu, dirujuk oleh" ini "." Tidak, thisdan ruang lingkup tidak ada hubungannya sama sekali dalam ES5 dan sebelumnya (misalnya, ketika jawaban ini ditulis). Dalam ES2015 (alias ES6), thisdan lingkup terkait satu cara panah wrt cara yang cukup minimal (fungsi panah thisdalam diwarisi dari cakupan melampirkan), tetapi thistidak pernah merujuk pada lingkup.
TJ Crowder
10

Berikut adalah salah satu sumber thismasuk yang bagus JavaScript.

Berikut ringkasannya:

  • global ini

    Di browser, di lingkup global, thisadalah windowobjek

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

    Dalam nodemenggunakan repl, thisadalah namespace teratas. Anda dapat menyebutnya sebagai global.

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

    Dalam nodemengeksekusi dari skrip, thisdi lingkup global dimulai sebagai objek kosong. Ini tidak sama denganglobal

    \\test.js
    console.log(this);  \\ {}
    console.log(this === global); \\ fasle
  • berfungsi ini

Kecuali dalam hal event handler DOM atau ketika thisArgdisediakan (lihat lebih jauh ke bawah), baik di node maupun di browser yang menggunakan thisfungsi yang tidak disebut dengan newreferensi lingkup global ...

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

Jika Anda menggunakan use strict;, dalam hal thisapaundefined

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

Jika Anda memanggil fungsi dengan newyang thisakan menjadi konteks baru, itu tidak akan referensi global this.

<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>
  • prototipe ini

Fungsi yang Anda buat menjadi objek fungsi. Mereka secara otomatis mendapatkan prototypeproperti khusus , yang merupakan sesuatu yang dapat Anda berikan nilainya. Saat Anda membuat instance dengan memanggil fungsi newAnda dengan Anda mendapatkan akses ke nilai yang Anda tetapkan untuk prototypeproperti. Anda mengakses nilai-nilai itu menggunakan this.

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

Thing.prototype.foo = "bar";

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

Biasanya merupakan kesalahan untuk menetapkan array atau objek pada prototype. Jika Anda ingin instance untuk masing-masing memiliki array sendiri, buat mereka dalam fungsi, bukan prototipe.

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 []
  • keberatan ini

Anda dapat menggunakan thisfungsi apa pun pada objek untuk merujuk ke properti lain pada objek itu. Ini tidak sama dengan instance yang dibuat dengan new.

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

obj.logFoo(); //logs "bar"
  • Acara DOM ini

Dalam penangan acara HTML DOM, thisselalu ada referensi ke elemen DOM tempat acara dilampirkan

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

Kecuali Anda bindkonteksnya

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 ini

Di dalam atribut HTML di mana Anda dapat menempatkan JavaScript, thisadalah referensi ke elemen.

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

Anda dapat menggunakannya evaluntuk mengakses this.

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

var thing = new Thing();
thing.logFoo();
  • dengan ini

Anda dapat menggunakan withuntuk menambah thisruang lingkup saat ini untuk membaca dan menulis ke nilai thistanpa merujuk thissecara eksplisit.

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 ini

jQuery akan di banyak tempat thismerujuk ke elemen DOM.

<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>
zangw
sumber
9

Daniel, penjelasan yang luar biasa! Beberapa kata pada ini dan daftar yang baik dari thispointer konteks eksekusi dalam hal penangan acara.

Dalam dua kata, thisdalam JavaScript menunjukkan objek dari siapa (atau dari konteks pelaksanaannya) fungsi saat ini dijalankan dan selalu hanya baca, Anda tetap tidak dapat mengaturnya (upaya tersebut akan berakhir dengan 'Kiri tidak valid' sisi dalam pesan tugas.

Untuk penangan event: penangan event inline, seperti <element onclick="foo">, mengesampingkan penangan lain yang terlampir sebelumnya dan sebelumnya, jadi berhati-hatilah dan lebih baik untuk tidak ikut serta dalam delegasi acara inline sama sekali. Dan terima kasih kepada Zara Alaverdyan yang mengilhami saya untuk daftar contoh ini melalui debat yang berbeda :)

  • 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)">
Arman McHitarian
sumber
9

Ada banyak kebingungan mengenai bagaimana kata kunci "ini" ditafsirkan dalam JavaScript. Semoga artikel ini akan meletakkan semua orang untuk beristirahat sekali dan untuk semua. Dan masih banyak lagi. Silakan baca seluruh artikel dengan seksama. Diperingatkan bahwa artikel ini panjang.

Terlepas dari konteks di mana ia digunakan, "ini" selalu merujuk "objek saat ini" dalam Javascript. Namun, apa "objek saat ini" berbeda menurut konteksnya . The konteks mungkin persis 1 dari 6 berikut:

  1. Global (mis. Di luar semua fungsi)
  2. Panggilan "Non Bound Function" Direct Direct (yaitu fungsi yang belum terikat dengan memanggil functionName.bind )
  3. Di dalam Indirect "Non Bound Function" Panggil melalui functionName.call dan functionName.apply
  4. Di dalam Panggilan "Fungsi Terikat" (yaitu fungsi yang telah terikat dengan memanggil functionName.bind )
  5. Sedangkan Penciptaan Obyek melalui "baru"
  6. Di dalam pengatur acara DOM Inline

Berikut ini menjelaskan masing-masing konteks ini satu per satu:

  1. Konteks Global (yaitu Di luar semua fungsi):

    Di luar semua fungsi (yaitu dalam konteks global) "objek saat ini" (dan karenanya nilai "ini" ) selalu menjadi objek "jendela" untuk browser.

  2. Panggilan "Non Bound Function" Langsung Di Dalam :

    Di dalam Panggilan "Fungsi Tidak Terikat" Langsung, objek yang memanggil pemanggilan fungsi menjadi "objek saat ini" (dan karenanya nilai "ini" ). Jika suatu fungsi dipanggil tanpa objek saat ini eksplisit , objek saat ini adalah objek "jendela" (Untuk Mode Non Strict) atau tidak terdefinisi (Untuk Mode Strict). Setiap fungsi (atau variabel) yang didefinisikan dalam Konteks Global secara otomatis menjadi properti dari objek "jendela". Misalnya, fungsi Misalkan didefinisikan dalam Konteks Global sebagai

    function UserDefinedFunction(){
        alert(this)
        }

    itu menjadi properti objek jendela, seolah-olah Anda telah mendefinisikannya sebagai

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

    Dalam "Non Strict Mode", Memanggil / Memanggil fungsi ini langsung melalui "UserDefinedFunction ()" akan secara otomatis memanggil / memanggilnya sebagai "window.UserDefinedFunction ()" menjadikan "jendela" sebagai "objek saat ini" (dan karenanya nilai dari " ini " ) dalam " UserDefinedFunction " .Melakukan fungsi ini dalam" Non Strict Mode "akan menghasilkan yang berikut ini

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

    Dalam "Mode Ketat", Memanggil / Memanggil fungsi langsung melalui "UserDefinedFunction ()" akan "TIDAK" secara otomatis memanggil / memanggilnya sebagai "window.UserDefinedFunction ()" .Dari "objek saat ini" (dan nilai "ini" ) dalam "UserDefinedFunction" harus ditentukan . Menjalankan fungsi ini dalam "Mode Ketat" akan menghasilkan yang berikut ini

    UserDefinedFunction() // displays undefined

    Namun, menjalankannya secara eksplisit menggunakan objek jendela akan menghasilkan sebagai berikut

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

    Mari kita lihat contoh lain. Silakan lihat kode berikut

     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

    Dalam contoh di atas kita melihat bahwa ketika "UserDefinedFunction" dipanggil melalui o1 , "this" mengambil nilai o1 dan nilai propertinya "a" dan "b" ditampilkan. Nilai "c" dan "d" ditampilkan sebagai tidak terdefinisi karena o1 tidak mendefinisikan properti ini

    Demikian pula ketika "UserDefinedFunction" itu dipanggil melalui o2 , "ini" mengambil nilai o2 dan nilai properti nya "c" dan "d" mendapatkan tampil pada display nilai "a" dan "b" yang ditampilkan sebagai terdefinisi sebagai o2 tidak tidak mendefinisikan properti ini.

  3. Di dalam Indirect "Non Bound Function" Panggil melalui functionName.call dan functionName.apply :

    Ketika "Fungsi Tidak Terikat" dipanggil melalui functionName.call atau functionName.apply , "objek saat ini" (dan karenanya nilai "ini" ) diatur ke nilai parameter "ini" (parameter pertama) diteruskan untuk memanggil Saya melamar . Kode berikut menunjukkan hal yang sama.

    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

    Kode di atas dengan jelas menunjukkan bahwa nilai "ini" untuk "Fungsi NON Bound" apa pun dapat diubah melalui panggilan / berlaku . Juga, jika parameter "ini" tidak secara eksplisit diteruskan untuk memanggil / menerapkan , "objek saat ini" (dan karenanya nilai "ini") diatur ke "jendela" dalam mode Non-ketat dan "tidak terdefinisi" dalam mode ketat.

  4. Di dalam Panggilan "Fungsi Terikat" (yaitu fungsi yang telah terikat dengan memanggil functionName.bind ):

    Fungsi terikat adalah fungsi yang nilainya "ini" telah diperbaiki. Kode berikut menunjukkan bagaimana "ini" bekerja jika ada fungsi terikat

    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

    Seperti yang diberikan dalam kode di atas, nilai "ini" untuk "Fungsi Batas" apa pun TIDAK DAPAT diubah melalui panggilan / berlaku . Juga, jika parameter "ini" tidak secara eksplisit diteruskan untuk mengikat, "objek saat ini" (dan karenanya nilai "ini" ) diatur ke "jendela" dalam mode Non-ketat dan "tidak terdefinisi" dalam mode ketat. Satu hal lagi. Mengikat fungsi yang sudah terikat tidak mengubah nilai "ini" . Tetap ditetapkan sebagai nilai yang ditetapkan oleh fungsi bind pertama.

  5. Sedangkan Pembuatan Objek melalui "baru" :

    Di dalam fungsi konstruktor, "objek saat ini" (dan karenanya nilai "ini" ) merujuk objek yang saat ini sedang dibuat melalui "baru" terlepas dari status mengikat fungsi. Namun jika konstruktor adalah fungsi terikat, ia harus dipanggil dengan seperangkat argumen yang telah ditentukan sebagaimana ditetapkan untuk fungsi terikat.

  6. Pengendali acara DOM Inside Inline :

    Silakan lihat Cuplikan HTML berikut

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

    The "ini" di contoh di atas merujuk pada "tombol" elemen dan "div" elemen masing-masing.

    Pada contoh pertama, warna font tombol harus diatur ke putih ketika diklik.

    Dalam contoh kedua ketika elemen "div" diklik, ia akan memanggil fungsi OnDivClick dengan parameter keduanya merujuk pada elemen div yang diklik. Namun nilai "ini" dalam OnDivClick TIDAK AKAN mereferensikan elemen div yang diklik . Ini harus ditetapkan sebagai "objek jendela" atau "tidak terdefinisi" dalam Mode Non-ketat dan Ketat masing-masing (jika OnDivClick adalah fungsi tidak terikat ) atau diatur ke nilai Batas yang ditentukan sebelumnya (jika OnDivClick adalah fungsi terikat )

Berikut ini ringkasan seluruh artikel

  1. Global Context "ini" selalu mengacu pada "jendela" objek

  2. Setiap kali suatu fungsi dipanggil, ia dipanggil dalam konteks objek ( "objek saat ini" ). Jika objek saat ini tidak disediakan secara eksplisit, objek saat ini adalah "objek jendela" dalam Mode NON Ketat dan "tidak terdefinisi" dalam Mode Ketat secara default.

  3. Nilai "ini" dalam fungsi Non Bound adalah referensi ke objek dalam konteks fungsi yang dipanggil ( "objek saat ini" )

  4. Nilai "ini" dalam fungsi Non Bound dapat diganti dengan panggilan dan menerapkan metode fungsi.

  5. Nilai "ini" adalah tetap untuk fungsi Terikat dan tidak dapat diganti dengan panggilan dan menerapkan metode fungsi.

  6. Binding dan fungsi yang sudah terikat tidak mengubah nilai "ini". Tetap ditetapkan sebagai nilai yang ditetapkan oleh fungsi bind pertama.

  7. Nilai "ini" dalam konstruktor adalah objek yang sedang dibuat dan diinisialisasi

  8. Nilai "ini" dalam event handler DOM inline adalah referensi ke elemen yang event handler diberikan.

Arup Hore
sumber
9

Mungkin artikel yang paling terperinci dan komprehensif thisadalah sebagai berikut:

Penjelasan lembut tentang kata kunci 'ini' dalam JavaScript

Gagasan di belakang thisadalah untuk memahami bahwa jenis pemanggilan fungsi memiliki kepentingan yang signifikan pada pengaturan thisnilai.


Ketika mengalami kesulitan mengidentifikasi this, jangan bertanya pada diri sendiri:

Dari mana thisdiambil ?

tapi jangan bertanya pada diri sendiri:

Bagaimana fungsi dipanggil ?

Untuk fungsi panah (kasus khusus transparansi konteks) tanyakan pada diri sendiri:

Nilai apa yang dimiliki di thismana fungsi panah didefinisikan ?

Pola pikir ini benar ketika berhadapan dengan thisdan akan menyelamatkan Anda dari sakit kepala.

Dmitri Pavlutin
sumber
Selain menautkan ke blog Anda, mungkin Anda bisa menggali lebih dalam tentang bagaimana mengajukan pertanyaan-pertanyaan itu membantu seseorang memahami thiskata kunci?
Magnus Lind Oxlund
7

Ini adalah penjelasan terbaik yang pernah saya lihat: Memahami JavaScripts ini dengan Clarity

The ini referensi SELALU mengacu pada (dan memegang nilai) obyek-a tunggal objek-dan biasanya digunakan di dalam fungsi atau metode, meskipun dapat digunakan di luar fungsi dalam lingkup global. Perhatikan bahwa ketika kita menggunakan mode ketat, ini memegang nilai yang tidak terdefinisi dalam fungsi global dan fungsi anonim yang tidak terikat pada objek apa pun.

Ada Empat Skenario di mana ini bisa membingungkan:

  1. Ketika kami melewati metode (yang menggunakan ini ) sebagai argumen untuk digunakan sebagai fungsi panggilan balik.
  2. Ketika kita menggunakan fungsi bagian dalam (penutupan). Penting untuk dicatat bahwa penutupan tidak dapat mengakses fungsi luar dari variabel ini dengan menggunakan kata kunci ini karena variabel ini hanya dapat diakses oleh fungsi itu sendiri, bukan oleh fungsi dalam.
  3. Ketika metode yang bergantung pada ini ditugaskan untuk variabel lintas konteks, dalam hal ini referensi objek lain dari yang semula dimaksudkan.
  4. Saat menggunakan ini bersama dengan metode bind, apply, dan call.

Dia memberikan contoh kode, penjelasan, dan solusi, yang saya pikir sangat membantu.

James Drinkard
sumber
6

Dalam istilah pseudoklasik, cara banyak kuliah mengajarkan kata kunci 'ini' adalah sebagai objek yang dipakai oleh kelas atau konstruktor objek. Setiap kali sebuah objek baru dibangun dari sebuah kelas, bayangkan bahwa di bawah kap sebuah instance lokal dari objek 'ini' dibuat dan dikembalikan. Saya ingat itu diajarkan seperti ini:

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;
mrmaclean89
sumber
5

thisadalah salah satu konsep disalahpahami dalam JavaScript karena berperilaku sedikit berbeda dari satu tempat ke tempat lain. Sederhananya, thismengacu pada "pemilik" fungsi yang sedang kami jalankan .

thismembantu mendapatkan objek saat ini (alias konteks eksekusi) yang kami kerjakan. Jika Anda mengerti di objek mana fungsi saat ini dieksekusi, Anda dapat dengan mudah memahami apa itu saat thisini

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

Di atas kita membuat 3 variabel dengan nama yang sama 'val'. Satu dalam konteks global, satu di dalam obj dan yang lainnya di dalam metode obj. JavaScript menyelesaikan pengidentifikasi dalam konteks tertentu dengan meningkatkan rantai lingkup dari lokal go global.


Beberapa tempat di mana thisdapat dibedakan

Memanggil metode objek

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

Ketika line1 dieksekusi, JavaScript menetapkan konteks eksekusi (EC) untuk pemanggilan fungsi, mengatur thiske objek yang dirujuk oleh apa pun yang datang sebelum "" terakhir. . jadi di baris terakhir Anda bisa mengerti yang a()dieksekusi dalam konteks global yang mana window.

Dengan Konstruktor

this dapat digunakan untuk merujuk ke objek yang sedang dibuat

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

Ketika baru Person()dieksekusi, objek yang sama sekali baru dibuat. Persondipanggil dan thisdiatur untuk referensi objek baru itu.

Panggilan fungsi

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 

Jika kami kehilangan newkata kunci, whatIsThislihat konteks paling global yang dapat ditemukannya ( window)

Dengan penangan acara

Jika pengendali event inline, thismerujuk ke objek global

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

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

Saat menambahkan pengendali acara melalui JavaScript, thismerujuk ke elemen DOM yang menghasilkan acara.


Nipuna
sumber
5

Nilai "ini" tergantung pada "konteks" di mana fungsi dijalankan. Konteksnya dapat berupa objek apa pun atau objek global, yaitu jendela.

Jadi Semantik "ini" berbeda dari bahasa OOP tradisional. Dan itu menyebabkan masalah: 1. ketika suatu fungsi dilewatkan ke variabel lain (kemungkinan besar, panggilan balik); dan 2. ketika penutupan dipanggil dari metode anggota kelas.

Dalam kedua kasus, ini diatur ke jendela.

Trombe
sumber
3

Apa ini bisa membantu? (Sebagian besar kebingungan 'ini' dalam javascript berasal dari fakta bahwa umumnya ini tidak terkait dengan objek Anda, tetapi ke lingkup eksekusi saat ini - yang mungkin tidak persis bagaimana cara kerjanya tetapi selalu terasa seperti itu bagi saya - lihat artikel untuk penjelasan lengkap)

Simon Groenewolt
sumber
1
Akan lebih baik untuk mengatakan itu terkait " dengan konteks eksekusi saat ini ". Kecuali ES6 (konsep) mengubah itu dengan fungsi panah, di mana ini diselesaikan pada konteks eksekusi luar.
RobG
3

Sedikit info tentang kata kunci ini

Mari masuk thiskata kunci ke konsol dalam lingkup global tanpa kode apa pun kecuali

console.log(this)

Di Klien / Browser this kata kunci adalah objek global yangwindow

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

dan

Dalam kata kunci runtime Server / Node / Javascript this juga merupakan objek global yangmodule.exports

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

Perlu diingat exportshanyalah referensi untukmodule.exports

tidak fleksibel
sumber
1

ini digunakan untuk Lingkup seperti ini

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

nilai txt1 dan txt sama dalam contoh di atas $ (ini) = $ ('# tbleName tbody tr') adalah Sama

PRADEEP SINGH Chundawat
sumber
1

Saya memiliki pandangan berbeda this dari jawaban lain yang saya harap dapat membantu.

Salah satu cara untuk melihat JavaScript adalah dengan melihat bahwa hanya ada 1 cara untuk memanggil fungsi 1 . ini

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

Selalu ada beberapa nilai yang diberikan untuk objectForThis.

Yang lainnya adalah gula sintaksis functionObject.call

Jadi, semua hal lain dapat dijelaskan dengan bagaimana ia diterjemahkan functionObject.call.

Jika Anda hanya memanggil fungsi maka thisadalah "objek global" yang di browser adalah jendela

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

foo();  // this is the window object

Dengan kata lain,

foo();

secara efektif diterjemahkan ke dalam

foo.call(window);

Perhatikan bahwa jika Anda menggunakan mode ketat maka thisakan menjadiundefined

'use strict';

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

foo();  // this is the window object

yang berarti

Dengan kata lain,

foo();

secara efektif diterjemahkan ke dalam

foo.call(undefined);

Dalam JavaScript ada operator seperti +dan -dan *. Ada juga operator titik yang.

The .Operator bila digunakan dengan fungsi di sebelah kanan dan objek di sebelah kiri secara efektif berarti "lulus objek sebagaithis fungsi.

Contoh

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

bar.foo();  // this is bar

Dengan kata lain bar.foo()diterjemahkan menjadiconst temp = bar.foo; temp.call(bar);

Perhatikan bahwa tidak masalah bagaimana fungsi itu dibuat (kebanyakan ...). Semua ini akan menghasilkan hasil yang sama

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

Sekali lagi ini semua hanyalah gula sintaksis

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

Satu kerutan lainnya adalah rantai prototipe. Ketika Anda menggunakan a.bJavaScript, pertama-tama terlihat pada objek yang dirujuk langsung oleh auntuk properti b. Jika btidak ditemukan pada objek maka JavaScript akan mencari prototipe objek untuk ditemukan b.

Ada berbagai cara untuk mendefinisikan prototipe objek, yang paling umum pada 2019 adalah classkata kunci. Untuk tujuan thismeskipun tidak masalah. Yang penting adalah bahwa ketika terlihat di objek auntuk properti bjika menemukan properti bpada objek atau dalam rantai prototipe itu jika bakhirnya menjadi fungsi maka aturan yang sama seperti di atas berlaku. bReferensi fungsi akan dipanggil menggunakan callmetode dan lewata sebagai objectForThis seperti yang ditunjukkan bagian atas jawaban ini.

Sekarang. Mari kita bayangkan kita membuat fungsi yang secara eksplisit mengatur thissebelum memanggil fungsi lain dan kemudian memanggilnya dengan .operator (titik)

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

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

const obj = {
  bar,
};

obj.bar();  

Setelah terjemahan yang digunakan call, obj.bar()menjadi const temp = obj.bar; temp.call(obj);. Ketika kita memasuki barfungsi yang kita panggil footetapi kita secara eksplisit melewati objek lain untuk objectForThis sehingga ketika kita tiba di foothis adalah objek batin itu.

Inilah yang keduanya binddan =>fungsi lakukan secara efektif. Mereka lebih banyak gula sintaksis. Mereka secara efektif membangun fungsi tak kasat mata baru persis seperti di baratas yang secara eksplisit mengatur thissebelum memanggil fungsi apa pun yang ditentukan. Dalam hal mengikat thisdiatur ke apa pun yang Anda lewati 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'});

Perhatikan bahwa jika functionObject.bindtidak ada kita bisa membuat sendiri seperti ini

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

dan kemudian kita bisa menyebutnya seperti ini

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

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

Fungsi panah, =>operator adalah gula sintaksis untuk mengikat

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

sama dengan

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

Sama seperti bind, fungsi tak terlihat baru dibuat yang memanggil fungsi yang diberikan dengan nilai terikat untuk objectForThistetapi tidak seperti bindobjek yang akan terikat adalah implisit. Apa pun yang thisterjadi ketika=> operator digunakan.

Jadi, sama seperti aturan di atas

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()menerjemahkan const temp = obj.foo; temp.call(obj);yang berarti operator panah di dalam fooakan mengikat objke fungsi tak terlihat baru dan mengembalikan fungsi tak terlihat baru yang ditugaskan b. b()akan berfungsi seperti biasa b.call(window)atau b.call(undefined)memanggil fungsi tak terlihat yang foodibuat. Fungsi tak terlihat itu mengabaikan yang thisditeruskan ke dalamnya dan meneruskan objsebagai objectForThis` ke fungsi panah.

Kode di atas diterjemahkan menjadi

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 adalah fungsi lain yang mirip dengancall

functionName.apply(objectForThis, arrayOfArgs);

Tetapi pada ES6 secara konseptual Anda bahkan dapat menerjemahkannya menjadi

functionName.call(objectForThis, ...arrayOfArgs);
gman
sumber
0

Ringkasan thisJavascript:

  • Nilai thisditentukan oleh bagaimana fungsi dipanggil bukan, di mana ia dibuat!
  • Biasanya nilai thisditentukan oleh Obyek yang tersisa dari titik. (window di ruang global)
  • Dalam hal pendengar nilai this mengacu pada elemen DOM yang menjadi dasar acara tersebut.
  • Ketika dalam fungsi dipanggil dengan newkata kunci nilaithis merujuk ke objek yang baru dibuat
  • Anda dapat memanipulasi nilai thisdengan fungsi: call, apply,bind

Contoh:

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
              
             

Contoh pendengar acara:

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>

Contoh konstruktor:

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.

Willem van der Veen
sumber
0

Untuk memahami "ini" dengan benar orang harus memahami konteks dan ruang lingkup dan perbedaan di antara mereka.

Lingkup : Dalam lingkup javascript terkait dengan visibilitas variabel, ruang lingkup dicapai melalui penggunaan fungsi. (Baca lebih lanjut tentang ruang lingkup)

Konteks : Konteks terkait dengan objek. Ini merujuk ke objek yang memiliki fungsi. Saat Anda menggunakan kata kunci JavaScript "this", ini merujuk ke objek yang memiliki fungsi. Misalnya, di dalam suatu fungsi, ketika Anda mengatakan: "this.accoutNumber", Anda merujuk ke properti "accoutNumber", yang menjadi milik objek yang memiliki fungsi itu.

Jika objek "myObj" memiliki metode yang disebut "getMyName", ketika kata kunci JavaScript "this" digunakan di dalam "getMyName", itu merujuk ke "myObj". Jika fungsi "getMyName" dieksekusi dalam lingkup global, maka "ini" merujuk ke objek jendela (kecuali dalam mode ketat).

Sekarang mari kita lihat beberapa contoh:

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

Runnig abobve kode dalam output browser akan: masukkan deskripsi gambar di sini

Menurut output Anda berada di dalam konteks objek jendela, juga terlihat bahwa prototipe jendela mengacu pada Objek.

Sekarang mari kita coba bagian dalam suatu fungsi:

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

Keluaran:

masukkan deskripsi gambar di sini Outputnya sama karena kami mencatat variabel 'ini' di lingkup global dan kami mencatatnya di lingkup fungsional, kami tidak mengubah konteksnya. Dalam kedua kasus konteksnya sama, terkait dengan objek janda .

Sekarang mari kita buat objek kita sendiri. Dalam javascript, Anda dapat membuat objek dengan banyak cara.

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

Keluaran: masukkan deskripsi gambar di sini

Jadi dari contoh di atas, kami menemukan bahwa kata kunci 'ini' mengacu pada konteks baru yang terkait dengan myObj, dan myObject juga memiliki rantai prototipe ke Object.

Mari kita lempar contoh lain:

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

keluaran: Masuk akal bukan? (baca komentar) masukkan deskripsi gambar di sini

Jika Anda kesulitan memahami contoh di atas, mari kita coba dengan panggilan balik kami sendiri;

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

keluaran: masukkan deskripsi gambar di sini

Sekarang mari kita Memahami Lingkup, Diri, IIFE dan INI bagaimana berperilaku

       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> 

Outputnya cukup luar biasa bukan? masukkan deskripsi gambar di sini

Tuan
sumber
-1

Jawaban sederhana:

Kata kunci "ini" selalu tergantung pada konteks doa. Mereka disebutkan di bawah ini.

  1. FUNGSI DISEBUT DENGAN KATA KUNCI BARU

    Jika fungsinya dipanggil dengan kata kunci BARU maka INI akan terikat pada objek yang baru dibuat.

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

    Di atas ini akan terikat ke objek 'myCar'

  2. FUNGSI DISEBUT SECARA EKSPLISIT MENGGUNAKAN METODE PANGGILAN DAN APLIKASI.

    Dalam hal ini, INI akan terikat pada objek yang secara eksplisit diteruskan ke fungsi.

    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. JIKA FUNGSI DISEBUT DENGAN OBYEK SEPENUHNYA KEMUDIAN INI AKAN TERTENTU DENGAN OBYEK YANG

    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. KETIKA FUNGSI DISEBUT TANPA KONTEKS, KEMUDIAN INI AKAN TERTENTU DENGAN OBYEK GLOBAL

    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. DALAM MODE KETAT INI AKAN TIDAK DIKENAL

    function setName(name){
        "use strict"
        return this.name;
    }
    setName(); //WILL BE ERROR SAYING name IS UNDEFINED. 
PALLAMOLLA SAI
sumber