tip
Pertama -tama, saya tahu bahwa artikel ini membosankan, tidak lebih dari ini di JS, dan ada ribuan artikel yang menulis bagian ini;
Namun, saya masih ingin menulis artikel tentang ini di JS, yang dapat dianggap sebagai ringkasan; (Dewa bisa berkeliling dan membaca artikel saya yang lain)
Dalam JS, konteks ini selalu tidak dapat diprediksi, dan seringkali bug selalu bingung. Bahkan, selama Anda dengan jelas membedakan cara mengeksekusi dalam keadaan yang berbeda, itu akan baik -baik saja.
Eksekusi Global
Pertama, mari kita lihat apa ini di lingkungan global:
Pertama. Browser:
Console.log (this); // window {pidato: pidato speechsynthesis, cache: cachestorage, localstorage: storage, sessionStorage: Storage, WebKitStorageInfo: DeprecatedStorageInfo…}Anda dapat melihat bahwa objek jendela dicetak;
Kedua. Node:
Console.log (ini); // Global
Anda dapat melihat bahwa objek global dicetak;
Ringkasan: Dalam lingkup global, ini mengeksekusi objek global saat ini (jendela di browser, global in node).
Mengeksekusi dalam fungsi
Panggilan fungsi murni
Ini adalah cara paling umum untuk menggunakan fungsi:
function test () {console.log (this);}; test (); // window {pidato: pidato speechsynthesis, cache: cachestorage, localstorage: penyimpanan, sessionstorage: penyimpanan, webkitstorageInfo: decrecatedstorageInfo…}Kita dapat melihat bahwa ketika suatu fungsi dipanggil secara langsung, itu milik panggilan global, dan pada saat ini ini menunjuk ke objek global;
Mode ketat 'Gunakan ketat';
Jika panggilan fungsi murni dieksekusi dalam mode yang ketat, maka ini di sini tidak menunjuk ke global, tetapi tidak ditentukan. Ini untuk menghilangkan beberapa perilaku yang tidak kaku di JS:
'gunakan strict'; function test () {console.log (this);}; test (); // tidak ditentukanTentu saja, menempatkannya dalam fungsi eksekusi langsung akan lebih baik, menghindari mencemari situasi global:
(function () {"gunakan ketat"; console.log (this);}) (); // tidak ditentukanPanggilan metode sebagai objek
Ketika suatu fungsi disebut sebagai metode objek:
var obj = {name: 'qiutc', foo: function () {console.log (this.name); }} obj.foo (); // 'qiutc'Pada saat ini, ini menunjuk pada objek saat ini;
Tentu saja, kita bisa melakukan ini:
function test () {console.log (this.name);} var obj = {name: 'qiutc', foo: test} obj.foo (); // 'qiutc'Juga tidak berubah, karena dalam JS semuanya adalah objek, dan fungsi juga merupakan objek. Untuk tes, ini hanya nama fungsi, referensi ke fungsi, yang menunjuk ke fungsi ini. Saat tes foo =, Foo juga menunjuk ke fungsi ini.
Bagaimana jika Anda menetapkan metode objek ke variabel dan kemudian panggil variabel ini secara langsung:
var obj = {name: 'qiutc', foo: function () {console.log (this); }} var test = obj.foo; test (); // windowDapat dilihat bahwa ini mengeksekusi dunia global saat ini. Ketika kita menempatkan tes = obj.foo, tes secara langsung menunjuk ke referensi ke suatu fungsi. Pada saat ini, sebenarnya tidak ada hubungannya dengan objek OBJ, jadi itu disebut langsung sebagai fungsi biasa, jadi ini menunjuk pada objek global.
Beberapa jebakan
Kami sering menemukan beberapa jebakan dalam fungsi panggilan balik:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (this.foo, 1000); }} obj.foo2 ();Setelah menjalankan kode ini, kami akan menemukan bahwa cetakan berbeda satu sama lain:
Pertama kali adalah mencetak ini secara langsung di FOO2, menunjuk ke objek OBJ di sini, kami tidak ragu;
Namun, This.foo dieksekusi di SetTimeout menunjuk ke objek global. Bukankah itu digunakan sebagai metode fungsi di sini? Ini sering membingungkan banyak pemula;
Bahkan, SetTimeout hanyalah suatu fungsi, dan fungsi mungkin memerlukan parameter. Kami melewati ini. Saat lulus dalam parameter, kami benar -benar melakukan operasi yang menyenangkan = this.foo. Melihat bahwa tidak ada, kami secara langsung menunjukkan kesenangan untuk referensi this.foo; Saat mengeksekusi, fun () sebenarnya dieksekusi, jadi itu tidak ada hubungannya dengan OBJ. Ini disebut secara langsung sebagai fungsi biasa, jadi ini menunjuk pada objek global.
Masalah ini biasanya ditemui dalam banyak fungsi panggilan balik asinkron;
menyelesaikan
Untuk mengatasi masalah ini, kita dapat menggunakan fitur penutupan untuk menghadapinya:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); var _pis = ini; setTimeout (function () {console.log (this); // window console.log (_this); // objek {name: "qiutc"}}, 1000); }} obj.foo2 ();Anda dapat melihat bahwa menggunakan ini secara langsung masih merupakan jendela; Karena ini di FOO2 poin ke OBJ, pertama -tama kita dapat menggunakan variabel _ ini untuk menyimpannya, dan kemudian menggunakan _THIS dalam fungsi callback untuk menunjuk ke objek saat ini;
Lubang setTimeout lainnya
Seperti yang disebutkan sebelumnya, jika fungsi callback dieksekusi secara langsung tanpa lingkup mengikat, maka titik ini ke objek global (jendela), yang akan menunjuk ke tidak terdefinisi dalam mode ketat. Namun, fungsi callback di SetTimeout menunjukkan berbeda dalam mode ketat:
'gunakan strict'; function foo () {console.log (this);} setTimeout (foo, 1); // windowSecara logis, kami menambahkan mode ketat, dan panggilan Foo tidak menentukan ini, jadi itu harus tidak ditentukan, tetapi masih ada objek global di sini. Apakah karena mode ketat telah gagal?
Tidak, bahkan dalam mode ketat, ketika metode SetTimeout memanggil fungsi yang masuk, jika fungsi tidak menentukan ini, ia akan melakukan operasi implisit - secara otomatis menyuntikkan konteks global, yang setara dengan memanggil foo.Apply (jendela) alih -alih foo ();
Tentu saja, jika kita sudah menentukan ini ketika melewati fungsi, maka kita tidak akan disuntikkan ke objek global, seperti: setTimeout (foo.bind (obj), 1) ;;
Gunakan sebagai konstruktor
Di JS, untuk mengimplementasikan kelas, kita perlu mendefinisikan beberapa konstruktor, dan kata kunci baru perlu ditambahkan saat memanggil konstruktor:
function person (name) {this.name = name; console.log (this);} var p = orang baru ('qiutc'); // orang {name: "qiutc"}Kita dapat melihat bahwa ketika disebut sebagai konstruktor, ini menunjuk pada objek yang dipakai ketika konstruktor ini dipanggil;
Tentu saja, konstruktor sebenarnya adalah fungsi. Jika kita menjalankannya sebagai fungsi normal, ini masih akan mengeksekusi secara global:
function person (name) {this.name = name; console.log (this);} var p = person ('qiutc'); // windowPerbedaannya adalah bagaimana menyebut fungsi (baru).
Fungsi panah
Dalam spesifikasi ES6 baru, fungsi panah telah ditambahkan. Hal yang paling berbeda dari fungsi biasa adalah menunjuk ini. Apakah Anda ingat bahwa kami menggunakan penutupan untuk menyelesaikan masalah penunjuk ini? Jika kita menggunakan fungsi panah, kita dapat menyelesaikannya dengan lebih sempurna:
var obj = {name: 'qiutc', foo: function () {console.log (this); }, foo2: function () {console.log (this); setTimeout (() => {console.log (this); // objek {name: "qiutc"}}, 1000); }} obj.foo2 ();Seperti yang Anda lihat, dalam fungsi yang dieksekusi oleh SetTimeout, seharusnya dicetak di jendela, tetapi ini menunjuk ke OBJ di sini. Alasannya adalah bahwa fungsi (parameter) yang diteruskan ke SetTimeout adalah fungsi panah:
Objek ini dalam badan fungsi adalah objek yang didefinisikan, bukan objek yang digunakan.
Berdasarkan contoh, mari kita pahami kalimat ini:
Ketika obj.foo2 () dieksekusi, saat ini menunjuk ke obj; Saat menjalankan SetTimeout, pertama -tama kami mendefinisikan fungsi panah anonim, dan titik kunci ada di sini. Objek dalam fungsi panah di mana ini dieksekusi ketika mendefinisikan fungsi panah ini diarahkan pada ini dalam ruang lingkup ketika mendefinisikan fungsi panah ini, yaitu, ini dalam obj.foo2, yaitu, obj; Jadi saat menjalankan fungsi panah, ini -> obj di obj.foo2 -> obj;
Sederhananya, ini dalam fungsi panah hanya terkait dengan ini dalam ruang lingkup saat mendefinisikannya, dan tidak ada hubungannya dengan di mana dan bagaimana itu disebut. Pada saat yang sama, titik ini tidak dapat diubah.
Hubungi, lamar, bind
Dalam JS, fungsi juga merupakan objek, dan ada juga beberapa metode. Di sini kami memperkenalkan tiga metode, mereka dapat mengubah pointer ini dalam fungsi:
panggilan
fun.call (thisarg [, arg1 [, arg2 [, ...]]))
Ini akan segera menjalankan fungsi. Parameter pertama menentukan konteks ini dalam fungsi eksekusi, dan parameter selanjutnya adalah parameter yang perlu diteruskan dalam fungsi eksekusi;
menerapkan
fun.apply (thisarg [, [arg1, arg2, ...]])
Ini akan segera menjalankan fungsi. Parameter pertama menentukan konteks ini dalam fungsi eksekusi, dan parameter kedua adalah array, yang merupakan parameter yang diteruskan ke fungsi eksekusi (perbedaan dari panggilan);
mengikat
var foo = fun.bind (thisarg [, arg1 [, arg2 [, ...]]]);
Itu tidak menjalankan fungsi, tetapi mengembalikan fungsi baru. Fungsi baru ini menentukan konteks ini, dan parameter selanjutnya adalah parameter yang perlu diteruskan untuk menjalankan fungsi;
Ketiga fungsi ini sebenarnya serupa. Tujuan keseluruhannya adalah untuk menentukan konteks fungsi (ini). Mari kita ambil fungsi panggilan sebagai contoh;
Tentukan ini untuk fungsi normal
var obj = {name: 'qiutc'}; function foo () {console.log (this);} foo.call (obj); // objek {name: "qiutc"}Dapat dilihat bahwa ketika mengeksekusi foo.call (OBJ), ini dalam fungsi menunjuk pada objek OBJ, yang berhasil;
Tentukan ini untuk metode dalam objek
var obj = {name: 'qiutc', foo: function () {console.log (this); }} var obj2 = {name: 'tcqiu222222'}; obj.foo.call (obj2); // objek {name: "tcqiu222222"}Anda dapat melihat bahwa ketika menjalankan fungsi, ini menunjuk ke OBJ2, yang berhasil;
Tentukan ini untuk konstruktor
function person (name) {this.name = name; console.log (this);} var obj = {name: 'qiutc2222222'}; var p = orang baru.Kesalahan dilaporkan di sini karena kami pergi ke orang baru. Fungsi call, bukan orang, dan fungsinya di sini bukan konstruktor;
Ubah untuk mengikat dan mencoba:
function person (name) {this.name = name; console.log (this);} var obj = {name: 'qiutc2222222'}; var person2 = person.bind (obj); var p = new person2 ('qiutc'); // name {name: "qiutc"} console.log (obj); // objek {"qiUtc"Apa yang dicetak adalah objek yang dipakai oleh orang, yang tidak ada hubungannya dengan OBJ, dan OBJ tidak berubah, menunjukkan bahwa kami menentukan konteks ini kepada orang tanpa memanfaatkan;
Oleh karena itu, dapat disimpulkan bahwa menggunakan Bind untuk menentukan ini untuk konstruktor. Ketika konstruktor baru, ini ditentukan oleh fungsi BIND tidak akan berlaku;
Tentu saja, Bind tidak hanya dapat menentukan ini, tetapi juga lulus parameter. Mari kita coba operasi ini:
function person (name) {this.name = name; console.log (this);} var obj = {name: 'qiutc2222222'}; var person2 = person.bind (obj, 'qiutc11111111'); var p = new person2 ('qiutc'); // orang {nama: "qiutc1111111"}Seperti yang Anda lihat, meskipun menentukan ini tidak berhasil, parameter yang masuk masih berfungsi;
Tentukan ini untuk fungsi panah
Mari kita tentukan fungsi panah di bawah global, jadi ini dalam fungsi panah ini pasti akan menunjuk ke objek global. Bagaimana jika ini diubah dengan menggunakan metode panggilan:
var afoo = (a) => {console.log (a); console.log (this);} afoo (1); // 1 // windowvar obj = {name: 'qiutc'}; afoo.call (obj, 2); // 2 // windowSeperti yang Anda lihat, operasi panggilan yang menunjuk ke sini tidak berhasil, sehingga dapat disimpulkan bahwa ini dalam fungsi panah telah memutuskan ketika mendefinisikannya (jalankan ini dalam ruang lingkup yang mendefinisikannya), dan tidak ada hubungannya dengan bagaimana menyebutnya dan di mana harus menyebutnya. Tidak ada operasi termasuk (panggilan, berlaku, bind) dan operasi lain tidak dapat mengubah ini.
Ingatlah bahwa fungsi panah itu bagus dan ini tetap tidak berubah.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.