Bagaimana cara kerja kata kunci "ini"?
Saya perhatikan bahwa tampaknya tidak ada penjelasan yang jelas tentang apa this
kata kunci itu dan bagaimana kata kunci itu digunakan dengan benar (dan salah) dalam JavaScript di situs Stack Overflow.
Saya telah menyaksikan beberapa perilaku yang sangat aneh dengannya dan gagal memahami mengapa hal itu terjadi.
Bagaimana cara this
kerjanya dan kapan harus digunakan?
Jawaban
Saya sarankan membaca Mike Barat 's artikel Ruang Lingkup dalam JavaScript ( cermin ) pertama. Ini adalah pengantar yang sangat baik dan bersahabat untuk konsep this
dan rantai lingkup di JavaScript.
Begitu Anda mulai terbiasa this
, aturannya sebenarnya cukup sederhana. Standar ECMAScript 5.1 mendefinisikan this
:
§11.1.1 Kata
this
kunciKata
this
kunci mengevaluasi ke nilai ThisBinding dari konteks eksekusi saat ini
ThisBinding adalah sesuatu yang dipelihara oleh penerjemah JavaScript saat mengevaluasi kode JavaScript, seperti register CPU khusus yang menyimpan referensi ke suatu objek. Penerjemah memperbarui ThisBinding setiap kali membuat konteks eksekusi di salah 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, ThisBinding disetel ke objek global, window
( §10.4.1.1 ).
2. Memasukkan kode eval
… Dengan panggilan langsung ke
eval()
ThisBinding tidak berubah; itu 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 itu panggilan langsung eval()
. 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') di JavaScript? dan ECMA-262-5 Dmitry Soshnikov secara rinci. Bab 2. Mode Ketat. untuk saat Anda mungkin menggunakan eval()
panggilan tidak langsung .
3. Memasukkan kode fungsi
Ini terjadi saat memanggil suatu fungsi. Jika suatu fungsi dipanggil pada suatu objek, seperti in obj.myMethod()
atau padanannya obj["myMethod"]()
, maka ThisBinding diatur ke objek tersebut ( obj
dalam contoh; §13.2.1 ). Dalam kebanyakan kasus lain, ThisBinding disetel ke objek global ( §10.4.3 ).
Alasan untuk menulis "dalam kebanyakan kasus lain" adalah karena ada delapan ECMAScript 5 fungsi built-in yang memungkinkan ThisBinding ditentukan dalam daftar argumen. Fungsi-fungsi khusus ini mengambil apa yang disebut thisArg
yang menjadi ThisBinding saat 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 kasus Function.prototype
fungsi, mereka dipanggil pada objek fungsi, tetapi daripada menyetel ThisBinding ke objek fungsi, ThisBinding diatur ke thisArg
.
Dalam kasus Array.prototype
fungsi, yang diberikan callbackfn
dipanggil dalam konteks eksekusi di mana ThisBinding diatur ke thisArg
jika disediakan; jika tidak, ke objek global.
Itu adalah aturan untuk JavaScript biasa. Saat Anda mulai menggunakan pustaka JavaScript (misalnya jQuery), Anda mungkin menemukan bahwa fungsi pustaka tertentu memanipulasi nilai this
. Pengembang pustaka JavaScript tersebut melakukan ini karena cenderung mendukung kasus penggunaan yang paling umum, dan pengguna pustaka biasanya menganggap perilaku ini lebih nyaman. Saat meneruskan fungsi callback yang merujuk this
ke fungsi library, Anda harus merujuk ke dokumentasi untuk jaminan apa pun tentang berapa nilainya this
saat fungsi tersebut dipanggil.
Jika Anda bertanya-tanya bagaimana pustaka JavaScript memanipulasi nilai this
, pustaka tersebut hanya menggunakan salah satu fungsi JavaScript bawaan yang menerima a thisArg
. Anda juga dapat menulis fungsi Anda sendiri dengan menggunakan fungsi callback dan thisArg
:
function doWork(callbackfn, thisArg) {
//...
if (callbackfn != null) callbackfn.call(thisArg);
}
Ada kasus khusus yang belum saya sebutkan. Saat membuat objek baru melalui new
operator, penerjemah JavaScript membuat objek baru yang kosong, menyetel beberapa properti internal, dan kemudian memanggil fungsi konstruktor pada objek baru tersebut. Jadi, ketika sebuah fungsi dipanggil dalam konteks konstruktor, nilainya this
adalah objek baru yang dibuat oleh penerjemah:
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 di ECMA6) mengubah cakupan this
. Lihat pertanyaan kanonis yang ada, fungsi Panah vs deklarasi / ekspresi fungsi: Apakah setara / dapat ditukar? untuk informasi lebih lanjut. Tapi singkatnya:
Fungsi panah tidak memiliki
this
.... pengikatannya sendiri . Sebaliknya, pengidentifikasi tersebut diselesaikan dalam lingkup leksikal seperti variabel lainnya. Itu berarti bahwa di dalam fungsi panah,this
... merujuk ke nilai-nilaithis
di lingkungan tempat fungsi panah didefinisikan.
Hanya untuk bersenang-senang, uji pemahaman Anda dengan beberapa contoh
Untuk mengungkapkan jawabannya, arahkan mouse ke kotak abu-abu terang.
- Berapakah nilai
this
pada garis yang ditandai? Mengapa?
window
- Garis yang ditandai dievaluasi dalam konteks eksekusi global awal.
if (true) {
// What is `this` here?
}
- Berapakah nilai
this
pada garis yang ditandai ketikaobj.staticFunction()
dieksekusi? Mengapa?
obj
- Saat memanggil fungsi pada objek, ikatan 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);
- Berapakah nilai
this
pada garis yang ditandai? Mengapa?
window
Dalam contoh ini, penerjemah JavaScript memasukkan kode fungsi, tetapi karena
myFun
/obj.myMethod
tidak dipanggil pada objek, ThisBinding disetel kewindow
.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);
- Berapakah nilai
this
pada garis yang ditandai? Mengapa?
window
Yang ini rumit. Saat mengevaluasi kode eval,
this
adalahobj
. Namun, dalam kode eval,myFun
tidak dipanggil pada suatu objek, jadi ThisBinding disetel kewindow
untuk panggilan tersebut.
<!-- no snippet because, seemingly, eval doesn’t work in snippets -->
function myFun() {
return this; // What is `this` here?
}
var obj = {
myMethod: function () {
eval("myFun()");
}
};
- Berapakah nilai
this
pada garis yang ditandai? Mengapa?
obj
Baris
myFun.call(obj);
tersebut memanggil fungsi bawaan khususFunction.prototype.call()
, yang menerimathisArg
sebagai 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);
Kata this
kunci berperilaku berbeda di JavaScript dibandingkan dengan bahasa lain. Dalam bahasa Berorientasi Objek, this
kata kunci mengacu pada instance kelas saat ini. Dalam JavaScript, nilai this
ditentukan oleh konteks pemanggilan function ( context.function()
) dan tempat pemanggilannya .
1. Saat digunakan dalam konteks global
Saat Anda menggunakan this
dalam konteks global, itu terikat ke objek global ( window
di browser)
document.write(this); //[object Window]
Ketika Anda menggunakan this
di dalam fungsi yang didefinisikan dalam konteks global, this
masih terikat ke objek global karena fungsi tersebut sebenarnya membuat metode konteks global.
function f1()
{
return this;
}
document.write(f1()); //[object Window]
Di atas f1
dibuat metode objek global. Jadi kita juga bisa memanggilnya pada window
objek sebagai berikut:
function f()
{
return this;
}
document.write(window.f()); //[object Window]
2. Saat digunakan di dalam metode objek
Ketika Anda menggunakan this
kata kunci di dalam metode objek, this
terikat ke objek yang melingkupi "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 menumpuk objek di dalam objek lain, maka this
terikat ke induk langsung.
var obj = {
name: "obj1",
nestedobj: {
name:"nestedobj",
f: function () {
return this + ":" + this.name;
}
}
}
document.write(obj.nestedobj.f()); //[object Object]:nestedobj
Meskipun Anda menambahkan fungsi secara eksplisit ke objek sebagai metode, itu masih mengikuti aturan di atas, yang this
masih mengarah 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 tanpa konteks
Saat Anda menggunakan this
fungsi di dalam yang dipanggil tanpa konteks apa pun (yaitu bukan pada objek apa pun), itu terikat ke objek global ( window
di browser) (bahkan jika fungsi itu 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 literal objek. Kita dapat menambahkan anggota ke fungsi dengan menggunakan
this
. untuk menentukannya. - Notasi literal objek membuat turunan dari objek yang dapat kita gunakan segera. Dengan fungsi kita mungkin perlu membuat instance-nya terlebih dahulu menggunakan
new
operator. - Juga dalam pendekatan literal objek, kita dapat secara eksplisit menambahkan anggota ke objek yang sudah ditentukan menggunakan operator titik. Ini akan ditambahkan ke contoh tertentu saja. Namun saya telah menambahkan variabel ke prototipe fungsi sehingga itu tercermin dalam semua contoh fungsi.
Di bawah ini saya mencoba semua hal yang kami lakukan dengan Object dan di this
atasnya, tetapi dengan terlebih dahulu membuat fungsi alih-alih 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 (yaitu ketika dipanggil dengan new
kata kunci), this
bagian dalam badan fungsi 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. Ketika digunakan fungsi di dalam yang didefinisikan pada rantai prototipe
Jika metode berada pada rantai prototipe objek, this
di dalam metode tersebut mengacu pada objek tempat 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. Di dalam fungsi call (), apply () dan bind ()
- Semua metode ini didefinisikan di
Function.prototype
. - Metode ini memungkinkan untuk menulis fungsi satu kali dan memanggilnya dalam konteks yang berbeda. Dengan kata lain, mereka memungkinkan untuk menentukan nilai
this
yang akan digunakan saat fungsi sedang dijalankan. Mereka juga mengambil parameter apa pun untuk diteruskan ke fungsi asli saat dipanggil. fun.apply(obj1 [, argsArray])
Menyetelobj1
sebagai nilaithis
insidefun()
dan memanggilfun()
elemen yang lewatargsArray
sebagai argumennya.fun.call(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Ditetapkanobj1
sebagai nilaithis
insidefun()
dan panggilan yangfun()
lewatarg1, arg2, arg3, ...
sebagai argumennya.fun.bind(obj1 [, arg1 [, arg2 [,arg3 [, ...]]]])
- Mengembalikan referensi ke fungsifun
denganthis
kesenangan di dalam terikatobj1
dan parameterfun
terikat ke parameter yang ditentukanarg1, arg2, arg3,...
.- Sekarang perbedaan antara
apply
,call
danbind
pasti sudah menjadi jelas.apply
memungkinkan untuk menetapkan argumen agar berfungsi sebagai objek mirip larik, yaitu objek denganlength
properti numerik dan properti bilangan bulat non-negatif yang sesuai. Sedangkancall
memungkinkan untuk menentukan argumen ke fungsi secara langsung. Keduanyaapply
dancall
segera memanggil fungsi dalam konteks yang ditentukan dan dengan argumen yang ditentukan. Di sisi lain,bind
cukup kembalikan fungsi yang terikat ke nilai yang ditentukanthis
dan argumen. Kita bisa menangkap referensi ke fungsi yang dikembalikan ini dengan menugaskannya ke variabel dan nanti kita bisa 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. this
penanganan acara di dalam
- Saat Anda menetapkan fungsi secara langsung ke penangan peristiwa suatu elemen, penggunaan
this
langsung di dalam fungsi penanganan peristiwa merujuk ke elemen yang sesuai. Penugasan fungsi langsung tersebut dapat dilakukan dengan menggunakanaddeventListener
metode atau melalui metode pendaftaran acara tradisional sepertionclick
. - Demikian pula, saat Anda menggunakan
this
langsung di dalam properti event (seperti<button onclick="...this..." >
) elemen, ini merujuk ke elemen. - Namun penggunaan
this
secara tidak langsung melalui fungsi lain yang dipanggil di dalam fungsi penanganan acara atau properti acara menyelesaikan objek globalwindow
. - Perilaku yang sama di atas dicapai ketika kita melampirkan fungsi ke event handler menggunakan metode model Pendaftaran Peristiwa Microsoft
attachEvent
. Alih-alih menetapkan fungsi ke event handler (dan dengan demikian membuat metode fungsi elemen), ia memanggil fungsi pada acara (secara efektif memanggilnya dalam konteks global).
Saya sarankan untuk lebih baik mencoba ini 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. this
dalam fungsi panah ES6
Dalam fungsi panah, this
akan berperilaku seperti variabel umum: itu akan diwarisi dari ruang lingkup leksikal. Fungsi this
, di mana fungsi panah ditentukan, akan menjadi fungsi panah this
.
Jadi, itu perilaku yang sama seperti:
(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
Javascript this
Pemanggilan 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 dijalankan di browser, nilai this
akan dicatat sebagai window
. Ini karena window
variabel global dalam lingkup browser web.
Jika Anda menjalankan bagian kode yang sama ini di lingkungan seperti node.js, this
akan merujuk ke variabel global di aplikasi Anda.
Sekarang jika kita menjalankan ini dalam mode ketat dengan menambahkan pernyataan "use strict";
ke awal deklarasi fungsi, this
tidak akan lagi merujuk ke variabel global di salah satu lingkungan. Ini dilakukan untuk menghindari kebingungan dalam mode ketat. this
akan, dalam hal ini hanya log undefined
, karena itu apa adanya, itu tidak didefinisikan.
Dalam kasus berikut, kita akan melihat bagaimana memanipulasi nilai this
.
Memanggil fungsi pada suatu objek
Ada berbagai cara untuk melakukan ini. Jika Anda telah memanggil metode asli dalam Javascript like forEach
and slice
, Anda seharusnya sudah tahu bahwa this
variabel dalam kasus itu mengacu Object
pada yang Anda panggil fungsi itu (Perhatikan bahwa dalam javascript, hampir semuanya adalah an Object
, termasuk Array
s dan Function
s). Ambil kode berikut ini sebagai contoh.
var myObj = {key: "Obj"};
myObj.logThis = function () {
// I am a method
console.log(this);
}
myObj.logThis(); // myObj is logged
Jika sebuah Object
berisi properti yang menampung Function
, properti itu disebut metode. Metode ini, ketika dipanggil, akan selalu this
mengatur variabelnya ke variabel Object
terkait. Ini berlaku untuk mode ketat dan non-ketat.
Perhatikan bahwa jika metode disimpan (atau lebih tepatnya, disalin) di variabel lain, referensi ke this
tidak lagi disimpan 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 praktis:
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 new
kunci
Pertimbangkan fungsi konstruktor di 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? Nah, mari kita lihat apa yang terjadi saat kita menggunakan new
kata kunci tersebut.
- Memanggil fungsi dengan
new
kata kunci akan segera menginisialisasi sebuahObject
tipePerson
. - Konstruktor ini
Object
memiliki konstruktornya disetel kePerson
. Juga, perhatikan bahwa hanyatypeof awal
akan kembaliObject
. Object
Prototipe baru ini akan diberiPerson.prototype
. Ini berarti bahwa metode atau properti apa pun dalamPerson
prototipe akan tersedia untuk semua instancePerson
, termasukawal
.- Fungsi
Person
itu sendiri sekarang dipanggil;this
menjadi referensi ke objek yang baru dibangunawal
.
Cukup mudah, eh?
Perhatikan bahwa spesifikasi ECMAScript resmi tidak menyatakan bahwa jenis fungsi seperti itu adalah constructor
fungsi sebenarnya . Ini hanyalah fungsi normal, dan new
dapat digunakan pada fungsi apa pun. Hanya saja kami menggunakannya seperti itu, jadi kami menyebutnya begitu saja.
Fungsi panggilan pada Fungsi: call
danapply
Jadi ya, karena function
s juga Objects
(dan sebenarnya variabel kelas satu dalam Javascript), bahkan fungsi memiliki metode yang ... yah, berfungsi sendiri.
Semua fungsi mewarisi dari global Function
, dan dua dari banyak metodenya adalah call
dan apply
, dan keduanya dapat digunakan untuk memanipulasi nilai this
dalam fungsi yang memanggilnya.
function foo () { console.log (this, arguments); }
var thisArg = {myObj: "is cool"};
foo.call(thisArg, 1, 2, 3);
Ini adalah contoh umum penggunaan call
. Ini pada dasarnya mengambil parameter pertama dan menetapkan this
fungsi foo
sebagai referensi thisArg
. Semua parameter lain yang diteruskan ke call
diteruskan ke fungsi foo
sebagai argumen.
Jadi kode di atas akan masuk {myObj: "is cool"}, [1, 2, 3]
ke konsol. Cara yang cukup bagus untuk mengubah nilai this
dalam fungsi apa pun.
apply
hampir sama dengan call
accept yang hanya membutuhkan dua parameter: thisArg
dan array yang berisi argumen untuk diteruskan ke fungsi. Jadi call
panggilan di atas bisa diterjemahkan apply
seperti ini:
foo.apply(thisArg, [1,2,3])
Perhatikan bahwa call
dan apply
dapat menimpa nilai this
pemanggilan metode set by dot yang telah kita diskusikan di poin kedua. Cukup sederhana :)
Mempersembahkan .... bind
!
bind
adalah saudara dari call
dan apply
. Ini juga merupakan metode yang diwarisi oleh semua fungsi dari Function
konstruktor global dalam Javascript. Perbedaan antara bind
dan call
/ apply
adalah bahwa keduanya call
dan apply
akan benar-benar menjalankan fungsi tersebut. bind
, di sisi lain, mengembalikan fungsi baru dengan thisArg
dan arguments
pra-setel. 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 di antara ketiganya? Ini halus, tetapi digunakan secara berbeda. Suka call
dan apply
, bind
juga akan mengganti nilai this
set dengan pemanggilan metode titik.
Perhatikan juga bahwa tidak satu pun dari ketiga fungsi ini melakukan perubahan apa pun ke fungsi aslinya. call
dan apply
akan mengembalikan nilai dari fungsi yang baru dibangun sementara bind
akan mengembalikan fungsi yang baru dibangun itu sendiri, siap untuk dipanggil.
Hal ekstra, salin ini
Terkadang, Anda tidak menyukai kenyataan bahwa this
berubah dengan cakupan, terutama cakupan bersarang. Lihat 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"
});
}
};
Pada kode di atas, kita melihat bahwa nilai this
diubah dengan cakupan bersarang, tetapi kita menginginkan nilai dari this
cakupan asli. Jadi kami 'menyalin' this
ke that
dan menggunakan salinannya, bukan this
. Pintar, ya?
Indeks:
- Apa yang ditahan
this
secara default? - Bagaimana jika kita memanggil fungsi tersebut sebagai metode dengan notasi Object-dot?
- Bagaimana jika kita menggunakan
new
kata kunci? - Bagaimana kita memanipulasi
this
dengancall
danapply
? - Menggunakan
bind
. - Menyalin
this
untuk memecahkan masalah cakupan bersarang.
"ini" adalah tentang ruang lingkup. Setiap fungsi memiliki ruang lingkupnya sendiri, dan karena semua yang ada 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 suatu objek. Oleh karena itu, setiap kali suatu 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; $ ('. some-elements'). each (function (elt) { elt.innerHTML = this.value; // uh oh!! mungkin tidak terdefinisi }); }) (2);
Jadi di sini, di dalam each (), "this" tidak memiliki "nilai" yang Anda harapkan (dari
this.value = value;di atasnya). Jadi, untuk mengatasi masalah ini (tidak ada permainan kata-kata), pengembang dapat:
(fungsi (nilai) { var self = ini; // uang receh self.value = nilai; $ ('. some-elements'). each (function (elt) { elt.innerHTML = self.value; // Fiuh !! == 2 }); }) (2);
Cobalah; Anda akan mulai menyukai pola pemrograman ini
Sejak utas ini naik, saya telah mengumpulkan beberapa poin untuk pembaca yang baru this
mengenal topik.
Bagaimana nilai this
ditentukan?
Kami menggunakan ini mirip dengan cara kami menggunakan kata ganti dalam bahasa alami seperti bahasa Inggris: “John berlari cepat karena dia mencoba mengejar kereta.” Sebaliknya kita bisa menulis "... John sedang mencoba naik 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 sebuah objek memanggil fungsi di mana ia didefinisikan. Dalam lingkup global, semua variabel dan fungsi global ditentukan pada window
objek. Oleh karena itu, this
dalam fungsi global mengacu pada (dan memiliki nilai) window
objek global .
Ketika use strict
, this
dalam fungsi global dan anonim yang tidak terikat ke objek apa pun memiliki nilai undefined
.
Kata this
kunci paling disalahpahami ketika: 1) kami meminjam metode yang menggunakan this
, 2) kami menetapkan metode yang digunakan this
untuk variabel, 3) fungsi yang digunakan this
diteruskan sebagai fungsi panggilan balik, dan 4) this
digunakan di dalam closure - fungsi batin. (2)
Apa yang menahan masa depan
Didefinisikan dalam ECMA Script 6 , fungsi panah mengadopsi this
pengikatan dari lingkup penutup (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!
Meskipun fungsi panah memberikan alternatif untuk digunakan bind()
, penting untuk dicatat bahwa mereka pada dasarnya menonaktifkan this
mekanisme tradisional untuk mendukung pelingkupan leksikal yang lebih dipahami secara luas. (1)
Referensi:
- ini & Prototipe Objek , oleh Kyle Simpson. © 2014 Getify Solutions.
- javascriptissexy.com - http://goo.gl/pvl0GX
- Angus Croll - http://goo.gl/Z2RacU
this
dalam JavaScript selalu mengacu pada 'pemilik' dari fungsi yang sedang dijalankan .
Jika tidak ada pemilik eksplisit yang ditentukan, maka pemilik paling atas, objek jendela, direferensikan.
Jadi jika saya melakukannya
function someKindOfFunction() {
this.style = 'foo';
}
element.onclick = someKindOfFunction;
this
akan merujuk ke objek elemen. Tapi hati-hati, banyak orang yang melakukan kesalahan ini.
<element onclick="someKindOfFunction()">
Dalam kasus terakhir, Anda hanya mereferensikan fungsi, bukan menyerahkannya ke elemen. Oleh karena itu, this
akan mengacu pada objek jendela.
Setiap konteks eksekusi dalam javascript memiliki parameter ini yang disetel oleh:
- Bagaimana fungsi dipanggil (termasuk sebagai metode objek, penggunaan panggilan dan penerapan , penggunaan baru )
- Penggunaan bind
- Secara leksikal untuk fungsi panah (mereka mengadopsi ini dari konteks eksekusi luarnya)
- Apakah kode dalam mode ketat atau non-ketat
- Apakah kode tersebut dipanggil menggunakan eval
Anda dapat mengatur nilai ini menggunakan func.call
, func.apply
atau 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 hal ini sepele untuk diubah dengan jQuery.proxy.
Daniel, penjelasan yang luar biasa! Beberapa kata tentang ini dan daftar this
penunjuk konteks eksekusi yang bagus dalam kasus penangan acara.
Dalam dua kata, this
dalam JavaScript menunjukkan objek dari siapa (atau dari konteks eksekusinya) fungsi saat ini dijalankan dan selalu hanya-baca, Anda tetap tidak dapat menyetelnya (upaya seperti itu akan berakhir dengan 'Invalid left-hand sisi dalam tugas 'pesan.
Untuk penangan peristiwa: penangan peristiwa sebaris, seperti <element onclick="foo">
, menimpa penangan lain yang terpasang sebelumnya dan sebelumnya, jadi berhati-hatilah dan lebih baik tidak sama sekali dari delegasi peristiwa sebaris. Dan terima kasih kepada Zara Alaverdyan yang menginspirasi 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)">
Berikut adalah salah satu sumber this
masuk yang bagus JavaScript
.
Berikut ringkasannya:
global ini
Di browser, pada lingkup global,
this
adalahwindow
objeknya<script type="text/javascript"> console.log(this === window); // true var foo = "bar"; console.log(this.foo); // "bar" console.log(window.foo); // "bar"
Dalam
node
menggunakan repl,this
adalah namespace teratas. Anda bisa menyebutnya sebagaiglobal
.>this { ArrayBuffer: [Function: ArrayBuffer], Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, ... >global === this true
Dalam
node
mengeksekusi dari skrip,this
pada lingkup global dimulai sebagai objek kosong. Ini tidak sama denganglobal
\\test.js console.log(this); \\ {} console.log(this === global); \\ fasle
fungsi ini
Kecuali dalam kasus penangan kejadian DOM atau ketika a thisArg
disediakan (lihat lebih jauh di bawah), baik di node dan di browser yang menggunakan this
fungsi yang tidak dipanggil dengan new
referensi cakupan 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 this
iniundefined
<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 new
yang this
akan 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 prototype
properti khusus , yang merupakan sesuatu yang dapat Anda tetapkan nilainya. Saat Anda membuat instance dengan memanggil fungsi new
Anda, Anda mendapatkan akses ke nilai yang Anda tetapkan ke prototype
properti. 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 kesalahan untuk menetapkan array atau objek pada file prototype
. Jika Anda ingin setiap instance memiliki lariknya sendiri, buatlah 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 this
fungsi 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 event handler DOM HTML, this
selalu ada referensi ke elemen DOM tempat kejadian 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 bind
konteksnya
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 meletakkan JavaScript, this
adalah referensi ke elemen.
<div id="foo" onclick="console.log(this);"></div>
<script type="text/javascript">
document.getElementById("foo").click(); //logs <div id="foo"...
</script>
- evaluasi ini
Anda dapat menggunakan eval
untuk 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 with
untuk menambah this
cakupan saat ini untuk membaca dan menulis ke nilai this
tanpa merujuk this
secara 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 di banyak tempat akan this
merujuk 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>
Ada banyak kebingungan tentang bagaimana kata kunci "ini" diinterpretasikan dalam JavaScript. Mudah-mudahan artikel ini akan meletakkan semua itu untuk beristirahat sekali dan untuk selamanya. Dan masih banyak lagi. Harap baca seluruh artikel dengan cermat. Diperingatkan bahwa artikel ini panjang.
Terlepas dari konteks penggunaannya, "ini" selalu merujuk pada "objek saat ini" dalam Javascript. Namun, apa yang dimaksud dengan "objek saat ini" berbeda menurut konteksnya . The konteks mungkin persis 1 dari 6 berikut:
- Global (yaitu Di luar semua fungsi)
- Panggilan Inside Direct "Non Bound Function" (yaitu fungsi yang belum terikat dengan memanggil functionName.bind )
- Inside Indirect "Fungsi Tidak Terikat" Panggil melalui functionName.call dan functionName.apply
- Di dalam Panggilan "Bound Function" (yaitu fungsi yang telah diikat dengan memanggil functionName.bind )
- Sementara Pembuatan Objek melalui "baru"
- Di dalam event handler DOM Inline
Uraian berikut menjelaskan setiap konteks ini satu per satu:
Konteks Global (yaitu Di luar semua fungsi):
Di luar semua fungsi (yaitu dalam konteks global) "objek saat ini" (dan karenanya nilai "ini" ) selalu merupakan objek "jendela" untuk browser.
Panggilan Inside Direct "Fungsi Tidak Terikat" :
Di dalam Panggilan "Fungsi Tidak Terikat" Langsung, objek yang memanggil panggilan fungsi menjadi "objek saat ini" (dan karenanya menjadi nilai "ini" ). Jika suatu fungsi dipanggil tanpa objek saat ini eksplisit , objek saat ini adalah objek "jendela" (Untuk Mode Non Ketat) atau tidak ditentukan (Untuk Mode Ketat). Setiap fungsi (atau variabel) yang didefinisikan dalam Konteks Global secara otomatis menjadi properti dari objek "jendela". Misalnya Misalkan fungsi 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 secara langsung melalui "UserDefinedFunction ()" akan secara otomatis memanggil / memanggilnya sebagai "window.UserDefinedFunction ()" membuat "jendela" sebagai "objek saat ini" (dan karenanya nilai " ini " ) dalam " UserDefinedFunction ". Memasukkan fungsi ini dalam" Non Strict Mode "akan menghasilkan
UserDefinedFunction() // displays [object Window] as it automatically gets invoked as window.UserDefinedFunction()
Dalam "Strict Mode", Memanggil / Memanggil fungsi secara langsung melalui "UserDefinedFunction ()" akan "TIDAK" secara otomatis memanggil / memanggilnya sebagai "window.UserDefinedFunction ()". Oleh karena itu, "objek saat ini" (dan nilai "ini" ) dalam "UserDefinedFunction" tidak akan ditentukan . Memanggil fungsi ini dalam "Mode Ketat" akan menghasilkan hal berikut
UserDefinedFunction() // displays undefined
Namun, memanggilnya secara eksplisit menggunakan objek jendela akan menghasilkan sebagai berikut
window.UserDefinedFunction() // "always displays [object Window] irrespective of mode."
Mari kita lihat contoh lainnya. 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 menentukan 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.
Panggil "Fungsi Tidak Terikat" Di Dalam Tidak Langsung melalui functionName.call dan functionName.apply :
Ketika "Fungsi Tidak Terikat" dipanggil melalui functionName.call atau functionName.apply , "objek saat ini" (dan karenanya nilai "ini" ) disetel ke nilai parameter "ini" (parameter pertama) yang diteruskan ke panggilan / terapkan . 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 setiap "Fungsi NON Bound" dapat diubah melalui panggilan / penerapan . Selain itu, jika parameter "ini" tidak secara eksplisit diteruskan ke panggilan / penerapan , "objek saat ini" (dan karenanya nilai "ini") disetel ke "jendela" dalam mode Tidak ketat dan "tidak ditentukan" dalam mode ketat.
Di dalam Panggilan "Bound Function" (yaitu fungsi yang telah diikat dengan memanggil functionName.bind ):
Fungsi terikat adalah fungsi yang nilai "ini" -nya telah diperbaiki. Kode berikut menunjukkan bagaimana "ini" bekerja dalam kasus 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 setiap "Fungsi Terikat" TIDAK DAPAT diubah melalui panggilan / penerapan . Selain itu, jika parameter "ini" tidak secara eksplisit dikirimkan untuk mengikat, "objek saat ini" (dan karenanya nilai "ini" ) disetel ke "jendela" dalam mode Tidak ketat dan "tidak ditentukan" dalam mode ketat. Satu hal lagi. Mengikat fungsi yang sudah terikat tidak mengubah nilai "ini" . Ini tetap ditetapkan sebagai nilai yang ditetapkan oleh fungsi mengikat pertama.
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 tersebut. Namun jika konstruktor adalah fungsi terikat, ia akan dipanggil dengan set argumen yang telah ditentukan sebagai set untuk fungsi terikat.
Di dalam event handler DOM Inline :
Silakan lihat Snippet 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.
Dalam contoh pertama, warna font tombol akan disetel menjadi putih saat diklik.
Dalam contoh kedua ketika elemen "div" diklik, itu akan memanggil fungsi OnDivClick dengan parameter kedua yang mereferensikan elemen div yang diklik. Namun nilai "ini" dalam OnDivClick TIDAK AKAN mereferensikan elemen div yang diklik . Ini akan ditetapkan sebagai "objek window" atau "tidak terdefinisi" di Non ketat dan ketat Mode masing-masing (jika OnDivClick adalah fungsi terikat ) atau set ke nilai Bound telah ditetapkan (jika OnDivClick adalah fungsi terikat )
Berikut ini ringkasan keseluruhan artikel
Global Context "ini" selalu mengacu pada "jendela" objek
Setiap kali suatu fungsi dipanggil, itu dipanggil dalam konteks objek ( "objek saat ini" ). Jika objek saat ini tidak disediakan secara eksplisit, objek saat ini adalah "objek jendela" dalam Mode Ketat NON dan "tidak ditentukan" dalam Mode Ketat secara default.
Nilai "ini" dalam fungsi Tidak Terikat adalah referensi ke objek dalam konteks di mana fungsi tersebut dipanggil ( "objek saat ini" )
Nilai "ini" dalam fungsi Tidak Terikat dapat diganti dengan memanggil dan menerapkan metode fungsi.
Nilai "ini" ditetapkan untuk fungsi Terikat dan tidak dapat diganti dengan metode panggilan dan penerapan fungsi.
Fungsi mengikat dan sudah terikat tidak mengubah nilai "ini". Ini tetap ditetapkan sebagai nilai yang ditetapkan oleh fungsi mengikat pertama.
Nilai "ini" dalam konstruktor adalah objek yang dibuat dan diinisialisasi
Nilai "ini" dalam pengendali kejadian DOM sebaris merujuk ke elemen yang diberikan pengendali kejadian.
Mungkin artikel paling rinci dan komprehensif tentang this
adalah sebagai berikut:
Penjelasan lembut tentang kata kunci 'ini' dalam JavaScript
Ide di baliknya this
adalah untuk memahami bahwa jenis pemanggilan fungsi memiliki kepentingan yang signifikan dalam menetapkan this
nilai.
Saat mengalami kesulitan mengidentifikasi this
, jangan tanyakan pada diri Anda:
Dari mana
this
diambil ?
tapi jangan bertanya pada diri sendiri:
Bagaimana fungsi tersebut dipanggil ?
Untuk fungsi panah (kasus khusus transparansi konteks) tanyakan pada diri Anda:
Nilai apa yang memiliki
this
fungsi panah didefinisikan ?
Pola pikir ini benar saat menghadapi this
dan akan menyelamatkan Anda dari sakit kepala.
Ini adalah penjelasan terbaik yang pernah saya lihat: Pahami JavaScripts ini dengan Kejelasan
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 saat kita menggunakan mode ketat, ini memegang nilai tak terdefinisi dalam fungsi global dan fungsi anonim yang tidak terikat ke objek apa pun.
Ada Empat Skenario mana ini dapat membingungkan:
- Ketika kita mengirimkan metode (yang menggunakan ini ) sebagai argumen untuk digunakan sebagai fungsi panggilan balik.
- Saat kita menggunakan fungsi bagian dalam (penutupan). Penting untuk diperhatikan bahwa closures tidak dapat mengakses fungsi luar variabel ini dengan menggunakan kata kunci ini karena variabel ini hanya dapat diakses oleh fungsi itu sendiri, bukan oleh fungsi dalam.
- Ketika metode yang bergantung pada ini ditetapkan ke variabel di seluruh konteks, dalam hal ini referensi objek lain dari yang dimaksudkan semula.
- Saat menggunakan ini bersama dengan metode bind, apply, dan call.
Dia memberikan contoh kode, penjelasan, dan solusi, yang menurut saya sangat membantu.
this
adalah salah satu konsep yang disalahpahami dalam JavaScript karena perilakunya sedikit berbeda dari satu tempat ke tempat lain. Sederhananya, this
mengacu pada "pemilik" dari fungsi yang sedang kita jalankan .
this
membantu untuk mendapatkan objek saat ini (alias konteks eksekusi) yang kita kerjakan. Jika Anda memahami di objek mana fungsi saat ini dijalankan, Anda dapat dengan mudah memahami apa itu saat this
ini
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 kami membuat 3 variabel dengan nama yang sama 'val'. Satu dalam konteks global, satu di dalam obj dan yang lainnya di dalam innerMethod of obj. JavaScript menyelesaikan pengenal dalam konteks tertentu dengan menaikkan rantai cakupan dari lokal go global.
Beberapa tempat yang this
bisa 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
Saat baris1 dijalankan, JavaScript membuat konteks eksekusi (EC) untuk pemanggilan fungsi, menyetel this
ke objek yang direferensikan oleh apa pun yang datang sebelum "." . jadi di baris terakhir Anda dapat memahami bahwa a()
dieksekusi dalam konteks global yaitu file 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
Saat new Person()
dijalankan, objek yang benar-benar baru dibuat. Person
dipanggil dan this
disetel untuk mereferensikan 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 melewatkan new
kata kunci, whatIsThis
lihat konteks paling global yang dapat ditemukannya ( window
)
Dengan penangan acara
Jika pengendali kejadian sebaris, this
mengacu pada 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 peristiwa melalui JavaScript, this
mengacu pada elemen DOM yang menghasilkan peristiwa tersebut.
- Anda juga dapat memanipulasi konteks menggunakan
.apply()
.call()
dan.bind()
- Proksi JQuery adalah cara lain yang dapat Anda gunakan untuk memastikan ini dalam suatu fungsi akan menjadi nilai yang Anda inginkan. (Periksa Memahami penggunaan $ .proxy () , jQuery.proxy () )
- Apa var that = thisartinya di JavaScript
Dalam istilah pseudoklasik, cara banyak kuliah mengajarkan kata kunci 'ini' adalah sebagai objek yang dipakai oleh kelas atau konstruktor objek. Setiap kali objek baru dibangun dari sebuah kelas, bayangkan bahwa di bawah tenda 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;
Nilai "ini" bergantung pada "konteks" tempat fungsi tersebut dijalankan. Konteksnya dapat berupa objek apa pun atau objek global, yaitu jendela.
Jadi Semantik dari "ini" berbeda dari bahasa OOP tradisional. Dan itu menyebabkan masalah: 1. ketika suatu fungsi dilewatkan ke variabel lain (kemungkinan besar, callback); dan 2. ketika closure dipanggil dari metode anggota kelas.
Dalam kedua kasus, ini disetel ke jendela.
Apa yang bisa membantu ini ? (Sebagian besar kebingungan 'ini' di javascript berasal dari fakta bahwa itu umumnya tidak terkait dengan objek Anda, tetapi ke ruang lingkup eksekusi saat ini - itu mungkin tidak persis seperti cara kerjanya tetapi selalu terasa seperti itu bagi saya - lihat artikel untuk penjelasan lengkapnya)
Sedikit info tentang kata kunci ini
Mari catat this
kata kunci ke konsol dalam lingkup global tanpa kode lagi selain
console.log(this)
Dalam Client / Browser this
kata kunci adalah obyek global yaituwindow
console.log(this === window) // true
dan
Dalam Server / Node / Javascript runtime this
kata kunci juga merupakan objek global yangmodule.exports
console.log(this === module.exports) // true
console.log(this === exports) // true
Yang perlu diingat exports
hanyalah referensi kemodule.exports
ini digunakan untuk Scope 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 pada contoh di atas $ (this) = $ ('# tbleName tbody tr') sama
Saya memiliki pandangan berbeda this
dari jawaban lain yang saya harap bermanfaat.
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 nilai yang diberikan objectForThis
.
Yang lainnya adalah untuk gula sintaksis functionObject.call
Jadi, segala sesuatu yang lain dapat dijelaskan dengan cara menerjemahkannya ke dalam functionObject.call
.
Jika Anda hanya memanggil suatu fungsi maka this
adalah "objek global" yang di browser adalah jendela
function foo() {
console.log(this);
}
foo(); // this is the window object
Dengan kata lain,
foo();
diterjemahkan secara efektif ke dalam
foo.call(window);
Perhatikan bahwa jika Anda menggunakan mode ketat maka this
akanundefined
'use strict';
function foo() {
console.log(this);
}
foo(); // this is the window object
yang berarti
Dengan kata lain,
foo();
diterjemahkan secara efektif ke dalam
foo.call(undefined);
Di JavaScript ada operator seperti +
dan -
dan *
. Ada juga operator titik.
The .
Operator bila digunakan dengan fungsi di sebelah kanan dan objek di sebelah kiri secara efektif berarti "lulus objek sebagai this
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 memberikan 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 hanya untuk gula sintaksis
{ const temp = bar.fn1; temp.call(bar); }
{ const temp = bar.fn2; temp.call(bar); }
{ const temp = bar.fn3; temp.call(bar); }
Kerutan lainnya adalah rantai prototipe. Saat Anda menggunakan a.b
JavaScript, pertama-tama, lihat objek yang direferensikan secara langsung oleh a
untuk properti tersebut b
. Jika b
tidak ditemukan pada objek maka JavaScript akan mencari di prototipe objek untuk menemukannya b
.
Ada berbagai cara untuk mendefinisikan prototipe objek, yang paling umum di tahun 2019 adalah class
kata kunci. Untuk tujuan this
meskipun itu tidak masalah. Yang penting adalah seperti yang terlihat di objek a
untuk properti b
jika menemukan properti b
pada objek atau dalam rantai prototipe itu jika b
akhirnya menjadi fungsi maka aturan yang sama seperti di atas berlaku. b
Referensi fungsi akan dipanggil menggunakan call
metode dan meneruskan a
sebagai objectForThis seperti yang ditunjukkan di bagian atas jawaban ini.
Sekarang. Mari kita bayangkan kita membuat sebuah fungsi yang secara eksplisit disetel this
sebelum 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();
Mengikuti terjemahan untuk digunakan call
, obj.bar()
menjadi const temp = obj.bar; temp.call(obj);
. Ketika kita memasuki bar
fungsi yang kita panggil foo
tetapi kita secara eksplisit mengirimkan objek lain untuk objectForThis jadi ketika kita tiba di foo this
adalah objek dalam itu.
Inilah yang dilakukan oleh keduanya bind
dan =>
fungsi secara efektif. Mereka lebih banyak gula sintaksis. Mereka secara efektif membangun fungsi baru yang tidak terlihat persis seperti di bar
atas yang secara eksplisit ditetapkan this
sebelum memanggil fungsi apa pun yang ditentukan. Dalam kasus mengikat this
diatur ke apa pun yang Anda berikan 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.bind
tidak ada kita bisa membuatnya 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 baru yang tidak terlihat dibuat yang memanggil fungsi yang diberikan dengan nilai terikat objectForThis
tetapi tidak seperti bind
objek yang akan diikat, bersifat implisit. Apapun yang this
terjadi ketika =>
operator digunakan.
Jadi, 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()
diterjemahkan const temp = obj.foo; temp.call(obj);
yang berarti operator panah di dalam foo
akan mengikat obj
ke fungsi tak terlihat baru dan mengembalikan fungsi tak terlihat baru yang ditetapkan ke b
. b()
akan bekerja seperti biasa b.call(window)
atau b.call(undefined)
memanggil fungsi tak terlihat baru yang foo
dibuat. Fungsi tak terlihat itu mengabaikan yang this
diteruskan ke dalamnya dan diteruskan obj
sebagai 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 ke dalam
functionName.call(objectForThis, ...arrayOfArgs);
Ringkasan this
Javascript:
- Nilai
this
ditentukan oleh bagaimana fungsi tersebut dipanggil tidak, di mana ia dibuat! - Biasanya nilai
this
ditentukan oleh Objek yang berada di kiri titik. (window
di ruang global) - Dalam event listener, nilai
this
merujuk ke elemen DOM tempat kejadian dipanggil. - Ketika dalam fungsi dipanggil dengan
new
kata kunci nilaithis
merujuk ke objek yang baru dibuat - Anda dapat memanipulasi nilai
this
dengan 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 pemroses 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.
Untuk memahami "ini" dengan benar, seseorang harus memahami konteks dan ruang lingkup serta perbedaan di antara keduanya.
Lingkup : Dalam lingkup javascript terkait dengan visibilitas variabel, ruang lingkup dicapai melalui penggunaan fungsi. (Baca lebih lanjut tentang ruang lingkup)
Konteks : Konteks berhubungan dengan objek. Ini mengacu pada objek yang dimiliki suatu fungsi. Saat Anda menggunakan JavaScript kata kunci "ini", ini merujuk ke objek yang memiliki fungsi. Misalnya, di dalam suatu fungsi, saat Anda mengatakan: "this.accoutNumber", Anda merujuk ke properti "accoutNumber", yang dimiliki oleh objek yang memiliki fungsi tersebut.
Jika objek "myObj" memiliki metode yang disebut "getMyName", saat kata kunci JavaScript "ini" digunakan di dalam "getMyName", ini merujuk ke "myObj". Jika fungsi "getMyName" dijalankan 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>
Kode runnig abobve dalam output browser akan:
Menurut output Anda berada di dalam konteks objek jendela, juga terlihat bahwa prototipe jendela mengacu pada Objek.
Sekarang mari kita coba di dalam sebuah fungsi:
<script>
function myFunc(){
console.log('What is this: '+this);
console.log(this);
}
myFunc();
</script>
Keluaran:
Sekarang mari 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:
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 Objek.
Mari kita berikan 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 kan? (baca komentar)
Jika Anda kesulitan memahami contoh di atas, mari coba dengan callback kita 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:
Sekarang mari kita Pahami Cakupan, Diri, HIDUP 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 mengagumkan bukan?