Saya baru saja menemukan situasi yang menarik dalam JavaScript. Saya memiliki kelas dengan metode yang mendefinisikan beberapa objek menggunakan notasi objek-literal. Di dalam benda-benda itu, this
pointer sedang digunakan. Dari perilaku program, saya telah menyimpulkan bahwa this
pointer merujuk ke kelas di mana metode itu dipanggil, dan bukan objek yang dibuat oleh literal.
Ini tampaknya sewenang-wenang, meskipun itu adalah cara yang saya harapkan akan berhasil. Apakah perilaku ini didefinisikan? Apakah ini lintas browser aman? Adakah alasan yang melatarbelakangi mengapa hal itu berada di luar "spesifikasi kata" (misalnya, apakah ini merupakan konsekuensi dari beberapa keputusan / filosofi desain yang lebih luas)? Contoh kode yang diturunkan:
// inside class definition, itself an object literal, we have this function:
onRender: function() {
this.menuItems = this.menuItems.concat([
{
text: 'Group by Module',
rptletdiv: this
},
{
text: 'Group by Status',
rptletdiv: this
}]);
// etc
}
var signup = { onLoadHandler:function(){ console.log(this); return Type.createDelegate(this,this._onLoad); }, _onLoad: function (s, a) { console.log("this",this); }};
Jawaban:
Dibatalkan dari pos saya yang lain, ini lebih dari yang ingin Anda ketahui tentang ini .
Sebelum saya mulai, inilah hal paling penting untuk diingat tentang Javascript, dan untuk mengulangi diri Anda ketika itu tidak masuk akal. Javascript tidak memiliki kelas (ES6
class
adalah gula sintaksis ). Jika sesuatu terlihat seperti kelas, itu trik yang cerdas. Javascript memiliki objek dan fungsi . (Itu tidak 100% akurat, fungsi hanyalah objek, tetapi kadang-kadang bisa berguna untuk menganggapnya sebagai hal yang terpisah)The ini variabel melekat fungsi. Setiap kali Anda menjalankan fungsi, ini diberi nilai tertentu, tergantung pada bagaimana Anda menjalankan fungsi. Ini sering disebut pola doa.
Ada empat cara untuk menjalankan fungsi dalam javascript. Anda dapat memanggil fungsi sebagai metode , sebagai fungsi , sebagai konstruktor , dan dengan menerapkan .
Sebagai Metode
Metode adalah fungsi yang dilampirkan ke objek
Ketika dipanggil sebagai metode, ini akan terikat ke objek fungsi / metode adalah bagian dari. Dalam contoh ini, ini akan terikat ke foo.
Sebagai Fungsi
Jika Anda memiliki fungsi yang berdiri sendiri, variabel ini akan terikat ke objek "global", hampir selalu objek jendela dalam konteks browser.
Ini mungkin yang membuat Anda tersandung , tetapi jangan merasa buruk. Banyak orang menganggap ini keputusan desain yang buruk. Karena panggilan balik dipanggil sebagai fungsi dan bukan sebagai metode, itu sebabnya Anda melihat apa yang tampak sebagai perilaku yang tidak konsisten.
Banyak orang mengatasi masalah dengan melakukan sesuatu seperti, um, ini
Anda mendefinisikan variabel yang yang menunjuk ke ini . Penutupan (topik semua itu sendiri) terus yang di sekitar, jadi jika Anda menelepon bar sebagai callback, masih memiliki referensi.
CATATAN: Dalam
use strict
mode jika digunakan sebagai fungsi,this
tidak terikat ke global. (Yaituundefined
).Sebagai Konstruktor
Anda juga dapat menjalankan fungsi sebagai konstruktor. Berdasarkan konvensi penamaan yang Anda gunakan (TestObject) ini juga mungkin apa yang Anda lakukan dan apa yang membuat Anda tersandung .
Anda memanggil fungsi sebagai Konstruktor dengan kata kunci baru.
Ketika dipanggil sebagai konstruktor, Obyek baru akan dibuat, dan ini akan terikat ke objek itu. Sekali lagi, jika Anda memiliki fungsi dalam dan mereka digunakan sebagai callback, Anda akan memanggil mereka sebagai fungsi, dan ini akan terikat pada objek global. Gunakan var itu = trik / pola ini.
Beberapa orang berpikir konstruktor / kata kunci baru adalah tulang yang dilemparkan ke Jawa / programmer OOP tradisional sebagai cara untuk membuat sesuatu yang mirip dengan kelas.
Dengan Metode Terapkan
Akhirnya, setiap fungsi memiliki metode (ya, fungsi adalah objek dalam Javascript) bernama "apply". Terapkan memungkinkan Anda menentukan apa nilai ini akan, dan juga memungkinkan Anda mengirimkan array argumen. Ini contoh yang tidak berguna.
sumber
this
akanundefined
untuk pemanggilan fungsi.this
tidak ada hubungannya dengan ruang lingkup. Maksud Anda objek global .this.confusing = 'hell yeah';
sama denganvar confusing = 'hell yeah';
? Jadi keduanya akan memungkinkanmyObject.confusing
? Akan lebih baik jika tidak hanya agar Anda dapat menggunakanthis
untuk membuat properti dan variabel lain untuk pekerjaan internal.function Foo(thought){ this.confusing = thought; }
dan kemudianvar myObject = new Foo("hell yeah");
Panggilan fungsi
Fungsi hanyalah jenis Objek.
Semua objek fungsi memiliki panggilan dan menerapkan metode yang mengeksekusi objek fungsi mereka dipanggil.
Saat dipanggil, argumen pertama ke metode ini menentukan objek yang akan direferensikan oleh
this
kata kunci selama eksekusi Fungsi - apakah itunull
atauundefined
, objek globalwindow
, digunakan untukthis
.Dengan demikian, memanggil Fungsi ...
... dengan tanda kurung -
foo()
- sama denganfoo.call(undefined)
ataufoo.apply(undefined)
, yang secara efektif sama denganfoo.call(window)
ataufoo.apply(window)
.Argumen tambahan untuk
call
diteruskan sebagai argumen untuk panggilan fungsi, sedangkan argumen tambahan tunggal untukapply
dapat menentukan argumen untuk panggilan fungsi sebagai objek seperti Array.Dengan demikian,
foo(1, 2, 3)
sama denganfoo.call(null, 1, 2, 3)
ataufoo.apply(null, [1, 2, 3])
.Jika suatu fungsi adalah properti dari suatu objek ...
... mengakses referensi ke Fungsi melalui objek dan memanggilnya dengan tanda kurung -
obj.foo()
- sama denganfoo.call(obj)
ataufoo.apply(obj)
.Namun, fungsi yang dipegang sebagai properti objek tidak "terikat" pada objek tersebut. Seperti yang dapat Anda lihat dalam definisi di
obj
atas, karena Fungsi hanyalah jenis Objek, mereka dapat dirujuk (dan dengan demikian dapat diteruskan dengan referensi ke Panggilan fungsi atau dikembalikan dengan referensi dari Panggilan fungsi). Ketika referensi ke Fungsi dilewatkan, tidak ada informasi tambahan tentang di mana ia lulus dari dilakukan dengan itu, yang mengapa terjadi berikut:Panggilan ke referensi Fungsi kami
baz
,, tidak memberikan konteks apa pun untuk panggilan tersebut, jadi itu sama denganbaz.call(undefined)
, jadi padathis
akhirnya merujukwindow
. Jika kita inginbaz
tahu bahwa itu milikobj
, kita perlu entah bagaimana memberikan informasi itu ketikabaz
dipanggil, yang merupakan tempat argumen pertamacall
atauapply
dan penutupan ikut bermain.Rantai ruang lingkup
Ketika suatu Fungsi dieksekusi, ia menciptakan suatu lingkup baru dan memiliki referensi ke segala lingkup yang melampirkan. Ketika fungsi anonim dibuat dalam contoh di atas, ia memiliki referensi ke ruang lingkup itu dibuat, yang merupakan
bind
ruang lingkup. Ini dikenal sebagai "penutupan."Ketika Anda mencoba mengakses variabel ini, "rantai lingkup" ini berjalan untuk menemukan variabel dengan nama yang diberikan - jika cakupan saat ini tidak mengandung variabel, Anda melihat cakupan berikutnya dalam rantai, dan seterusnya hingga Anda mencapai ruang lingkup global. Ketika fungsi anonim dikembalikan dan
bind
selesai dieksekusi, fungsi anonim masih memiliki referensi kebind
ruang lingkup, jadibind
ruang lingkup tidak "hilang".Dengan semua hal di atas, Anda sekarang harus dapat memahami bagaimana ruang lingkup bekerja dalam contoh berikut, dan mengapa teknik untuk melewatkan fungsi di sekitar "pra-terikat" dengan nilai tertentu
this
akan memilikinya ketika disebut bekerja:sumber
Iya. Dan ya.
Arti
this
cukup sederhana untuk disimpulkan:this
digunakan di dalam fungsi konstruktor, dan fungsi itu dipanggil dengannew
kata kunci,this
merujuk ke objek yang akan dibuat.this
akan terus berarti objek bahkan dalam metode publik.this
digunakan di tempat lain, termasuk fungsi yang dilindungi bersarang , ini merujuk ke lingkup global (yang dalam hal browser adalah objek jendela).Kasing kedua jelas cacat desain, tetapi cukup mudah untuk mengatasinya dengan menggunakan penutup.
sumber
Dalam hal ini bagian dalam
this
terikat ke objek global alih-alih kethis
variabel fungsi luar. Begitulah cara bahasa dirancang.Lihat "JavaScript: The Good Parts" oleh Douglas Crockford untuk penjelasan yang baik.
sumber
Saya menemukan tutorial yang bagus tentang ECMAScript ini
Objek apa pun dapat digunakan sebagai nilai konteks ini.
Fitur ini sangat penting, karena bertentangan dengan variabel, nilai ini tidak pernah berpartisipasi dalam proses resolusi pengidentifikasi. Yaitu ketika mengakses ini dalam kode, nilainya diambil langsung dari konteks eksekusi dan tanpa pencarian rantai lingkup. Nilai ini ditentukan hanya sekali ketika memasuki konteks.
Dalam konteks global, nilai ini adalah objek global itu sendiri (itu berarti, nilai ini di sini sama dengan objek variabel)
Dalam kasus konteks fungsi, nilai ini dalam setiap panggilan fungsi tunggal mungkin berbeda
Referensi Javascript-the-core dan Bab-3-ini
sumber