ECMAScript 6'da Ok işlevlerini ne zaman kullanmalıyım?


406

Soru, yaklaşan ECMAScript 6 (Harmony) bağlamında kod stilini düşünen ve zaten dil ile çalışmış kişilere yöneliktir.

İle () => {}ve function () {}biz ES6 içinde işlevlerini yazmak için iki çok benzer yollar alıyoruz. Diğer dillerde lambda işlevleri genellikle anonim olarak ayırt edilir, ancak ECMAScript'te herhangi bir işlev anonim olabilir. İki türün her biri benzersiz kullanım alanlarına sahiptir (yani thisaçık bir şekilde veya açık bir şekilde bağlı olmaması gerektiğinde). Bu alanlar arasında, gösterimlerin her ikisinin de gerçekleştirileceği çok sayıda durum vardır.

ES6'daki ok işlevlerinin en az iki sınırı vardır:

  • İle çalışma newve oluştururken kullanılamazprototype
  • thisBaşlatma sırasında kapsama bağlı sabit

Bu iki sınırlama bir yana, ok işlevleri teorik olarak neredeyse her yerde normal işlevlerin yerini alabilir. Bunları pratikte kullanmak için doğru yaklaşım nedir? Ok işlevleri kullanılmalı mı, örneğin:

  • "çalıştıkları her yerde", yani bir fonksiyonun thisdeğişken hakkında agnostik olması gerekmiyor ve biz bir nesne yaratmıyoruz .
  • yalnızca "ihtiyaç duydukları her yerde", yani belirli bir kapsama bağlı olması gereken olay dinleyicileri, zaman aşımları
  • 'kısa' işlevlerle ancak 'uzun' işlevlerle değil
  • yalnızca başka bir ok işlevi içermeyen işlevlerle

Ne arıyorum ECMAScript gelecekteki sürümünde uygun işlev gösterimi seçmek için bir kılavuzdur. Kılavuzun, bir takımdaki geliştiricilere öğretilebilmesi ve bir işlev göstergesinden diğerine sürekli olarak yeniden düzenleme gerektirmemesi için tutarlı olması gerekir.


33
Fixed this bound to scope at initialisationBir sınırlama olarak mı düşünüyorsunuz ?
thefourtheye

12
Bu bir avantajdır, ancak işlevi orijinal bağlamın dışında yeniden kullanmayı planlıyorsanız da bir sınırlama olabilir. Örneğin Object.prototype aracılığıyla bir sınıfa dinamik olarak bir işlev eklerken. 'Sınırlama' ile kastettiğim, değerini değiştirmek thisnormal işlevlerle yapabileceğiniz, ancak ok işlevleriyle yapamayacağınız bir şeydir.
lyschoening

1
Dürüst olmak gerekirse, kodlama stili yönergelerinin oldukça fikirli olduğunu düşünüyorum. Beni yanlış anlamayın, bence önemli, ama herkes için uygun tek bir kılavuz yok.
Felix Kling

Fixed this bound to scope at initialisationBir sınırlama olduğunu düşünmüyorum . :) Bu makaleye bir göz atın: exploringjs.com/es6/ch_arrow-functions.html
NgaNguyenGün

3
@thefourtheye, "sınırlama" burada "sınırlama anlamına gelir, çünkü aptal bir otomatik kod çevirmeni birbirini körü körüne değiştiremez ve her şeyin beklendiği gibi çalışacağını varsayar".
Pacerier

Yanıtlar:


322

Bir süre önce ekibimiz tüm kodunu (orta büyüklükteki AngularJS uygulaması) Traceur Babel kullanarak derlenen JavaScript'e taşıdı . Şimdi ES6 ve ötesindeki işlevler için aşağıdaki temel kuralı kullanıyorum:

  • functionGlobal kapsamda ve Object.prototypeözellikler için kullanın .
  • classNesne yapıcılar için kullanın .
  • =>Başka her yerde kullanın .

Neden hemen hemen her yerde ok fonksiyonlarını kullanıyorsunuz?

  1. Kapsam güvenliği: Ok işlevleri sürekli kullanıldığında, her şeyin thisObjectkökle aynı şekilde kullanılması garanti edilir . Tek bir standart işlev geri çağrısı bile bir grup ok işleviyle karıştırılmışsa, kapsamın dağılması ihtimali vardır.
  2. Kompaktlık: Ok işlevlerinin okunması ve yazılması daha kolaydır. (Bu görüş gibi görünebilir, bu yüzden daha fazla birkaç örnek vereceğim).
  3. Netlik: Hemen hemen her şey bir ok işlevi olduğunda, herhangi bir düzenli functionhemen kapsamı tanımlamak için dışarı çıkar. Bir geliştirici, functionne olduğunu görmek için her zaman bir sonraki en yüksek ifadeyi arayabilir thisObject.

Neden daima global kapsamda veya modül kapsamında düzenli işlevler kullanıyorsunuz?

  1. İşlevine erişmemesi gereken bir işlevi belirtmek için thisObject.
  2. windowNesne (küresel kapsam) en iyi açıkça ele olduğunu.
  3. Birçok Object.prototypetanım küresel kapsamda (düşün String.prototype.truncatevb.) Yaşar ve bunların genel olarak functionyine de tür olması gerekir . functionGlobal kapsamda sürekli kullanmak hataların önlenmesine yardımcı olur.
  4. Küresel kapsamdaki birçok işlev, eski stil sınıf tanımları için nesne oluşturuculardır.
  5. Fonksiyonlar 1 olarak adlandırılabilir . Bunun iki faydası vardır: (1) Özellikle diğer işlev çağrılarının dışında yazmak function foo(){}daha az gariptir const foo = () => {}. (2) İşlev adı yığın izlerinde gösterilir. Her dahili geri çağrıyı adlandırmak sıkıcı olsa da, tüm ortak işlevleri adlandırmak muhtemelen iyi bir fikirdir.
  6. İşlev bildirimleri kaldırılır (yani, bildirilmeden önce erişilebilirler), bu da statik bir yardımcı program işlevinde yararlı bir özelliktir.


Nesne yapıcılar

Bir ok işlevini başlatmaya çalışmak bir istisna atar:

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

Bu nedenle işlevlerin ok işlevlerine göre önemli bir avantajı, nesne oluşturucu olarak işlev görmesidir:

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

Ancak, işlevsel olarak özdeş 2 ES Harmony taslak sınıfı tanımı neredeyse kompakttır:

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

Önceki gösterimin kullanımının sonunda ertelenmesini bekliyorum. Nesne yapıcı gösterimi, bazılarının nesnelerin programlı olarak oluşturulduğu basit başka anonim nesne fabrikaları için kullanılabilir, ancak başka bir şey için kullanılamaz.

Bir nesne yapıcıya ihtiyaç duyulduğunda, fonksiyon classyukarıda gösterildiği gibi a'ya dönüştürülmelidir . Sözdizimi anonim işlevlerle / sınıflarla da çalışır.


Ok fonksiyonlarının okunabilirliği

Düzenli işlevlere bağlı kalmanın en iyi argümanı - kapsam güvenliği lanet olası - ok işlevlerinin normal işlevlerden daha az okunabilir olmasıdır. Kodunuz ilk etapta işlevsel değilse, ok işlevleri gerekli görünmeyebilir ve ok işlevleri sürekli kullanılmadığında çirkin görünürler.

ECMAScript 5.1 bize fonksiyonel verdi beri ECMAScript biraz değişti Array.forEach, Array.mapve bizi var bu işlevsel programlama özellikleri için-döngüler önce kullanılmış olurdu işlevlerini kullanın. Zaman uyumsuz JavaScript biraz çıkmıştır. ES6 ayrıca bir Promisenesne gönderecektir , bu da daha anonim işlevler anlamına gelir. Fonksiyonel programlama için geri dönüş yoktur. İşlevsel JavaScript'te, ok işlevleri normal işlevlere göre tercih edilir.

Örneğin bu (özellikle kafa karıştırıcı) kod 3 parçasını ele alalım :

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;
        })
}

Normal işlevlerle aynı kod parçası:

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));
}

Ok işlevlerinden herhangi biri standart bir işlevle değiştirilebilse de, bunu yaparak elde etmek için çok az şey olacaktır. Hangi sürüm daha okunabilir? İlkini söylerdim.

Ok fonksiyonlarının mı yoksa normal fonksiyonların mı kullanıldıkları sorusunun zamanla daha az alakalı hale geleceğini düşünüyorum. Çoğu işlev ya functionanahtar sözcükten uzaklaşan sınıf yöntemleri veya sınıf haline gelir. Fonksiyonlar sınıfları yamalamak için kullanımda kalacaktır Object.prototype. Bu arada, functionanahtar kelimeyi gerçekten bir sınıf yöntemi veya bir sınıf olması gereken herhangi bir şey için ayırmanızı öneririm .


notlar

  1. Adlandırılmış ok işlevleri ES6 spesifikasyonunda ertelenmiştir . Yine de gelecekteki bir sürüm eklenebilir.
  2. Taslak belirtime göre, "sınıf bildirimleri / ifadeleri , sınıf extendanahtar kelimeyi kullanmadığı sürece, yapıcı işlev / prototip çiftini tam olarak işlev bildirimleri için oluşturur" . Küçük bir fark, sınıf bildirimlerinin sabit olması, işlev bildirimlerinin olmamasıdır.
  3. Tek deyimli ok işlevlerindeki bloklar hakkında not: Yalnızca yan etki için (örneğin atama) bir ok işlevinin çağrıldığı her yerde bir blok kullanmayı seviyorum. Bu şekilde, dönüş değerinin atılabileceği açıktır.

4
Kullanmak istediğiniz bir diğer zaman , sınırlanmak functionistemediğiniz zamandır this, değil mi? Bunun için en yaygın senaryom this, olayı tetikleyen nesneye (genellikle DOM düğümü) başvurmak isteyebileceğiniz olaylardır.
Brett

13
Aslında örnek 3'te normal işlevlerin daha okunabilir olduğunu düşünüyorum. Programcı olmayanlar bile olanları ilahi yapabilirler. Oklarla, bu örneği anlamak için tam olarak nasıl çalıştıklarını bilmeniz gerekir. Belki daha fazla yeni satır ok örneğine yardımcı olabilir, ama bilmiyorum. Sadece 2 sentim ama oklar beni kandırıyor (ama henüz kullanmadım, bu yüzden yakında dönüştürülebilirim.)
Spencer

3
@ Spencer adil bir nokta. Kendi deneyimlerime göre, =>zamanla daha iyi görünmeye başlar. Programcı olmayanların iki örnek hakkında çok farklı hissedeceklerinden şüpheliyim. ES2016 kodunu yazıyorsanız, normalde bu çok sayıda ok işlevini de kullanmayacaksınız. Bu örnekte, async / await ve bir dizi kavrama kullanarak, reduce()çağrıda yalnızca bir ok işlevi elde edersiniz .
48

3
Spencer'a bu örnekte normal işlevlerin çok daha okunabilir olduğuna tamamen katılıyorum.
jonschlinkert

2
İyi cevap, teşekkürler! şahsen ben de küresel kapsamdaki okları mümkün olduğunca kullanıyorum. Bu beni neredeyse hiç 'işlev' bırakmıyor. Bana göre koddaki bir 'işlev', dışarı çıkması ve dikkatle değerlendirilmesi gereken özel bir durum anlamına gelir.
kofifus

80

Teklife göre , oklar "geleneksel olan birkaç ortak ağrı noktasına hitap etmek ve çözmek Function Expression". Bunlar thissözcüksel olarak bağlanarak ve kısa sözdizimi sunarak konuları iyileştirmeyi amaçladılar .

Ancak,

  • Kişi sürekli thisolarak sözcük olarak bağlanamaz
  • Ok işlevi sözdizimi hassas ve belirsiz

Bu nedenle, ok işlevleri karışıklık ve hatalar için fırsatlar yaratır ve bir JavaScript programcısının kelime haznesinin dışında bırakılmalıdır. function .

Sözlük ile ilgili this

this sorunlu:

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

Ok işlevleri this, geri arama içindeki bir özelliğe erişmemiz gereken sorunu gidermeyi amaçlamaktadır . Bunu yapmanın zaten birkaç yolu vardır: Bir thisdeğişkene atanabilir bind, Arraytoplama yöntemlerinde kullanılabilen 3. bağımsız değişkeni kullanabilir veya kullanabilirsiniz . Yine de oklar en basit çözüm gibi görünmektedir, bu nedenle yöntem şu şekilde yeniden düzenlenebilir:

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

Ancak, kodun yöntemleri thisözel olarak bağlanan jQuery gibi bir kitaplık kullanıp kullanmadığını göz önünde bulundurun . Şimdi, thisele alınması gereken iki değer var:

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

Biz kullanmalıdır functioniçin sıraylaeachthisDinamik olarak bağlamak . Burada bir ok işlevi kullanamayız.

Birden fazla thisdeğerle uğraşmak da kafa karıştırıcı olabilir, çünkü thisbir yazarın hangi konu hakkında konuştuğunu bilmek zordur :

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

Yazar gerçekten aramak istiyor muydu Book.prototype.reformat? Yoksa bağlanmayı thisve aramayı planladı Reader.prototype.reformatmı? İşleyiciyi bir ok işlevine değiştirirsek, benzer şekilde yazarın dinamiği isteyip istemediğini merak eder this, ancak bir satıra sığdığı için bir ok seçer:

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

Birisi şu şekilde olabilir: "Okların bazen yanlış bir işlev olması istisnai olabilir mi? Belki de nadiren dinamik thisdeğerlere ihtiyacımız olursa , çoğu zaman okları kullanmakta sorun olmaz."

Ama kendinize şunu sorun: "Kod hatalarını ayıklamak ve bir hatanın sonucunun bir 'son durum tarafından getirildiğini bulmak' buna değer mi? '" Zamanın% 100'ü.

Daha iyi bir yol var: Her zaman kullanın function(böylece thisher zaman dinamik olarak bağlanabilir) ve her zaman thisbir değişken aracılığıyla referans alın . Değişkenler sözcükseldir ve birçok isim varsayarlar. thisBir değişkene atamak niyetlerinizi netleştirecektir:

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

Ayrıca, her zamanthis bir değişkene atamak (tek bir thisfonksiyon olsa bile veya başka bir fonksiyon olmasa bile) kod değiştirildikten sonra bile niyetlerinin net kalmasını sağlar.

Ayrıca, dinamik thisneredeyse istisnai değildir. jQuery 50 milyondan fazla web sitesinde kullanılmaktadır (Şubat 2016'da bu yazıdan itibaren). thisDinamik olarak bağlanan diğer API'lar şunlardır :

  • Mocha (~ 120 bin indirme) dün için test metotları ortaya koyuyor this.
  • Grunt (~ 63k indirme dün) üzerinden görevleri oluşturmak için yöntemler ortaya koymaktadır this.
  • Omurga (dün ~ 22 bin indirme) erişim yöntemlerini tanımlar this.
  • Etkinlik API'ları (DOM'lar gibi) bir EventTargetile ilgilidir this.
  • Yamalı veya uzatılmış prototip API'leri, ile olan örnekleri ifade eder this.

( Http://trends.builtwith.com/javascript/jQuery ve https://www.npmjs.com üzerinden istatistikler .)

thisZaten dinamik bağlamalar gerektiriyor olabilirsiniz .

Sözcük bilgisi thisbazen beklenir, bazen beklemez ; tıpkı bir dinamik thisbeklendiği gibi bazen de beklenmiyor. Neyse ki, her zaman beklenen bağlamayı üreten ve ileten daha iyi bir yol var.

Kısa sözdizimi ile ilgili

Ok işlevleri, işlevler için "daha kısa sözdizimsel form" sağlamada başarılı olmuştur. Ancak bu daha kısa fonksiyonlar sizi daha başarılı kılacak mı?

x => x * xdaha "kolay okunur" function (x) { return x * x; }? Belki de öyle, çünkü tek, kısa bir kod satırı üretme olasılığı daha yüksektir. Dyson'a göre Okuma hızı ve satır uzunluğunun ekrandan okumanın etkinliği üzerindeki etkisi ,

Normal ve yüksek hızlarda etkili okumayı desteklemek için orta satır uzunluğu (satır başına 55 karakter) görünür. Bu, en yüksek düzeyde kavrayışı sağlamıştır. . .

Koşullu (üçlü) operatör ve tek satırlı ififadeler için benzer gerekçeler yapılır .

Ancak, teklifte tanıtılan basit matematiksel fonksiyonları gerçekten yazıyor musunuz? Etki alanlarım matematiksel değil, bu yüzden altyordamlarım nadiren çok zarif. Aksine, ok işlevlerinin bir sütun sınırını kırdığını ve Dyson'un tanımına göre "okunabilirliği" geçersiz kılan editör veya stil kılavuzu nedeniyle başka bir satıra sarıyorum.

"Mümkün olduğunda kısa fonksiyonlar için kısa versiyonu kullanmaya ne dersiniz?" Ancak şimdi stilistik bir kural, bir dil kısıtlamasıyla çelişmektedir: "Bazen yalnızca en uzun gösterimin thisbeklendiği gibi bağlanacağını aklınızda tutarak, mümkün olan en kısa işlev gösterimini kullanmaya çalışın ." Bu tür bir birleşim okları özellikle yanlış kullanıma eğilimli hale getirir.

Ok işlevi sözdiziminde çok sayıda sorun var:

const a = x =>
    doSomething(x);

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

Bu işlevlerin her ikisi de sözdizimsel olarak geçerlidir. Ancak doSomethingElse(x);, bsadece zayıf girintili, üst düzey bir ifadedir.

Blok formuna genişletilirken, artık returngeri yüklenmeyi unutabilecek bir örtük yoktur . Ancak ifadenin yalnızca bir yan etki yaratması amaçlanmış olabilir , bu yüzden returnileride açık bir ifadenin gerekli olup olmayacağını kim bilebilir ?

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);
};

Dinlenme parametresi olarak düşünülmesi gerekenler, yayma işleci olarak ayrıştırılabilir:

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

Atama varsayılan bağımsız değişkenlerle karıştırılabilir:

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

Bloklar nesneler gibi görünür:

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

Ne anlama geliyor?

() => {}

Yazar boş bir nesne veya boş bir nesne döndüren bir işlev mi yaratmayı planladı? (Bunu göz önünde bulundurarak, daha {sonra yerleştirmeliyiz =>mi? Kendimizi yalnızca ifade sözdizimiyle sınırlamalı mıyız? Bu, okların sıklığını daha da azaltacaktır.)

=>şöyle görünür <=ve >=:

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

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

Bir ok işlevi ifadesini hemen çağırmak için, kişinin ()dışarıya yerleştirilmesi gerekir , ancak ()içeriye yerleştirmek geçerlidir ve kasıtlı olabilir.

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

Her ne kadar, kişi (() => doSomething()());hemen çağrılmış bir işlev ifadesi yazmak niyetiyle yazarsa, hiçbir şey olmayacaktır.

Yukarıdaki tüm durumlar göz önünde bulundurularak ok işlevlerinin "daha anlaşılır" olduğunu iddia etmek zor. Bir olabilirdi bu sözdizimini kullanmak için gerekli tüm özel kuralları öğrenirler. Gerçekten buna değer mi?

Sözdizimi functionalışılmadık şekilde genelleştirilmiştir. Özel olarak kullanmak function, dilin kendisinin kafa karıştırıcı kod yazmasını engellediği anlamına gelir. Her durumda sözdizimsel olarak anlaşılması gereken prosedürleri yazmak için seçiyorum function.

Kılavuz hakkında

"Açık" ve "tutarlı" olması gereken bir yönerge istersiniz. Ok işlevlerinin kullanılması sonuçta sözdizimsel olarak geçerli, mantıksal olarak geçersiz bir kodla sonuçlanır ve her iki işlev formu da anlamlı ve isteğe bağlı olarak iç içe geçer. Bu nedenle, aşağıdakileri sunuyoruz:

ES6'daki İşlev Gösterimi için Kılavuz:

  • Her zaman ile prosedürler oluşturun function.
  • Her zaman thisbir değişkene atayın . Kullanmayın () => {}.

5
Fonksiyonel bir programcının JavaScript hakkındaki görüşüne ilginç bir yazı. Özel değişkenler argümanına katıldığımdan emin değilim. IMO çok az insanın onlara gerçekten ihtiyacı var; Bunu yapanlar muhtemelen başka sözleşme özelliklerine de ihtiyaç duyacak ve yine de TypeScript gibi bir dil uzantısı kullanacaklardır. Kesinlikle selfbunun yerine cazibesini görebiliyorum . Belirtilen ok işlevi tuzaklarınız da geçerlidir ve parantez olmadan gidebilecek diğer ifadelerle aynı standartlar burada da geçerlidir; Aksi takdirde, sizin argümanınızla birlikte, her yerde ok işlevlerini de savunabileceğinizi düşünüyorum.
lyschoening

7
"Bir şeyler yapmanın birden fazla yoluna sahip olmak, işyerinde ve dil topluluğunda tartışmalar ve tartışmalar için gereksiz vektörler yaratır. Dil gramerinin kötü seçimler yapmamıza izin vermemesi daha iyi olurdu." Çok katılıyorum. Güzel yazı! Bence ok fonksiyonları aslında bir adım geri. Farklı bir konuda, arkadaşlarımın bir dizi .prototype tanımıyla JavaScript'i C #'a çevirmeye çalışmasını dilerdim. İğrenç.
Spencer

11
Çok iyi yazılmış! Puanlarınızın çoğuna katılmama rağmen, karşıt bakış açısını dikkate almak önemlidir.
minexew

4
Ok işlevleri değil, garip davranışı thisJavascript sorunudur. Örtük olarak bağlı olmak yerine, thisaçık bir argüman olarak geçirilmelidir.
bob

5
Msgstr " Her zaman fonksiyonu kullan (böylece her zaman dinamik olarak bağlanabilir) ve buna her zaman bir değişken aracılığıyla başvur. " Daha fazla anlaşamadım!

48

Ok fonksiyonları , fonksiyonu basitleştirmek scopeve thisanahtar kelimeyi daha basit hale getirerek çözmek için oluşturulmuştur . =>Ok gibi görünen sözdizimini kullanırlar .

Not: Mevcut işlevlerin yerini almaz. Her işlev sözdizimini ok işlevleriyle değiştirirseniz, her durumda çalışmaz.

Mevcut ES5 sözdizimine bir göz atalım, thisAnahtar kelime bir nesnenin yönteminin içindeyse (bir nesneye ait bir işlev), ne anlama gelirdi?

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

Yukarıdaki pasaj bir an anlamına gelir objectve adı yazdırır "RajiniKanth". Aşağıdaki kod parçacığını keşfedelim ve bunun ne anlama geldiğini görelim.

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

Actor.showMovies();

Peki, thisanahtar kelimenin içinde olup olmadığına ne dersiniz method’s function?

İşte bu ifade ediyorum window objectdaha inner functiononun düşmüş olarak üzerinden scope. Çünkü this, her zaman içinde bulunduğu işlevin sahibine başvurur, bu durumda - şimdi kapsam dışında olduğu için - pencere / global nesne.

Bir object'yöntemin içindeyken - function' ın sahibi nesnedir. Bu nedenle, bu anahtar kelime nesneye bağlıdır. Yine de, tek başına veya başka bir yöntemde bir işlevin içindeyse, her zaman window/globalnesneye atıfta bulunacaktır .

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

fn(); // [object Window]

Bu sorunu ES5kendi başımıza çözmenin yolları var, ES6 ok işlevlerini nasıl çözeceğine dalmadan önce buna bakalım.

Genellikle, yöntemin iç işlevinin dışında bir değişken yaratırsınız. Şimdi ‘forEach’yöntem this, object’sözelliklere ve değerlerine erişim kazanır .

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();

yöntemine bindgönderme yapan thisanahtar kelimeyi 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();

Şimdi ES6ok işlevi ile, lexical scopingsorunu daha basit bir şekilde ele alabiliriz.

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

Actor.showMovies();

Arrow functionsonlar dışında daha fonksiyon ifadeleri gibi bindbuna parent scope. Eğer arrow function is in top scope, thisargüman sevk edecektir window/global scopedüzenli işlevi içinde bir ok fonksiyonu dış işleviyle aynı onun bu argümanı var ise,.

İle arrowfonksiyonları thiskapatmakta bağlı scopeyaratma zamanda ve değiştirilemez. Yeni operatör, bağlama, arama ve uygulama işlemlerinin bunun üzerinde bir etkisi yoktur.

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

Yukarıdaki örnekte, bunun kontrolünü kaybettik. Yukarıdaki örneği değişken bir referans thiskullanarak veya kullanarak çözebiliriz bind. ES6 ile thisbağlı olduğu gibi yönetilmesi daha kolay hale gelir 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

Ok işlevlerine ne zaman

Bir nesnenin tam anlamıyla.

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

Actor.getName();

Actor.getNamebir ok fonksiyonu ile tanımlanır, fakat çağırma tanımsız uyarıları this.nameolan undefinedbağlamı kalır window.

Bunun nedeni, ok işlevinin bağlamı window object... yani dış kapsamla sözcüksel olarak bağlamasıdır . Yürütme this.name, window.nametanımsız olan eşdeğerdir .

Nesne prototipi

Aynı kural, a prototype object. SayCatName yöntemini tanımlamak için yanlış bir işlev getiren bir ok işlevi kullanmak yerine 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

Yapıcıları çağırmak

thisbir inşaat çağrısında yeni oluşturulan nesne. ) (Yeni Fn yürütürken, bağlam constructor Fnyeni nesnesidir: this instanceof Fn === true.

this çevreleyen bağlamdan, yani yeni oluşturulan nesneye atanmamış olmasını sağlayan dış kapsamdan ayarlanır.

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

Dinamik içerikli geri arama

Ok işlevi contextstatik olarak bildirime bağlanır ve dinamik hale getirmek mümkün değildir. DOM öğelerine olay dinleyicileri eklemek, istemci tarafı programlamasında yaygın bir görevdir. Bir olay, işleyici işlevini bununla hedef öğe olarak tetikler.

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

thisgenel bağlamda tanımlanan bir ok işlevindeki penceredir. Bir click olayı gerçekleştiğinde, tarayıcı düğme bağlamıyla işleyici işlevini çağırmaya çalışır, ancak ok işlevi önceden tanımlanmış bağlamını değiştirmez. this.innerHTMLeşittir window.innerHTMLve hiçbir anlamı yoktur.

Hedef öğeye bağlı olarak bunu değiştirmeye izin veren bir işlev ifadesi uygulamanız gerekir:

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

Kullanıcı düğmeyi tıklattığında, işleyici işlevindeki bu düğmedir. Böylece this.innerHTML = 'Clicked button', düğme metnini tıklanan durumu yansıtacak şekilde doğru şekilde değiştirir.

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


İtiraf etmeliyim ki, "en iyisi ortadadır" . İfade için önerilen, ok işlevlerinin olası işlev kullanım durumlarını kapsamamasıdır. Gerçekten ortak sorunların sadece bir kısmını çözmek için tasarlanmıştır. Onlara tamamen geçmek aşırıya kaçacak.
BlitZ

@DmitriPavlutin: Güncellenmiş yazımı kontrol edin, çok şey var ... belki bir referans göndermeliyim.
Thalaivar

2
'Yöntemi kullanarak yöntemin iç işlevine başvuran bu anahtar kelimeyi eklemek için bind kullanma' satırından sonraki kodunuz. içinde hatalar var. Diğer örneklerinizi test ettiniz mi?
Isaac Pak

Birinde using bind to attach the this keyword that refers to the method to the method’s inner function.sözdizimi hataları var.
Coda Chang

Olmalı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();
Coda Chang

14

Ok fonksiyonları - şimdiye kadar en çok kullanılan ES6 özelliği ...

Kullanım: Aşağıdaki senaryolar dışında tüm ES5 işlevleri ES6 ok işlevleriyle değiştirilmelidir:

Ok işlevleri KULLANILMAMALIDIR:

  1. İşlevsel kaldırma istediğimizde
    • çünkü ok işlevleri anonimdir.
  2. this/ argumentsBir işlevde kullanmak istediğimizde
    • ok işlevlerinin kendilerine ait olmadığı this/ argumentsdışsal bağlamlarına bağlı oldukları için.
  3. Adlandırılmış işlevi kullanmak istediğimizde
    • çünkü ok işlevleri anonimdir.
  4. Fonksiyonu bir constructor
    • çünkü ok fonksiyonlarının kendi fonksiyonları yoktur this.
  5. Nesne hazır bilgisinde özellik olarak işlev eklemek ve içinde nesne kullanmak istediğimizde
    • erişemediğimiz için this(nesnenin kendisi olmalıdır).

Daha iyi anlamak için ok fonksiyonlarının bazı varyantlarını anlayalım:

Değişke 1 : Bir işleve birden fazla argüman iletip işlevden bir değer döndürmek istediğimizde.

ES5 sürümü :

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

ES6 sürümü :

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

Not: functionanahtar kelime gerekli DEĞİLDİR. =>gerekli. {}isteğe bağlı olarak, sağladığımız {} returnzaman JavaScript tarafından örtük olarak eklenir ve sağladığımızda {}ihtiyaç duyduğumuzda eklememiz returngerekir.

Değişke 2 : SADECE bir argümanı bir işleve geçirmek ve ondan bir değer döndürmek istediğimizde.

ES5 sürümü :

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

ES6 sürümü :

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

Not: Sadece bir argümanı geçerken parantezini atlayabiliriz ().

Değişke 3 : Bir işleve herhangi bir argüman iletmek istemediğimizde ve herhangi bir değer döndürmek istemediğimizde.

ES5 sürümü :

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

ES6 sürümü :

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

Değişke 4 : Açıkça ok işlevlerinden dönmek istediğimizde.

ES6 sürümü :

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

Değişke 5 : Bir nesneyi ok işlevlerinden döndürmek istediğimizde.

ES6 sürümü :

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

Not: Nesneyi parantez içine almamız gerekir, ()aksi takdirde JavaScript bir blok ve bir nesne arasında ayrım yapamaz.

Değişke 6 : Ok işlevleri arguments, kendi dış bağlamına bağlı olarak kendilerine ait DEĞİL (dizi benzeri bir nesne) yoktur arguments.

ES6 sürümü :

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

Not: foobir ile bir ES5 fonksiyonudur argumentsbu da bir nesne gibi dizisi ve geçirilen bir bağımsız değişken 2çok arguments[0]için foo2'dir.

abco, kendi var ETMEZ beri ES6 işlevi ok ise argumentso yazdırır dolayısıyla arguments[0]bir fooyerine 's dış bağlamda.

Değişke 7 : Ok fonksiyonlarının thiskendilerine ait OLMAMALIDIR .this

ES5 sürümü :

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

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

Not: setTimeout'a iletilen geri arama bir ES5 işlevidir ve kendi ortamında vardır, bu thisda use-strictortamda tanımlanmamıştır, bu nedenle çıktı alırız:

undefined: Katty

ES6 sürümü :

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

Not: geçirilen geri arama setTimeoutişlevi ok ve, kendi var ETMEZ bir ES6 olduğunu thisöyle dış bağlam var dan bunu alır, böylece greetUsersahip olduğu thisolmasıdır obj6biz çıktıyı almak dolayısıyla:

Hi, Welcome: Katty

Çeşitli:new Ok işlevleriyle kullanamayız . Ok fonksiyonlarının prototypeözelliği yoktur. Biz bağlanmasının OLMAYAN thisfonksiyonu aracılığıyla çağrıldığında ok zaman applyya call.


6

Şimdiye kadarki harika yanıtlara ek olarak, ok işlevlerinin belirli bir anlamda temel olarak "sıradan" JavaScript işlevlerinden daha iyi olmasının çok farklı bir nedenini sunmak istiyorum. Tartışma amacıyla, geçici olarak TypeScript veya Facebook'un "Flow" gibi bir tür denetleyicisi kullandığımızı varsayalım. Geçerli ECMAScript 6 kodu artı Akış tipi ek açıklamaları olan aşağıdaki oyuncak modülünü göz önünde bulundurun: (Bu cevabın sonunda, Babel'den gerçekçi olarak ortaya çıkacak türlenmemiş kodu ekleyeceğim, böylece gerçekten çalıştırılabilir.)

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;};
  }
}

Şimdi C sınıfını farklı bir modülden kullandığımızda neler olduğunu görün, şöyle:

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!

Gördüğünüz gibi , tür denetleyicisi başarısız oldu burada : f2'nin bir sayı döndürmesi gerekiyordu, ancak bir dize döndürdü!

Daha kötüsü, öyle görünüyor ki akla yatkın bir tür denetleyicisinin sıradan (ok olmayan) JavaScript işlevlerini işleyemeyeceği , çünkü f2'nin "this" ifadesi f2 bağımsız değişken listesinde oluşmuyor, bu nedenle "this" için gereken tür muhtemelen eklenemedi f2'ye ek açıklama olarak.

Bu sorun tip denetleyicisi kullanmayan kişileri de etkiliyor mu? Sanırım, çünkü statik tipimiz olmasa bile, sanki oradalarmış gibi düşünüyoruz. ("İlk parametreler bir sayı, ikincisi bir dize olmalıdır" vb.) İşlevin vücudunda kullanılabilecek veya kullanılamayacak gizli bir "bu" argümanı zihinsel defter tutmayı zorlaştırır.

İşte Babel tarafından üretilen çalıştırılabilir tiplenmemiş versiyon:

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!



3

Hala ilk cevabımda yazdığım her şeyin yanındayım bu konudaki yanındayım. Ancak, kod stili hakkındaki düşüncem o zamandan beri gelişti, bu yüzden son soruya dayanan bu soruya yeni bir cevabım var.

Sözlük ile ilgili this

Son cevabımda, doğrudan bu yaptığım argümanla ilgili olmadığından, bu dil hakkında sahip olduğum temel bir inancı kasten savundum. Bununla birlikte, bu açıkça belirtilmeden, birçok insanın okları kullanmama tavsiyemde neden okları bu kadar yararlı bulduklarında neden eğildiğini anlayabiliyorum.

İnancım şu: thisilk etapta kullanmamalıyız. Bu nedenle, bir kişi kasıtlı olarak thiskodunda kullanmaktan kaçınırsa this, okların “sözcüksel ” özelliği çok azdır veya hiç değeri yoktur. Ayrıca, thiskötü bir şey olan öncül altında , okun tedavisi this“iyi bir şey” den daha azdır; bunun yerine, başka bir kötü dil özelliği için bir tür hasar kontrolü biçimidir.

Bunun ya bazı insanlarda gerçekleşmediğini, ancak yaptığı kişilerde bile, kendilerini sürekli olarak kod tabanlarında çalışırken bulmaları gerektiğini anlıyorum. this dosya başına yüz kez görünen ve biraz (veya çok) hasar kontrolü hepsi makul bir insan umut edebilir. Böylece oklar kötü bir durumu daha iyi hale getirdiklerinde iyi olabilirler.

thisOklarla birlikte kod yazmayı onlar olmadan yapmak daha kolay olsa da, okları kullanma kuralları çok karmaşıktır (bkz: geçerli iş parçacığı). Bu nedenle, yönergeler istediğiniz gibi “net” veya “tutarlı” değildir. Programcılar okların belirsizlikleri hakkında bilgi sahibi olsalar bile, bence omuzlarını silkiyor ve kabul ediyorlar, çünkü sözcüklerin değeri thisonları gölgede bırakıyor.

Bütün bunlar aşağıdaki gerçekleşmenin bir önsözüdür: eğer biri kullanmazsa this, o zaman thisokların normalde neden olduğu belirsizliği önemsiz hale gelir. Bu bağlamda oklar daha tarafsız hale gelir.

Kısa sözdizimi ile ilgili

İlk cevabımı yazdığımda, en iyi uygulamalara körü körüne bağlılığın bile, daha mükemmel bir kod üretebileceğim anlamına gelirse ödemek için değerli bir fiyat olduğu kanaatindeydim. Ama sonunda, tersliğin kod kalitesini de artırabilecek bir soyutlama biçimi olarak hizmet edebileceğini fark ettim - bazen en iyi uygulamalardan sapmayı haklı çıkarmak için yeterli.

Başka bir deyişle: dammit, ben de tek katmanlı fonksiyonlar istiyorum!

Kılavuz hakkında

this-Nötr ok fonksiyonları ve kıvamı takip etmeye değer olma olasılığı ile , aşağıdaki daha yumuşak kılavuzları sunuyoruz:

ES6'daki İşlev Gösterimi için Kılavuz:

  • Kullanma this.
  • Ada göre çağırdığınız işlevler için işlev bildirimlerini kullanın (kaldırıldıkları için).
  • Geri aramalar için ok işlevlerini kullanın (çünkü bunlar ters olma eğilimindedir).

Altta bulunan "ES6'daki İşlev Gösterimi Kılavuzu" bölümünüzle - özellikle kaldırma ve satır içi geri arama işlevleriyle% 100 anlaşın. güzel cevap!
Jeff McCloud

1

Basit bir şekilde,

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

Başka bir örnek:

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();

Cvp: Konsol 20 yazdıracaktı.

Bunun nedeni, bir işlev yürütüldüğünde kendi yığını oluşturulur, bu örnek exişlevde işleçle yürütülür, newböylece bir bağlam oluşturulur ve inneryürütüldüğünde JS yeni bir yığın oluşturur ve innerişlevi global contextbir yerel bağlam.

Dolayısıyla, innerişlevin yerel bir bağlama sahip olmasını istiyorsak , exo zaman bağlamı iç işleve bağlamamız gerekir.

Oklar bu problemi çözer Global context, local contexteğer varsa alırlarsa alırlar . İçinde olarak given example,alacaktır .new ex()this

Bu nedenle, bağlamanın açık olduğu tüm durumlarda Oklar sorunu varsayılan olarak çözer.


1

Ok işlevleri veya Lambdas, ES 6'da tanıtıldı. Minimum sözdizimindeki zarafetinin yanı sıra, en önemli fonksiyonel fark bir ok işlevinin kapsamını kapsamaktadır.this

Gelen düzenli işlev ifadeleri, thisanahtar kelime dayalı farklı değerlere bağlı bağlamda denir ki.

İn ok fonksiyonları , thisbir lexically bu fazla kapatır, yani bağlanmış thisok işlevi (üst-kapsamını) tanımlandığı bir kapsamından ve ne olursa olsun ve nasıl çağrılır / adı değiştirmez.

Bir Nesnede yöntem olarak Sınırlamalar Ok Fonksiyonları

// 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]

Durumunda objA.print()iken print()yöntemi düzenli kullanılarak tanımlanır function , bu gidererek çalıştı thisdüzgün objAyöntem çağırma için değil bir ok olarak tanımlanan zaman başarısız =>işlevi. Bunun nedeni this, bir nesnede ( objA) yöntem olarak çağrıldığında normal bir işlevde nesnenin kendisidir. Bununla birlikte, bir ok işlevi olması durumunda , tanımlandığı kapalı kapsama (söz konusu durumda küresel / Pencere) thisbağlanır thisve bir yöntem olarak çağrılması sırasında aynı kalır objA.

Bir ok işlevinin this, ancak zaman tanımında sabitlenmesi ve bağlanması beklendiğinde , bir nesnenin yöntem (ler) indeki normal işlevlere göre avantajları .

/* 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]

Durumunda usul fonksiyonu olarak tanımlanan başlatır edilir [$ {this.id} -> {this.name}] senkronize olmayan bir geri arama olarak  , doğru giderilmiş bir ok fonksiyonu geri arama olarak kullanıldığı zaman, ancak başarısız geri arama normal işlev olarak tanımlandığında. Bunun nedeni, ok işlevinin üst öğesinden yani sözlü olarak kapalı duruma geçmesidir. çağırma tanımladı. Diğer bir deyişle-ok işlev geçirilen bağlı onun şekilde çağırma nedeniyle olduğu kendisi.objB.print()print()console.log()setTimeoutthisobjB=>setTimeout(()=>..)thisobjB.print()=>setTimeout(()==>...objBthisobjB.print() thisobjB

Function.prototype.bind()Düzenli bir işlev olarak tanımlanan geri çağrıyı doğru şekilde bağlayarak kolayca kullanabiliriz 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]

Bununla birlikte, ok işlevleri kullanışlı ve daha az hata eğilimi gösterir, burada async geri çağırmaları durumunda this, işlev tanımının alındığı ve bağlanması gereken zamanı biliyoruz .

Bunun invokasyonlar arasında değişmesi gereken Ok Fonksiyonlarının Sınırlandırılması

Her thiszaman, çağırma sırasında değiştirilebilen fonksiyona ihtiyacımız var , ok fonksiyonlarını kullanamayız.

/* 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]

Ok fonksiyonu ile yukarıdaki irade işin Yok const print = () => { console.log([$ {this.id} -> {this.name}] );}olarak thisdeğiştirilemez ve bağlı kalacak thiso tanımlandı kapatan kapsam (küresel / Pencere) arasında. Tüm bu örneklerde, her ikisi de işlev bildirildikten sonra oluşturulan , aynı işlevi farklı nesnelerle ( obj1ve obj2birbiri ardına) print()çağırdık.

Bunlar birbiri ardına örneklerdi, ama biraz daha gerçek hayat örnekleri üzerinde düşünelim. reduce()Metodumuzu üzerinde çalışan bir metoda benzer şekilde yazmak zorunda arrays kalsaydık, tekrar lambda olarak tanımlayamayız, çünkü çıkarım yapması gerekirthis çağırma bağlamından , yani. çağrıldığı dizi

Bu nedenle, yapıcı işlev bildirimi sırasında ayarlanamadığı için constructorişlevler asla ok işlevleri olarak tanımlanamaz this. Her zaman bir yapıcı işlevi çağrılırnewAnahtar kelime , o çağrıyla ilişkili yeni bir nesne oluşturulur.

Ayrıca, çerçeveler veya sistemler daha sonra dinamik bağlamla çağrılmak üzere bir geri çağırma işlevini / işlevlerini kabul ettiğinde this , ok işlevlerini kullanamayız, çünkü thisher çağrıda tekrar değişmesi gerekebilir. Bu durum genellikle DOM olay işleyicileriyle ortaya çıkar

'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');
});

Bu ayrıca Angular 2+ ve Vue.js gibi çerçevelerde şablon bileşen bağlama yöntemlerinin thisçağırma gibi düzenli işlev / yöntem olmasını beklemelerinin sebebi de bağlayıcı işlevlerin çerçeveleri tarafından yönetilir. (Açısal, görünüm şablonu bağlama işlevlerinin çağrılması için zaman uyumsuz içeriği yönetmek için Zone.js'yi kullanır).

Öte yandan, React'te , bir bileşenin yöntemini bir olay işleyici olarak geçirmek istediğimizde, örneğin her çağrı için olduğu gibi bir ok işlevi olarak <input onChange={this.handleOnchange} />tanımlamamız gerekir handleOnchanage = (event)=> {this.props.onInputChange(event.target.value);}, bunun, işlenen için JSX'i oluşturan bileşenin aynı örneği olmasını istiyoruz DOM öğesi.


Bu makale aynı zamanda Medium yayınımda da kullanılabilir . Artile gibi, ya da herhangi bir görüş ve önerileriniz, lütfen varsa alkış veya izin comments on Orta .

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.