Halo, Habr! Saya mempersembahkan kepada Anda terjemahan artikel
"Apa yang harus dilakukan ketika" ini "kehilangan konteks" oleh
Cristi Salcescu .
Cara terbaik untuk menghindari kehilangan konteks
ini adalah dengan tidak menggunakan
ini . Namun, ini tidak selalu memungkinkan. Misalnya, kami bekerja dengan kode atau pustaka orang lain yang menggunakan
ini .
Objek literal, fungsi konstruktor, konstruktor objek kelas dalam sistem prototipe.
Parameter pseudo-
ini digunakan dalam sistem prototyping untuk memberikan akses ke properti objek.
Mari kita lihat beberapa kasing.
Fungsi Bersarang
ini kehilangan referensi konteks di dalam fungsi bersarang.
class Service { constructor(){ this.numbers = [1,2,3]; this.token = "token"; } doSomething(){ setTimeout(function doAnotherThing(){ this.numbers.forEach(function log(number){
Metode
doSomething () memiliki dua fungsi bersarang:
doAnotherthing () dan
log () . Saat memanggil
service.doSomething () ,
ini kehilangan referensi konteks dalam fungsi bersarang.
bind ()
Salah satu cara untuk memecahkan masalah adalah dengan metode
bind () . Lihatlah kode berikut:
doSomething(){ setTimeout(function doAnotherThing(){ this.numbers.forEach(function log(number){ console.log(number); console.log(this.token); }.bind(this)); }.bind(this), 100); }
bind () membuat versi baru dari fungsi, yang ketika dipanggil sudah memiliki nilai tertentu
ini .
function doAnotherThing () {/*...*/}.bind(this) membuat versi dari fungsi
doAnotherThing () , yang mengambil nilai
ini dari
doSomething () .
itu / diri
Opsi lain adalah mendeklarasikan dan menggunakan variabel baru
itu / self , yang akan menyimpan nilai
ini dari metode
doSomething () .
doSomething(){ let that = this; setTimeout(function doAnotherThing(){ that.numbers.forEach(function log(number){ console.log(number); console.log(that.token); }); }, 100); }
Kita harus mendeklarasikan
biarkan itu = ini di semua metode menggunakan
ini di fungsi bersarang.
Fungsi panah
Fungsi panah memberi kita cara lain untuk menyelesaikan masalah ini.
doSomething(){ setTimeout(() => { this.numbers.forEach(number => { console.log(number); console.log(this.token); }); }, 100); }
Fungsi panah tidak membuat konteks sendiri untuk
ini , melainkan menggunakan nilai
ini dari konteks sekitarnya. Dalam contoh di atas, ia menggunakan nilai
ini dari fungsi induk.
Kerugian dari metode ini adalah kita tidak dapat menentukan nama fungsi panah. Nama fungsi memainkan peran penting, karena meningkatkan keterbacaan kode dan menjelaskan tujuannya.
Di bawah ini adalah kode yang sama dengan fungsi yang dinyatakan dalam nama variabel:
doSomething(){ let log = number => { console.log(number); console.log(this.token); } let doAnotherThing = () => { this.numbers.forEach(log); } setTimeout(doAnotherThing, 100); }
Fungsi Panggilan Balik (Metode sebagai panggilan balik)
ini kehilangan referensi konteks ketika menggunakan metode ini sebagai fungsi panggilan balik. Mari kita lihat kelas berikut:
class Service { constructor(){ this.token = "token"; } doSomething(){ console.log(this.token);
Mari kita lihat situasi di mana metode
service.doSomething () digunakan sebagai fungsi callback.
Dalam semua kasus di atas,
ini kehilangan tautan konteks.
bind ()
Kita dapat menggunakan
bind () untuk menyelesaikan masalah ini. Di bawah ini adalah kode untuk opsi ini:
Fungsi panah
Cara lain adalah membuat fungsi panah yang memanggil
service.doSomething () .
Bereaksi Komponen
Dalam komponen,
ini kehilangan referensi konteks ketika metode digunakan sebagai callback untuk acara.
class TodoAddForm extends React.Component { constructor(){ super(); this.todos = []; } componentWillMount() { this.setState({desc: ""}); } add(){ let todo = {desc: this.state.desc};
Sebagai solusinya, kita bisa membuat fungsi baru di konstruktor yang akan menggunakan
bind (ini) .
constructor(){ super(); this.todos = []; this.handleChange = this.handleChange.bind(this); this.add = this.add.bind(this); }
Jangan gunakan "ini"
Tidak
ini - tidak ada masalah dengan hilangnya konteks. Objek dapat dibuat menggunakan
fungsi pabrik . Lihatlah contoh ini:
function Service() { let numbers = [1,2,3]; let token = "token"; function doSomething(){ setTimeout(function doAnotherThing(){ numbers.forEach(function log(number){ console.log(number); console.log(token); }); }, 100); } return Object.freeze({ doSomething }); }
Konteksnya tetap ada jika Anda menggunakan metode ini sebagai panggilan balik.
let service = Service(); service.doSomething();
Kesimpulan
ini kehilangan referensi konteks dalam berbagai situasi.
bind () , menggunakan variabel itu
sendiri / dan fungsi panah adalah cara untuk memecahkan masalah konteks.
Fungsi pabrik memungkinkan untuk membuat objek tanpa menggunakan
ini .