Kapan saya harus menggunakan fungsi Panah di ECMAScript 6?

407

Pertanyaannya diarahkan pada orang-orang yang memikirkan gaya kode dalam konteks ECMAScript 6 (Harmony) yang akan datang dan yang sudah bekerja dengan bahasa tersebut.

Dengan () => {}dan function () {}kami mendapatkan dua cara yang sangat mirip untuk menulis fungsi di ES6. Dalam bahasa lain, fungsi lambda sering kali membedakan diri dengan menjadi anonim, tetapi dalam ECMAScript, fungsi apa pun bisa anonim. Masing-masing dari kedua jenis memiliki domain penggunaan yang unik (yaitu ketika thisharus terikat secara eksplisit atau tidak terikat secara eksplisit). Di antara domain-domain tersebut ada sejumlah besar kasus di mana kedua notasi akan dilakukan.

Fungsi panah di ES6 memiliki setidaknya dua batasan:

  • Jangan bekerja dengan newdan tidak dapat digunakan saat membuatprototype
  • Tetap thisterikat pada cakupan saat inisialisasi

Selain dua keterbatasan ini, fungsi panah secara teoritis dapat menggantikan fungsi biasa hampir di mana saja. Apa pendekatan yang tepat dalam menggunakannya? Haruskah fungsi panah digunakan misalnya:

  • "Di mana pun mereka bekerja", yaitu di mana pun suatu fungsi tidak harus agnostik tentang this variabel dan kita tidak membuat objek.
  • hanya "di mana pun mereka dibutuhkan", yaitu pendengar acara, batas waktu, yang perlu terikat pada ruang lingkup tertentu
  • dengan fungsi 'pendek' tetapi tidak dengan fungsi 'panjang'
  • hanya dengan fungsi yang tidak mengandung fungsi panah lain

Apa yang saya cari adalah pedoman untuk memilih notasi fungsi yang sesuai di versi ECMAScript yang akan datang. Pedoman ini perlu jelas, sehingga dapat diajarkan kepada pengembang dalam tim, dan konsisten agar tidak memerlukan refactoring terus menerus bolak-balik dari satu notasi fungsi ke notasi fungsi lainnya.

lyschoening
sumber
33
Anda menganggap Fixed this bound to scope at initialisationsebagai batasan?
thethourtheye
12
Ini merupakan keuntungan, tetapi juga bisa menjadi batasan jika Anda berencana untuk menggunakan kembali fungsi di luar konteks aslinya. Misalnya ketika menambahkan fungsi ke kelas secara dinamis melalui Object.prototype. Yang saya maksud dengan 'batasan' adalah bahwa mengubah nilai thisadalah sesuatu yang dapat Anda lakukan dengan fungsi biasa tetapi tidak dengan fungsi panah.
lyschoening
1
Jujur saya pikir pedoman gaya pengkodean agak dikemukakan pendapat. Jangan salah paham, saya pikir itu penting, tetapi tidak ada pedoman tunggal yang cocok untuk semua orang.
Felix Kling
Saya pikir Fixed this bound to scope at initialisationitu bukan batasan. :) Lihatlah artikel ini: exploringjs.com/es6/ch_arrow-functions.html
NgaNguyenDuy
3
@thefourtheye, "batasan" di sini berarti "batasan karena penerjemah kode otomatis yang bodoh tidak dapat secara acak menggantikan satu dengan yang lain dan menganggap bahwa semuanya akan berjalan seperti yang diharapkan".
Pacerier

Jawaban:

322

Beberapa waktu yang lalu tim kami memigrasikan semua kodenya (aplikasi AngularJS berukuran sedang) ke JavaScript yang dikompilasi menggunakan Traceur Babel . Saya sekarang menggunakan aturan praktis berikut untuk fungsi di ES6 dan seterusnya:

  • Gunakan functiondalam lingkup global dan untuk Object.prototypeproperti.
  • Gunakan classuntuk konstruktor objek.
  • Gunakan =>tempat lain.

Mengapa menggunakan fungsi panah hampir di semua tempat?

  1. Keamanan lingkup: Ketika fungsi panah digunakan secara konsisten, semuanya dijamin untuk menggunakan yang sama thisObjectdengan root. Jika bahkan callback fungsi standar tunggal dicampur dengan sekelompok fungsi panah ada kemungkinan ruang lingkup akan menjadi kacau.
  2. Kekompakan: Fungsi panah lebih mudah dibaca dan ditulis. (Ini mungkin terkesan keras jadi saya akan memberikan beberapa contoh lebih lanjut).
  3. Kejelasan: Ketika hampir semuanya adalah fungsi panah, setiap reguler functionlangsung muncul untuk menentukan ruang lingkup. Pengembang selalu dapat melihat pernyataan selanjutnya yang lebih tinggi functionuntuk melihat apa thisObjectitu.

Mengapa selalu menggunakan fungsi reguler pada lingkup global atau lingkup modul?

  1. Untuk menunjukkan fungsi yang seharusnya tidak mengakses thisObject.
  2. The windowobjek (lingkup global) yang terbaik ditangani secara eksplisit.
  3. Banyak Object.prototypedefinisi yang hidup dalam lingkup global (pikirkan String.prototype.truncatedll.) Dan yang umumnya harus bertipe functionpula. Penggunaan yang konsisten functionpada lingkup global membantu menghindari kesalahan.
  4. Banyak fungsi dalam lingkup global adalah konstruktor objek untuk definisi kelas gaya lama.
  5. Fungsi dapat dinamai 1 . Ini memiliki dua manfaat: (1) Kurang canggung untuk menulis function foo(){}daripadaconst foo = () => {} - khususnya di luar panggilan fungsi lainnya. (2) Nama fungsi ditampilkan dalam jejak tumpukan. Meskipun akan membosankan untuk menyebutkan setiap panggilan balik internal, memberi nama semua fungsi publik mungkin adalah ide yang bagus.
  6. Deklarasi fungsi diangkat , (artinya dapat diakses sebelum dideklarasikan), yang merupakan atribut yang berguna dalam fungsi utilitas statis.


Konstruktor objek

Mencoba membuat instantiate fungsi panah melempar pengecualian:

var x = () => {};
new x(); // TypeError: x is not a constructor

Salah satu keuntungan utama fungsi daripada fungsi panah adalah fungsi tersebut berfungsi ganda sebagai konstruktor objek:

function Person(name) {
    this.name = name;
}

Namun, definisi kelas konsep 2 ES Harmony identik secara fungsional hampir sama kompaknya:

class Person {
    constructor(name) {
        this.name = name;
    }
}

Saya berharap bahwa penggunaan notasi sebelumnya pada akhirnya akan patah semangat. Notasi konstruktor objek masih dapat digunakan oleh beberapa untuk pabrik objek anonim sederhana di mana objek dihasilkan secara terprogram, tetapi tidak untuk banyak hal lain.

Di mana konstruktor objek diperlukan, seseorang harus mempertimbangkan mengubah fungsi menjadi classseperti yang ditunjukkan di atas. Sintaks berfungsi dengan fungsi / kelas anonim juga.


Keterbacaan fungsi panah

Argumen terbaik untuk tetap menggunakan fungsi biasa - ruang lingkup keselamatan terkutuk - adalah bahwa fungsi panah kurang dapat dibaca daripada fungsi biasa. Jika kode Anda tidak berfungsi di tempat pertama, maka fungsi panah mungkin tidak diperlukan, dan ketika fungsi panah tidak digunakan secara konsisten, mereka terlihat jelek.

ECMAScript telah berubah sedikit sejak ECMAScript 5.1 memberi kami fungsional Array.forEach, Array.mapdan semua fitur pemrograman fungsional ini membuat kami menggunakan fungsi di mana for-loop akan digunakan sebelumnya. JavaScript Asynchronous sudah cukup lama. ES6 juga akan mengirimkan Promiseobjek, yang berarti lebih banyak fungsi anonim. Tidak ada jalan kembali untuk pemrograman fungsional. Dalam JavaScript fungsional, fungsi panah lebih disukai daripada fungsi biasa.

Ambil contoh ini (terutama membingungkan) sepotong kode 3 :

function CommentController(articles) {
    this.comments = [];

    articles.getList()
        .then(articles => Promise.all(articles.map(article => article.comments.getList())))
        .then(commentLists => commentLists.reduce((a, b) => a.concat(b)));
        .then(comments => {
            this.comments = comments;
        })
}

Bagian kode yang sama dengan fungsi reguler:

function CommentController(articles) {
    this.comments = [];

    articles.getList()
        .then(function (articles) {
            return Promise.all(articles.map(function (article) { 
                return article.comments.getList();
            }));
        })
        .then(function (commentLists) {
            return commentLists.reduce(function (a, b) {
                return a.concat(b); 
            });
        })
        .then(function (comments) {
            this.comments = comments;
        }.bind(this));
}

Sementara salah satu fungsi panah dapat digantikan oleh fungsi standar, akan ada sangat sedikit yang bisa didapat dari melakukannya. Versi mana yang lebih mudah dibaca? Saya akan mengatakan yang pertama.

Saya pikir pertanyaan apakah menggunakan fungsi panah atau fungsi biasa akan menjadi kurang relevan seiring waktu. Sebagian besar fungsi akan menjadi metode kelas, yang menghilangkan functionkata kunci, atau mereka akan menjadi kelas. Fungsi akan tetap digunakan untuk menambal kelas melalui Object.prototype. Sementara itu saya sarankan memesan functionkata kunci untuk apa pun yang benar-benar harus menjadi metode kelas atau kelas.


Catatan

  1. Fungsi panah yang dinamai telah ditangguhkan dalam spesifikasi ES6 . Mereka mungkin masih ditambahkan versi masa depan.
  2. Menurut spesifikasi rancangan "Deklarasi / ekspresi kelas membuat fungsi konstruktor / pasangan prototipe persis seperti untuk deklarasi fungsi" selama kelas tidak menggunakan extendkata kunci. Perbedaan kecil adalah bahwa deklarasi kelas adalah konstanta, sedangkan deklarasi fungsi tidak.
  3. Catatan tentang blok dalam fungsi panah pernyataan tunggal: Saya suka menggunakan blok di mana fungsi panah dipanggil untuk efek samping saja (misal penugasan). Dengan begitu jelas bahwa nilai kembali dapat dibuang.
lyschoening
sumber
4
Waktu lain yang ingin Anda gunakan functionadalah ketika Anda tidak ingin thisterikat, bukan? Skenario saya yang paling umum untuk ini adalah peristiwa, di mana Anda mungkin ingin thismerujuk ke objek (biasanya simpul DOM) yang memicu acara.
Brett
13
Saya benar-benar berpikir dalam contoh 3, fungsi reguler lebih mudah dibaca. Bahkan yang bukan programmer dapat mengetahui apa yang sedang terjadi. Dengan panah, Anda harus tahu persis cara kerjanya untuk memahami contoh itu. Mungkin lebih banyak baris baru akan membantu contoh panah, tapi saya tidak tahu. Hanya 2 sen saya tetapi panah membuat saya merasa ngeri (tapi saya belum menggunakannya, jadi saya akan segera bertobat.)
Spencer
3
@Spencer itu adalah titik yang adil. Dari pengalaman saya sendiri, =>akhirnya tampak lebih baik seiring waktu. Saya ragu bahwa non-programmer akan merasa sangat berbeda tentang dua contoh. Jika Anda menulis kode ES2016, biasanya Anda tidak akan berakhir menggunakan banyak fungsi panah ini. Dalam contoh ini, menggunakan async / await dan pemahaman array, Anda akan berakhir hanya dengan satu fungsi panah dalam reduce()panggilan.
lyschoening
3
Saya sepenuhnya setuju dengan Spencer bahwa fungsi reguler jauh lebih mudah dibaca dalam contoh itu.
jonschlinkert
2
Jawaban yang bagus, terima kasih! secara pribadi saya juga menggunakan panah dalam lingkup global sebanyak mungkin. Ini membuat saya hampir tidak memiliki 'fungsi'. Bagi saya 'fungsi' dalam kode berarti kasus khusus yang perlu diperhatikan dan dipertimbangkan dengan cermat.
kofifus
81

Menurut proposal itu , panah bertujuan "untuk mengatasi dan menyelesaikan beberapa titik sakit tradisional yang umum Function Expression." Mereka bermaksud memperbaiki masalah dengan mengikatthis secara leksikal dan menawarkan sintaksis singkat.

Namun,

  • Seseorang tidak dapat mengikat secara konsisten this leksikal
  • Sintaks fungsi panah halus dan ambigu

Oleh karena itu, fungsi panah menciptakan peluang untuk kebingungan dan kesalahan, dan harus dikeluarkan dari kosakata programmer JavaScript, diganti dengan function secara eksklusif.

Mengenai leksikal this

this bermasalah:

function Book(settings) {
    this.settings = settings;
    this.pages = this.createPages();
}
Book.prototype.render = function () {
    this.pages.forEach(function (page) {
        page.draw(this.settings);
    }, this);
};

Fungsi panah bermaksud untuk memperbaiki masalah di mana kita perlu mengakses properti thisdi dalam panggilan balik. Sudah ada beberapa cara untuk melakukan itu: Seseorang dapat menetapkan thisuntuk variabel, menggunakan bind, atau menggunakan argumen ke-3 yang tersedia pada Arraymetode agregat. Namun panah tampaknya merupakan solusi yang paling sederhana, sehingga metode ini dapat di refactored seperti ini:

this.pages.forEach(page => page.draw(this.settings));

Namun, pertimbangkan jika kode tersebut menggunakan pustaka seperti jQuery, yang metodenya mengikat thissecara khusus. Sekarang, ada dua thisnilai yang harus dihadapi:

Book.prototype.render = function () {
    var book = this;
    this.$pages.each(function (index) {
        var $page = $(this);
        book.draw(book.currentPage + index, $page);
    });
};

Kita harus menggunakan functionagar eachmengikatthis secara dinamis. Kami tidak dapat menggunakan fungsi panah di sini.

Berurusan dengan banyak thisnilai juga bisa membingungkan, karena sulit untuk mengetahui thispenulis mana yang dibicarakan:

function Reader() {
    this.book.on('change', function () {
        this.reformat();
    });
}

Apakah penulis sebenarnya bermaksud menelepon Book.prototype.reformat? Atau apakah dia lupa mengikat this, dan berniat menelepon Reader.prototype.reformat? Jika kita mengubah penangan ke fungsi panah, kita juga akan bertanya-tanya apakah penulis menginginkan dinamika this, namun memilih panah karena sesuai pada satu baris:

function Reader() {
    this.book.on('change', () => this.reformat());
}

Seseorang dapat berpose: "Apakah luar biasa bahwa panah kadang-kadang bisa menjadi fungsi yang salah untuk digunakan? Mungkin jika kita jarang membutuhkan dinamika this nilai-nilai , maka sebagian besar waktu akan tetap oke untuk menggunakan panah."

Tetapi tanyakan pada diri sendiri ini: "Apakah 'layak' untuk men-debug kode dan menemukan bahwa hasil dari kesalahan dibawa oleh 'kasus tepi?'" Saya lebih suka menghindari masalah bukan hanya sebagian besar waktu, tetapi 100% dari waktu.

Ada cara yang lebih baik: Selalu gunakan function(jadi thisselalu bisa terikat secara dinamis), dan selalu referensi thismelalui variabel. Variabel leksikal dan mengasumsikan banyak nama. Menetapkan thiske variabel akan membuat niat Anda jelas:

function Reader() {
    var reader = this;
    reader.book.on('change', function () {
        var book = this;
        book.reformat();
        reader.reformat();
    });
}

Selain itu, selalu menugaskan thiske variabel (bahkan ketika ada satu thisatau tidak ada fungsi lain) memastikan niat seseorang tetap jelas bahkan setelah kode diubah.

Juga, dinamis thishampir tidak luar biasa. jQuery digunakan di lebih dari 50 juta situs web (pada tulisan ini pada Februari 2016). Berikut adalah API lain yang mengikat thissecara dinamis:

  • Mocha (~ 120k unduhan kemarin) memaparkan metode untuk pengujiannya via this.
  • Grunt (~ 63k unduhan kemarin) memaparkan metode untuk membangun tugas melalui this.
  • Backbone (~ 22k unduhan kemarin) mendefinisikan metode mengakses this.
  • API acara (seperti DOM) merujuk ke EventTargetdengan this.
  • API prototipe yang ditambal atau diperluas merujuk ke instance dengan this.

(Statistik via http://trends.builtwith.com/javascript/jQuery dan https://www.npmjs.com .)

Anda kemungkinan sudah membutuhkan thisbinding dinamis .

Leksikal thiskadang-kadang diharapkan, tetapi kadang-kadang tidak; sama seperti dinamika thiskadang-kadang diharapkan, tetapi kadang tidak. Syukurlah, ada cara yang lebih baik, yang selalu menghasilkan dan mengomunikasikan ikatan yang diharapkan.

Mengenai sintaks singkat

Fungsi panah berhasil menyediakan "bentuk sintaksis pendek" untuk fungsi. Tetapi apakah fungsi yang lebih pendek ini akan membuat Anda lebih sukses?

Apakah x => x * x"lebih mudah dibaca" daripada function (x) { return x * x; }? Mungkin begitu, karena lebih mungkin menghasilkan satu baris kode pendek. Mengakses pada Dyson Pengaruh kecepatan membaca dan panjang garis pada efektivitas membaca dari layar ,

Panjang garis sedang (55 karakter per baris) muncul untuk mendukung pembacaan yang efektif pada kecepatan normal dan cepat. Ini menghasilkan tingkat pemahaman tertinggi. . .

Pembenaran serupa dibuat untuk operator bersyarat (ternary), dan untuk ifpernyataan garis tunggal .

Namun, apakah Anda benar-benar menulis fungsi matematika sederhana yang diiklankan dalam proposal ? Domain saya bukan matematika, jadi subrutin saya jarang begitu elegan. Sebaliknya, saya biasanya melihat fungsi panah melanggar batas kolom, dan membungkus ke baris lain karena editor atau panduan gaya, yang membatalkan "keterbacaan" oleh definisi Dyson.

Seseorang mungkin berpose, "Bagaimana kalau hanya menggunakan versi pendek untuk fungsi pendek, bila memungkinkan?" Tetapi sekarang aturan gaya bertentangan dengan batasan bahasa: "Cobalah menggunakan notasi fungsi sesingkat mungkin, ingatlah bahwa kadang-kadang hanya notasi terpanjang yang akan mengikatthis seperti yang diharapkan." Penggabungan seperti itu membuat anak panah rentan terhadap penyalahgunaan.

Ada banyak masalah dengan sintaks fungsi panah:

const a = x =>
    doSomething(x);

const b = x =>
    doSomething(x);
    doSomethingElse(x);

Kedua fungsi ini valid secara sintaksis. Tetapi doSomethingElse(x);tidak ada di dalam tubuh b, itu hanya pernyataan tingkat atas yang indentasi buruk.

Ketika memperluas ke bentuk blok, tidak ada lagi yang tersirat return, yang orang bisa lupa untuk mengembalikan. Tetapi ungkapan itu mungkin hanya dimaksudkan untuk menghasilkan efek samping, jadi siapa yang tahu jika diperlukan eksplisit returnuntuk maju?

const create = () => User.create();

const create = () => {
    let user;
    User.create().then(result => {
        user = result;
        return sendEmail();
    }).then(() => user);
};

const create = () => {
    let user;
    return User.create().then(result => {
        user = result;
        return sendEmail();
    }).then(() => user);
};

Apa yang mungkin dimaksudkan sebagai parameter lainnya dapat diurai sebagai operator spread:

processData(data, ...results => {}) // Spread
processData(data, (...results) => {}) // Rest

Tugas dapat dikacaukan dengan argumen default:

const a = 1;
let x;
const b = x => {}; // No default
const b = x = a => {}; // "Adding a default" instead creates a double assignment
const b = (x = a) => {}; // Remember to add parens

Blok terlihat seperti objek:

(id) => id // Returns `id`
(id) => {name: id} // Returns `undefined` (it's a labeled statement)
(id) => ({name: id}) // Returns an object

Apa artinya ini?

() => {}

Apakah penulis bermaksud membuat no-op, atau fungsi yang mengembalikan objek kosong? (Dengan mengingat hal ini, haruskah kita menempatkan {setelah =>? Haruskah kita membatasi diri kita hanya pada sintaks ekspresi? Itu akan semakin mengurangi frekuensi panah.)

=>terlihat seperti <=dan >=:

x => 1 ? 2 : 3
x <= 1 ? 2 : 3

if (x => 1) {}
if (x >= 1) {}

Untuk memunculkan ekspresi fungsi panah dengan segera, seseorang harus menempatkan ()di luar, namun menempatkan ()di dalam adalah valid dan bisa disengaja.

(() => doSomething()()) // Creates function calling value of `doSomething()`
(() => doSomething())() // Calls the arrow function

Meskipun, jika seseorang menulis (() => doSomething()());dengan maksud untuk menulis ekspresi fungsi yang segera dipanggil, tidak ada yang akan terjadi.

Sulit untuk berpendapat bahwa fungsi panah "lebih dapat dimengerti" dengan semua kasus di atas dalam pikiran. Seseorang dapat mempelajari semua aturan khusus yang diperlukan untuk menggunakan sintaks ini. Apakah ini benar-benar layak?

Sintaksnya functiondigeneralisasikan secara tidak terduga. Untuk menggunakan functionsecara eksklusif berarti bahasa itu sendiri mencegah seseorang dari menulis kode yang membingungkan. Untuk menulis prosedur yang harus dipahami secara sintaksis dalam semua kasus, saya memilih function.

Tentang pedoman

Anda meminta pedoman yang harus "jelas" dan "konsisten." Menggunakan fungsi panah pada akhirnya akan menghasilkan kode yang valid secara sintaksis, tidak logis secara logis, dengan kedua bentuk fungsi saling terkait, bermakna dan sewenang-wenang. Karena itu, saya menawarkan yang berikut:

Pedoman untuk Notasi Fungsi di ES6:

  • Selalu buat prosedur dengan function.
  • Selalu tetapkan thiske variabel. Jangan gunakan () => {}.
Jackson
sumber
5
Menulis menarik pada pandangan programmer fungsional pada JavaScript. Saya tidak yakin saya setuju dengan argumen variabel pribadi. IMO hanya sedikit orang yang benar-benar membutuhkannya; mereka yang melakukannya mungkin juga membutuhkan fitur kontrak lain dan tetap menggunakan ekstensi bahasa seperti TypeScript. Saya pasti bisa melihat daya tarik selfbukan ini. Perangkap fungsi tanda panah yang Anda nyatakan juga semuanya valid, dan standar yang sama seperti pada pernyataan lain yang bisa digunakan tanpa kawat gigi pasti berlaku di sini juga; jika tidak, saya pikir dengan argumen Anda, orang juga bisa menganjurkan fungsi panah di mana-mana.
lyschoening
7
"Memiliki banyak cara dalam melakukan sesuatu menciptakan vektor yang tidak perlu untuk argumen dan pertikaian di tempat kerja dan komunitas bahasa. Akan lebih baik jika tata bahasa tidak memungkinkan kita untuk membuat pilihan yang buruk." Setuju begitu banyak. Langgan bagus! Saya pikir fungsi panah sebenarnya adalah langkah mundur. Pada topik yang berbeda, saya berharap rekan kerja saya akan berhenti mencoba mengubah JavaScript menjadi C # dengan serangkaian definisi .prototype. Itu menjijikkan. Saya harus menautkan pos Anda secara anonim :)
Spencer
11
Ditulis dengan sangat baik! Meskipun saya tidak setuju dengan sebagian besar poin Anda, penting untuk mempertimbangkan sudut pandang yang berlawanan.
minexew
4
Bukan fungsi panah tetapi perilaku aneh thisadalah masalah Javascript. Alih-alih terikat secara implisit, thisharus disahkan sebagai argumen eksplisit.
bob
5
+ Msgstr " Selalu gunakan fungsi (jadi ini selalu bisa terikat secara dinamis), dan selalu referensi ini melalui variabel. " Saya tidak bisa tidak setuju lagi!
48

Fungsi panah dibuat untuk menyederhanakan fungsi scopedan menyelesaikan thiskata kunci dengan membuatnya lebih sederhana. Mereka menggunakan =>sintaksis, yang terlihat seperti panah.

Catatan: Itu tidak menggantikan fungsi yang ada. Jika Anda mengganti setiap sintaks fungsi dengan fungsi panah, itu tidak akan berfungsi dalam semua kasus.

Mari kita lihat sintaks ES5 yang ada, Jika thiskata kunci ada di dalam metode objek (fungsi yang dimiliki objek), apa yang akan dirujuk?

var Actor = {
  name: 'RajiniKanth',
  getName: function() {
     console.log(this.name);
  }
};
Actor.getName();

Cuplikan di atas akan merujuk ke objectdan mencetak nama "RajiniKanth". Mari jelajahi cuplikan di bawah ini dan lihat apa yang akan ditunjukkan di sini.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  showMovies: function() {
   this.movies.forEach(function(movie) {
     alert(this.name + " has acted in " + movie);
   });
  }
};

Actor.showMovies();

Sekarang bagaimana dengan jika thiskata kunci ada di dalam method’s function?

Di sini ini akan merujuk window objectdaripada inner functionyang jatuh dari scope. Karena this, selalu referensi pemilik fungsi itu, untuk kasus ini - karena sekarang di luar ruang lingkup - jendela / objek global.

Ketika itu berada di dalam objectmetode an - functionpemilik adalah objek. Jadi kata kunci ini terikat ke objek. Namun ketika itu berada di dalam suatu fungsi, baik berdiri sendiri atau dalam metode lain, itu akan selalu merujuk pada window/globalobjek.

var fn = function(){
  alert(this);
}

fn(); // [object Window]

Ada beberapa cara untuk menyelesaikan masalah ini dengan ES5sendirinya, mari kita selidiki sebelum menyelam ke fungsi ES6 arrow tentang cara mengatasinya.

Biasanya Anda akan, membuat variabel di luar fungsi dalam metode ini. Sekarang ‘forEach’metode mendapatkan akses ke thisdan dengan demikian object’sproperti dan nilainya.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  showMovies: function() {
   var _this = this;
   this.movies.forEach(function(movie) {
     alert(_this.name + " has acted in " + movie);
   });
  }
};

Actor.showMovies();

gunakan binduntuk melampirkan thiskata kunci yang merujuk pada metode ke method’s inner function.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  showMovies: function() {
   this.movies.forEach(function(movie) {
     alert(this.name + " has acted in " + movie);
   }.bind(this));
  }
};

Actor.showMovies();

Sekarang dengan ES6fungsi panah, kita dapat menangani lexical scopingmasalah dengan cara yang lebih sederhana.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  showMovies: function() {
   this.movies.forEach((movie) => {
     alert(this.name + " has acted in " + movie);
   });
  }
};

Actor.showMovies();

Arrow functionslebih seperti pernyataan fungsi, kecuali bahwa mereka bindini untuk parent scope. Jika argumen arrow function is in top scope, thisakan merujuk window/global scope, sedangkan fungsi panah di dalam fungsi biasa akan memiliki argumen ini sama dengan fungsi luarnya.

Dengan arrowfungsi thisterikat ke melampirkan scopepada waktu pembuatan dan tidak dapat diubah. Operator baru, ikat, panggil, dan terapkan tidak berpengaruh pada ini.

var asyncFunction = (param, callback) => {
  window.setTimeout(() => {
  callback(param);
  }, 1);
};

// With a traditional function if we don't control
// the context then can we lose control of `this`.
var o = {
  doSomething: function () {
  // Here we pass `o` into the async function,
  // expecting it back as `param`
  asyncFunction(o, function (param) {
  // We made a mistake of thinking `this` is
  // the instance of `o`.
  console.log('param === this?', param === this);
  });
  }
};

o.doSomething(); // param === this? false

Dalam contoh di atas, kami kehilangan kendali atas hal ini. Kita dapat memecahkan contoh di atas dengan menggunakan referensi variabel thisatau menggunakan bind. Dengan ES6, ia menjadi lebih mudah dalam mengelola apa thisyang terikat padanya lexical scoping.

var asyncFunction = (param, callback) => {
  window.setTimeout(() => {
  callback(param);
  }, 1);
};

var o = {
  doSomething: function () {
  // Here we pass `o` into the async function,
  // expecting it back as `param`.
  //
  // Because this arrow function is created within
  // the scope of `doSomething` it is bound to this
  // lexical scope.
  asyncFunction(o, (param) => {
  console.log('param === this?', param === this);
  });
  }
};

o.doSomething(); // param === this? true

Ketika tidak ke Arrow fungsi

Di dalam objek literal.

var Actor = {
  name: 'RajiniKanth',
  movies: ['Kabali', 'Sivaji', 'Baba'],
  getName: () => {
     alert(this.name);
  }
};

Actor.getName();

Actor.getNamedidefinisikan dengan fungsi panah, tetapi pada pemanggilan peringatan itu tidak terdefinisi karena this.nameadalah undefinedsebagai konteks tetapwindow .

Itu terjadi karena fungsi panah mengikat konteks secara leksikal dengan window object... yaitu lingkup luar. Eksekusi this.namesetara dengan window.name, yang tidak terdefinisi.

Prototipe objek

Aturan yang sama berlaku ketika mendefinisikan metode pada a prototype object. Alih-alih menggunakan fungsi panah untuk mendefinisikan metode sayCatName, yang membawa kesalahan context window:

function Actor(name) {
  this.name = name;
}
Actor.prototype.getName = () => {
  console.log(this === window); // => true
  return this.name;
};
var act = new Actor('RajiniKanth');
act.getName(); // => undefined

Memohon konstruktor

thisdalam doa konstruksi adalah objek yang baru dibuat. Saat menjalankan Fn baru (), konteks objek constructor Fnadalah baru:this instanceof Fn === true .

this adalah pengaturan dari konteks melampirkan, yaitu lingkup luar yang membuatnya tidak ditugaskan ke objek yang baru dibuat.

var Message = (text) => {
  this.text = text;
};
// Throws "TypeError: Message is not a constructor"
var helloMessage = new Message('Hello World!');

Panggilan balik dengan konteks dinamis

Fungsi panah mengikat contextstatik pada deklarasi dan tidak mungkin membuatnya dinamis. Melampirkan pendengar acara ke elemen DOM adalah tugas umum dalam pemrograman sisi klien. Suatu peristiwa memicu fungsi handler dengan ini sebagai elemen target.

var button = document.getElementById('myButton');
button.addEventListener('click', () => {
  console.log(this === window); // => true
  this.innerHTML = 'Clicked button';
});

thisadalah jendela dalam fungsi panah yang didefinisikan dalam konteks global. Ketika suatu peristiwa klik terjadi, browser mencoba untuk memanggil fungsi handler dengan konteks tombol, tetapi fungsi panah tidak mengubah konteks yang telah ditentukan sebelumnya. this.innerHTMLsetara dengan window.innerHTMLdan tidak masuk akal.

Anda harus menerapkan ekspresi fungsi, yang memungkinkan untuk mengubahnya tergantung pada elemen target:

var button = document.getElementById('myButton');
button.addEventListener('click', function() {
  console.log(this === button); // => true
  this.innerHTML = 'Clicked button';
});

Ketika pengguna mengklik tombol, ini dalam fungsi penangan adalah tombol. Dengan demikian this.innerHTML = 'Clicked button'memodifikasi teks tombol dengan benar untuk mencerminkan status yang diklik.

Referensi: https://dmitripavlutin.com/when-not-to-use-arrow-functions-in-javascript/

Thalaivar
sumber
Yah, harus saya akui, bahwa "yang terbaik terletak di tengah" . Dipilih untuk pernyataan, bahwa fungsi panah tidak akan mencakup semua kasus penggunaan fungsi yang mungkin. Mereka benar-benar dirancang untuk menyelesaikan hanya sebagian dari masalah umum. Beralih saja ke mereka sepenuhnya akan menjadi pembunuhan yang berlebihan.
BlitZ
@DmitriPavlutin: Periksa posting saya yang diperbarui, ini koleksi banyak hal ... mungkin saya harus mengirim referensi.
Thalaivar
2
Kode Anda setelah baris 'menggunakan bind untuk melampirkan kata kunci ini yang merujuk pada metode ke fungsi bagian dalam metode.' memiliki bug di dalamnya. Sudahkah Anda menguji sisa contoh Anda?
Isaac Pak
Yang satu using bind to attach the this keyword that refers to the method to the method’s inner function.memiliki kesalahan sintaksis.
Coda Chang
Seharusnyavar Actor = { name: 'RajiniKanth', movies: ['Kabali', 'Sivaji', 'Baba'], showMovies: function() { this.movies.forEach(function(movie){ alert(this.name + ' has acted in ' + movie); }.bind(this)) } }; Actor.showMovies();
Coda Chang
14

Fungsi panah - fitur ES6 yang paling banyak digunakan sejauh ini ...

Penggunaan: Semua fungsi ES5 harus diganti dengan fungsi panah ES6 kecuali dalam skenario berikut:

Fungsi panah TIDAK boleh digunakan:

  1. Ketika kita ingin fungsi mengangkat
    • karena fungsi panah bersifat anonim.
  2. Ketika kita ingin menggunakan this/ argumentsdalam suatu fungsi
    • karena fungsi panah tidak memiliki this/ argumentssendiri, mereka bergantung pada konteks luarnya.
  3. Ketika kita ingin menggunakan fungsi bernama
    • karena fungsi panah bersifat anonim.
  4. Ketika kita ingin menggunakan fungsi sebagai a constructor
    • sebagai fungsi panah tidak memiliki sendiri this.
  5. Ketika kita ingin menambahkan fungsi sebagai properti dalam objek literal dan menggunakan objek di dalamnya
    • karena kita tidak dapat mengakses this(yang seharusnya menjadi objek itu sendiri).

Mari kita memahami beberapa varian fungsi panah untuk memahami lebih baik:

Varian 1 : Ketika kita ingin melewatkan lebih dari satu argumen ke suatu fungsi dan mengembalikan beberapa nilai darinya.

Versi ES5 :

var multiply = function (a,b) {
    return a*b;
};
console.log(multiply(5,6)); //30

Versi ES6 :

var multiplyArrow = (a,b) => a*b;
console.log(multiplyArrow(5,6)); //30

Catatan: functionkata kunci TIDAK diperlukan. =>Dibutuhkan. {}bersifat opsional, ketika kami tidak menyediakan {} returnsecara implisit ditambahkan oleh JavaScript dan ketika kami menyediakan {}kami perlu menambahkan returnjika kami membutuhkannya.

Varian 2 : Ketika kita ingin melewatkan HANYA satu argumen ke suatu fungsi dan mengembalikan beberapa nilai darinya.

Versi ES5 :

var double = function(a) {
    return a*2;
};
console.log(double(2)); //4

Versi ES6 :

var doubleArrow  = a => a*2;
console.log(doubleArrow(2)); //4

Catatan: Saat melewati hanya satu argumen, kita dapat menghilangkan tanda kurung () .

Varian 3 : Ketika kita TIDAK ingin meneruskan argumen apa pun ke suatu fungsi dan TIDAK ingin mengembalikan nilai apa pun.

Versi ES5 :

var sayHello = function() {
    console.log("Hello");
};
sayHello(); //Hello

Versi ES6 :

var sayHelloArrow = () => {console.log("sayHelloArrow");}
sayHelloArrow(); //sayHelloArrow

Varian 4 : Ketika kita ingin secara eksplisit kembali dari fungsi panah.

Versi ES6 :

var increment = x => {
  return x + 1;
};
console.log(increment(1)); //2

Varian 5 : Saat kita ingin mengembalikan objek dari fungsi panah.

Versi ES6 :

var returnObject = () => ({a:5});
console.log(returnObject());

Catatan: Kita perlu membungkus objek dalam tanda kurung ()jika tidak, JavaScript tidak dapat membedakan antara blok dan objek.

Varian 6 : Fungsi panah TIDAK memiliki arguments(array seperti objek) sendiri, mereka bergantung pada konteks luar arguments.

Versi ES6 :

function foo() {
  var abc = i => arguments[0];
  console.log(abc(1));
};    
foo(2); // 2

Catatan: fooadalah fungsi ES5, dengan argumentsarray seperti objek dan argumen dilewatkan ke itu 2sehingga arguments[0]untuk fooadalah 2.

abcadalah ES6 panah fungsi karena TIDAK memiliki itu sendiri argumentskarena itu mencetak arguments[0]dari fookonteks luar itu sebagai gantinya.

Varian 7 : Fungsi panah TIDAK miliki thissendiri, mereka bergantung pada konteks luar untukthis

Versi ES5 :

var obj5 = {
  greet: "Hi, Welcome ",
  greetUser : function(user) {
        setTimeout(function(){
        console.log(this.greet + ": " +  user); // "this" here is undefined.
        });
     }
};

obj5.greetUser("Katty"); //undefined: Katty

Catatan: Callback yang diteruskan ke setTimeout adalah fungsi ES5 dan memiliki itu sendiri thisyang tidak terdefinisi di use-strictlingkungan maka kita mendapatkan output:

undefined: Katty

Versi ES6 :

var obj6 = {
  greet: "Hi, Welcome ",
  greetUser : function(user) {
    setTimeout(() => console.log(this.greet + ": " +  user)); 
      // this here refers to outer context
   }
};

obj6.greetUser("Katty"); //Hi, Welcome: Katty

Catatan: Callback yang diteruskan ke setTimeoutadalah fungsi panah ES6 dan TIDAK memiliki itu sendiri thissehingga mengambilnya dari konteks luarnya greetUseryang memiliki thisyang obj6karenanya kita mendapatkan output:

Hi, Welcome: Katty

Lain-lain: Kami tidak dapat menggunakan newdengan fungsi panah. Fungsi panah tidak memiliki prototypeproperti. Kami TIDAK memiliki pengikatan thiskapan fungsi panah dipanggil melalui applyatau call.

Manishz90
sumber
6

Selain jawaban yang bagus sejauh ini, saya ingin menyajikan alasan yang sangat berbeda mengapa fungsi panah dalam arti tertentu secara fundamental lebih baik daripada fungsi JavaScript "biasa". Demi diskusi, mari kita asumsikan sementara kita menggunakan pemeriksa tipe seperti TypeScript atau "Aliran" Facebook. Pertimbangkan modul mainan berikut ini, yang merupakan kode ECMAScript 6 yang valid plus anotasi jenis aliran: (Saya akan memasukkan kode yang tidak diketik, yang secara realistis dihasilkan dari Babel, pada akhir jawaban ini, sehingga benar-benar dapat dijalankan.)

export class C {
  n : number;
  f1: number => number; 
  f2: number => number;

  constructor(){
    this.n = 42;
    this.f1 = (x:number) => x + this.n;
    this.f2 = function (x:number) { return  x + this.n;};
  }
}

Sekarang lihat apa yang terjadi ketika kita menggunakan kelas C dari modul yang berbeda, seperti ini:

let o = { f1: new C().f1, f2: new C().f2, n: "foo" };
let n1: number = o.f1(1); // n1 = 43
console.log(n1 === 43); // true
let n2: number = o.f2(1); // n2 = "1foo"
console.log(n2 === "1foo"); // true, not a string!

Seperti yang Anda lihat, pemeriksa tipe gagal di sini: f2 seharusnya mengembalikan nomor, tetapi mengembalikan string!

Lebih buruk lagi, tampaknya tidak ada pemeriksa tipe yang dapat menangani fungsi JavaScript biasa (non-panah), karena "ini" dari f2 tidak muncul dalam daftar argumen f2, sehingga jenis yang diperlukan untuk "ini" tidak dapat ditambahkan sebagai anotasi ke f2.

Apakah masalah ini juga memengaruhi orang yang tidak menggunakan checker tipe? Saya kira begitu, karena bahkan ketika kita tidak memiliki tipe statis, kita berpikir seolah-olah mereka ada di sana. ("Parameter pertama harus berupa angka, yang kedua adalah string" dll.) Dokumen "this" tersembunyi yang mungkin atau mungkin tidak digunakan dalam tubuh fungsi membuat pembukuan mental kita lebih sulit.

Ini adalah versi untyped runnable, yang akan diproduksi oleh Babel:

class C {
    constructor() {
        this.n = 42;
        this.f1 = x => x + this.n;
        this.f2 = function (x) { return x + this.n; };
    }
}

let o = { f1: new C().f1, f2: new C().f2, n: "foo" };
let n1 = o.f1(1); // n1 = 43
console.log(n1 === 43); // true
let n2 = o.f2(1); // n2 = "1foo"
console.log(n2 === "1foo"); // true, not a string!

Carsten Führmann
sumber
4

Saya masih mendukung semua yang saya tulis dalam jawaban pertama saya di utas ini. Namun, pendapat saya tentang gaya kode telah berkembang sejak saat itu, jadi saya punya jawaban baru untuk pertanyaan ini yang dibangun di atas yang terakhir.

Mengenai leksikal this

Dalam jawaban terakhir saya, saya sengaja menghindari keyakinan mendasar yang saya pegang tentang bahasa ini, karena tidak terkait langsung dengan argumen yang saya buat. Meskipun demikian, tanpa ini dinyatakan secara eksplisit, saya bisa mengerti mengapa banyak orang menolak keras rekomendasi saya untuk tidak menggunakan panah, ketika mereka menemukan panah sangat berguna.

Keyakinan saya adalah ini: kita seharusnya tidak menggunakannya this. Oleh karena itu, jika seseorang dengan sengaja menghindari penggunaan thisdalam kodenya, maka fitur "leksikal this" panah adalah sedikit atau tidak bernilai. Juga, di bawah premis yang thismerupakan hal yang buruk, perlakuan panah terhadap thiskurang dari "hal yang baik;" alih-alih, ini lebih merupakan bentuk kontrol kerusakan untuk fitur bahasa buruk lainnya.

Saya pikir ini tidak terjadi pada beberapa orang, tetapi bahkan bagi mereka yang melakukannya, mereka harus selalu menemukan diri mereka bekerja dalam basis kode di mana thismuncul ratusan kali per file, dan sedikit (atau banyak) kontrol kerusakan adalah semua orang yang berakal bisa berharap. Jadi panah bisa baik, dengan cara, ketika mereka membuat situasi yang buruk menjadi lebih baik.

Bahkan jika lebih mudah untuk menulis kode dengan thispanah daripada tanpa mereka, aturan untuk menggunakan panah tetap sangat kompleks (lihat: utas saat ini). Dengan demikian, pedoman tidak "jelas" atau "konsisten," seperti yang Anda minta. Bahkan jika programmer tahu tentang ambiguitas panah, saya pikir mereka mengangkat bahu dan menerimanya, karena nilai leksikal thismembayangi mereka.

Semua ini adalah kata pengantar untuk realisasi berikut: jika seseorang tidak menggunakan this, maka ambiguitas tentang thispanah yang biasanya menyebabkan menjadi tidak relevan. Panah menjadi lebih netral dalam konteks ini.

Mengenai sintaks singkat

Ketika saya menulis jawaban pertama saya, saya berpendapat bahwa bahkan kepatuhan terhadap praktik terbaik adalah harga yang pantas untuk dibayar jika itu berarti saya dapat menghasilkan kode yang lebih sempurna. Tapi saya akhirnya menyadari bahwa kesederhanaan dapat berfungsi sebagai bentuk abstraksi yang dapat meningkatkan kualitas kode juga - cukup sehingga untuk membenarkan penyimpangan dari praktik terbaik kadang-kadang.

Dengan kata lain: sialan, saya juga ingin fungsi satu-liner!

Tentang pedoman

Dengan kemungkinan thisfungsi panah-netral, dan kesederhanaan yang layak dikejar, saya menawarkan pedoman yang lebih lunak berikut:

Pedoman untuk Notasi Fungsi di ES6:

  • Jangan gunakan this.
  • Gunakan deklarasi fungsi untuk fungsi yang akan Anda panggil dengan nama (karena mereka diangkat).
  • Gunakan fungsi panah untuk panggilan balik (karena mereka cenderung terser).
Jackson
sumber
Setuju 100% dengan bagian "Pedoman Anda untuk Notasi Fungsi di ES6" di bagian bawah - terutama dengan fungsi mengangkat dan panggilan balik inline. jawaban bagus!
Jeff McCloud
1

Secara sederhana,

var a =20; function a(){this.a=10; console.log(a);} 
//20, since the context here is window.

Contoh lain:

var a = 20;
function ex(){
this.a = 10;
function inner(){
console.log(this.a); //can you guess the output of this line.
}
inner();
}
var test = new ex();

Jawab: Konsol akan mencetak 20.

Alasannya adalah setiap kali fungsi dijalankan, stack-nya sendiri dibuat, dalam exfungsi contoh ini dieksekusi dengan newoperator sehingga konteks akan dibuat, dan ketika innerdieksekusi JS akan membuat stack baru dan menjalankan innerfungsi global contextmeskipun ada konteks lokal.

Jadi, jika kita ingin innerfungsi memiliki konteks lokal, exmaka kita perlu mengikat konteks ke fungsi internal.

Panah memecahkan masalah ini, alih-alih mengambil Global contextmereka mengambil local contextjika ada. Dalam given example,itu akan mengambil new ex()sebagai this.

Jadi, dalam semua kasus di mana mengikat adalah Arrows eksplisit menyelesaikan masalah secara default.

Rajendra kumar Vankadari
sumber
1

Fungsi panah atau Lambdas, diperkenalkan dalam ES 6. Terlepas dari keanggunannya dalam sintaks minimal, perbedaan fungsional yang paling menonjol adalah pelingkupan this di dalam fungsi panah

Dalam ekspresi fungsi reguler , thiskata kunci terikat ke nilai yang berbeda berdasarkan konteks yang disebutnya.

Dalam fungsi panah , thisadalah leksikal terikat, yang berarti menutup lebih thisdari lingkup di mana fungsi panah didefinisikan (orang tua-lingkup), dan tidak berubah tidak peduli di mana dan bagaimana ia dipanggil / disebut.

Keterbatasan Panah-Berfungsi sebagai metode pada Objek

// this = global Window
let objA = {
 id: 10,
 name: "Simar",
 print () { // same as print: function() 
  console.log(`[${this.id} -> ${this.name}]`);
 }
}
objA.print(); // logs: [10 -> Simar]
objA = {
 id: 10,
 name: "Simar",
 print: () => {
  // closes over this lexically (global Window)
  console.log(`[${this.id} -> ${this.name}]`);
 }
};
objA.print(); // logs: [undefined -> undefined]

Dalam kasus objA.print()ketika print()metode didefinisikan menggunakan biasa function , itu bekerja dengan menyelesaikan thisdengan benar objAuntuk permohonan metode tetapi gagal ketika didefinisikan sebagai =>fungsi panah . Itu karena thisdalam fungsi reguler ketika dipanggil sebagai metode pada objek ( objA), adalah objek itu sendiri. Namun, dalam kasus fungsi panah, thissecara leksikal terikat pada thislingkup lingkup di mana ia didefinisikan (global / Window dalam kasus kami) dan tetap itu tetap sama selama doa sebagai metode aktif objA.

Keuntungan dari panah-fungsi atas fungsi biasa dalam metode (s) dari suatu objek TETAPI hanya ketika thisdiharapkan diperbaiki & terikat pada definisi waktu.

/* this = global | Window (enclosing scope) */

let objB = {
 id: 20,
 name: "Paul",
 print () { // same as print: function() 
  setTimeout( function() {
    // invoked async, not bound to objB
    console.log(`[${this.id} -> ${this.name}]`);
  }, 1)
 }
};
objB.print(); // logs: [undefined -> undefined]'
objB = {
 id: 20,
 name: "Paul",
 print () { // same as print: function() 
  setTimeout( () => {
    // closes over bind to this from objB.print()
    console.log(`[${this.id} -> ${this.name}]`);
  }, 1)
 }
};
objB.print(); // logs: [20 -> Paul]

Dalam kasus di objB.print()mana print()metode didefinisikan sebagai fungsi yang memanggil console.log([$ {this.id} -> {this.name}] secara )serempak sebagai panggilan balik aktif setTimeout , thisdiselesaikan dengan benar objBketika fungsi panah digunakan sebagai panggilan balik tetapi gagal ketika panggilan balik didefinisikan sebagai fungsi biasa. Itu karena =>fungsi panah dilewatkan untuk setTimeout(()=>..)ditutup thissecara leksikal dari induknya yaitu. doa objB.print()yang didefinisikan itu. Dalam lain-kata, panah =>fungsi berlalu ke untuk setTimeout(()==>...terikat objBsebagai yang thiskarena di doa objB.print() thisitu objBsendiri.

Kita dapat dengan mudah menggunakan Function.prototype.bind(), untuk membuat panggilan balik didefinisikan sebagai fungsi biasa berfungsi, dengan mengikatnya ke yang benar this.

const objB = {
 id: 20,
 name: "Singh",
 print () { // same as print: function() 
  setTimeout( (function() {
    console.log(`[${this.id} -> ${this.name}]`);
  }).bind(this), 1)
 }
}
objB.print() // logs: [20 -> Singh]

Namun, fungsi panah berguna dan lebih sedikit kesalahan rawan untuk kasus async call-backs di mana kita tahu thispada saat definisi fungsi yang didapat dan harus terikat.

Batasan Fungsi Panah di mana ini perlu diubah di seluruh doa

Kapan saja, kita membutuhkan fungsi yang thisdapat diubah pada saat doa, kita tidak bisa menggunakan fungsi panah.

/* this = global | Window (enclosing scope) */

function print() { 
   console.log(`[${this.id} -> {this.name}]`);
}
const obj1 = {
 id: 10,
 name: "Simar",
 print // same as print: print
};
obj.print(); // logs: [10 -> Simar]
const obj2 = {
 id: 20,
 name: "Paul",
};
printObj2 = obj2.bind(obj2);
printObj2(); // logs: [20 -> Paul]
print.call(obj2); // logs: [20 -> Paul]

Tidak satu pun dari yang di atas akan berfungsi dengan fungsi panah const print = () => { console.log([$ {this.id} -> {this.name}] );}karena thistidak dapat diubah dan akan tetap terikat dengan thislingkup lingkup terlampir di mana ia didefinisikan (global / Window). Dalam semua contoh ini, kami memanggil fungsi yang sama dengan objek yang berbeda ( obj1dan obj2) satu demi satu, keduanya dibuat setelah print()fungsi tersebut dinyatakan.

Ini adalah contoh yang dibuat-buat, tapi mari kita pikirkan beberapa contoh kehidupan nyata. Jika kita harus menulis reduce()metode kita mirip dengan yang bekerja arrays , kita lagi tidak dapat mendefinisikannya sebagai lambda, karena itu perlu disimpulkan thisdari konteks doa, yaitu. array yang dipanggil

Untuk alasan ini, constructorfungsi tidak pernah dapat didefinisikan sebagai fungsi panah, karena thisuntuk fungsi konstruktor tidak dapat ditetapkan pada saat deklarasi. Setiap kali fungsi konstruktor dipanggil dengan newkata kunci, objek baru dibuat yang kemudian terikat pada permintaan tertentu.

Juga ketika ketika kerangka kerja atau sistem menerima fungsi panggilan balik yang akan dipanggil nanti dengan konteks dinamis this , kita tidak bisa menggunakan fungsi panah karena lagi thismungkin perlu berubah dengan setiap doa. Situasi ini biasanya muncul dengan penangan acara DOM

'use strict'
var button = document.getElementById('button');
button.addEventListener('click', function {
  // web-api invokes with this bound to current-target in DOM
  this.classList.toggle('on');
});
var button = document.getElementById('button');
button.addEventListener('click', () => {
  // TypeError; 'use strict' -> no global this
  this.classList.toggle('on');
});

Ini juga merupakan alasan mengapa dalam kerangka kerja seperti Angular 2+ dan Vue.js mengharapkan metode pengikatan komponen-templat menjadi fungsi / metode biasa thiskarena permohonan mereka dikelola oleh kerangka kerja untuk fungsi pengikatan. (Angular menggunakan Zone.js untuk mengelola konteks async untuk pemanggilan fungsi pengikatan tampilan-templat).

Di sisi lain, di Bereaksi , ketika kita ingin meneruskan metode komponen sebagai event-handler misalnya <input onChange={this.handleOnchange} />kita harus mendefinisikan handleOnchanage = (event)=> {this.props.onInputChange(event.target.value);}sebagai fungsi panah seperti untuk setiap doa, kita ingin ini menjadi contoh yang sama dari komponen yang menghasilkan JSX untuk di-render Elemen DOM.


Artikel ini juga dapat ditayangkan di publikasi Medium saya . Jika Anda menyukai artile, atau memiliki komentar dan saran, silakan bertepuk tangan atau meninggalkan komentar di Medium .

Simar Singh
sumber