ES2015'te adlandırılmış bir ok işlevini nasıl yazarım?


204

ES6'da yeni ok sözdizimine dönüştürmeye çalıştığım bir işlevim var . Bu adlandırılmış bir işlevdir:

function sayHello(name) {
    console.log(name + ' says hello');
}

Var ifadesi olmayan bir ad vermenin bir yolu var mı:

var sayHello = (name) => {
    console.log(name + ' says hello');
}

Açıkçası bu işlevi ancak tanımladıktan sonra kullanabilirim. Aşağıdaki gibi bir şey:

sayHello = (name) => {
        console.log(name + ' says hello');
    }

ES6'da bunu yapmanın yeni bir yolu var mı ?


3
Ok noktası sözdiziminin işleve bir ad vermemesi değil mi?
AstroCB

64
Mutlaka değil, ok işlevleri sözcüksel kapsamı korur, bu nedenle sözcüksel kapsamla adlandırılmış işlevler üretmek için bir stile sahip olmak (yığın izlemesi için yararlıdır) oldukça yararlı olacaktır
Matt Styles

6
İkinci pasajdaki sorun nedir?
Bergi

Kesinlikle işlevin gövdesi içinde atanmış bir ada başvurabilirsiniz: var sayHello = (name) => {console.log (sayHello); }; Ve özyinelemeli işlevler söz konusu olduğunda, genellikle tam olarak bunu yaparsınız. Süper kullanışlı bir örnek değil, ancak argümanını almazsa kendini döndüren bir işlev var: var sayHello = (name) => name? Console.log (name + 'merhaba' diyor)): sayHello; sayHello () ( 'Frank'); // -> "frank merhaba diyor"
Dtipson

4
Sorunun başlığı içeriğine göre oldukça yanıltıcıdır, çünkü ok işlevlerini (ikinci snippettir) adlandırma şeklinizi dışladınız.
TJ Crowder

Yanıtlar:


212

ES2015'te adlandırılmış bir ok işlevini nasıl yazarım?

Sorunuzu dışladığınız şekilde yaparsınız: Bir ödevin veya özellik başlatıcısının sağ tarafına, değişken veya özellik adının JavaScript motoru tarafından bir ad olarak makul bir şekilde kullanılabileceği yere koyarsınız. Bunu yapmanın başka bir yolu yok, ancak bunu yapmak doğru ve tam olarak şartname kapsamındadır.

Özelliklere göre, bu işlevin gerçek bir adı vardır sayHello:

var sayHello = name => {
    console.log(name + ' says hello');
};

Bu, Atama İşleçleri> Çalışma Zamanı Semantiği: Değerlendirme işlemini soyut SetFunctionNameişlemi çağırdığı yerde tanımlanır (bu çağrı şu anda 1.e.iii adımındadır).

Benzer şekilde, Çalışma Zamanı Semantiği: PropertyDefinitionEvaluation çağırır SetFunctionNameve böylece bu işleve gerçek bir ad verir:

let o = {
    sayHello: name => {
        console.log(`${name} says hello`);
    }
};

Modern motorlar zaten böyle ifadeler için işlevin dahili adını ayarlar; Edge hala nameçalışma zamanı bayrağının arkasındaki işlev örneğinde olduğu gibi kullanılabilir .

Örneğin, Chrome veya Firefox'ta web konsolunu açın ve ardından bu snippet'i çalıştırın:

"use strict";
let foo = () => { throw new Error(); };
console.log("foo.name is: " + foo.name);
try {
  foo();
} catch (e) {
  console.log(e.stack);
}

Chrome 51 ve üstü ve Firefox 53 ve üstü (ve deneysel bir işaretle Edge 13 ve üstü), bunu çalıştırdığınızda şunları görürsünüz:

foo.name: foo
Hata
    foo'da (http://stacksnippets.net/js:14:23)
    http://stacksnippets.net/js:17:3

Not foo.name is: foove Error...at foo.

Chrome 50 ve öncesi, Firefox 52 ve öncesi ve deney bayrağı olmayan Edge'de, bunun yerine Function#name(henüz) mülke sahip olmadıkları için bunu görürsünüz :

foo.name: 
Hata
    foo'da (http://stacksnippets.net/js:14:23)
    http://stacksnippets.net/js:17:3

Adı eksik olduğunu not foo.name is:, ancak bir yığın izleme gösterilmiştir. Sadece name özelliğin fonksiyon üzerinde uygulanmasının diğer ES2015 özelliklerinden daha düşük önceliğe sahip olması; Chrome ve Firefox şimdi var; Edge'de bir bayrağın arkasında var, muhtemelen bayrağın arkasında çok daha uzun olmayacak.

Açıkçası, bu işlevi ancak tanımladıktan sonra kullanabilirim

Doğru. Ok işlevleri için işlev bildirimi sözdizimi yoktur , yalnızca işlev ifadesi sözdizimi yoktur ve işlev ifadesi ( var f = function foo() { };) adında eski bir stildeki ada eşdeğer bir ok yoktur . Yani şuna eşdeğer yok:

console.log(function fact(n) {
    if (n < 0) {
        throw new Error("Not defined for negative numbers");
    }
    return n == 0 ? 1 : n * fact(n - 1);
}(5)); // 120

Bunu iki ifadeye bölmelisiniz ( yine de yapmanız gerektiğini iddia ediyorum ) :

let fact = n => {
    if (n < 0) {
      throw new Error("Not defined for negative numbers.");
    }
    return n == 0 ? 1 : n * fact(n - 1);
};
console.log(fact(5));

Eğer değilse, doğal olması tek ifade gereklidir nereye koymak için her zaman ... bir ok işlevini kullanabilirsiniz:

console.log((() => {
    let fact = n => {
        if (n < 0) {
            throw new Error("Not defined for negative numbers.");
        }
        return n == 0 ? 1 : n * fact(n - 1);
    };
    return fact(5);
})()); // 120

Bunun güzel olduğunu söylemiyorum, ama kesinlikle tek bir ifade sarmalayıcısına ihtiyacınız varsa işe yarıyor.


Adın ayarlanmasını nasıl önleyebilirim (eski motorlarda olduğu gibi)?
trusktr

1
@trusktr: Neden istediğini anlayamıyorum, ama bunu önlemek istiyorsan: Yukarıdaki şeyleri yapma. Örneğin let f = () => { /* do something */ };, işleve bir ad atar let g = (() => () => { /* do something */ })();, değil.
TJ Crowder

Sonunda bunu yaptım. Sınıf miras kitaplığım tarafından, sınıf miras kitaplığı kullanıcısının düşünmesi gerekmeyen iç değişkenlerin adlarına sahip olmak yerine, anonim olarak oluşturulmuş anonim sınıflar olmasını tercih ediyorum ve son kullanıcının bir ad görmesini istiyorum sadece sınıfa bir isim verdiyse. ( github.com/trusktr/lowclass )
trusktr

4
@trusktr: Yaptıkları tek istisna amaçlarınıza uygun olabilir, o zaman: Varolan bir nesnenin özelliğine bir işlev atarsanız , ad ayarlanmaz: o.foo = () => {};işleve bir ad vermez. Bu , bilgi sızıntısını önlemek için bilerek yapılmıştır .
TJ Crowder

Görünüşe göre bazı cihazlarda yerel tepki
ver

86

Hayır. Ok sözdizimi anonim işlevlerin kısa biçimidir. İsimsiz fonksiyonlar isimsizdir.

Adlandırılmış işlevler functionanahtar sözcükle tanımlanır .


16
@ DenysSéguret tarafından belirtildiği gibi, anonim işlevler için bir kısa biçim değildir . Sabit bağlı bir fonksiyon elde edersiniz . Aktarılan sonucu burada görebilirsiniz bit.do/es2015-arrow bunun ne anlama geldiğini daha iyi anlamak için ...
sminutoli

16
Bu cevabın ilk kelimesi sorulan soru için doğrudur çünkü OP bir ok fonksiyonunu adlandırma şeklinizi reddetmiştir. Ancak cevabın geri kalanı yanlıştır. Soyut SetFunctionNameişlemin kullanıldığı teknik özelliklere bakın . hem teknik özelliklere hem de modern motorlara göre adlandırılmış bir işlevi let a = () => {};tanımlar (addır ) (görmek için bir hata atın); henüz mülkü desteklemiyorlar (ancak spesifikasyonda ve sonunda oraya ulaşacaklar). aname
TJ Crowder

4
@ DenysSéguret: Sen edebilirsiniz basitçe onlara isim, bu spec içinde. OP'nin soruda dışladığı şekilde yaparsınız, bu da işleve (sadece değişken değil) gerçek bir ad verir.
TJ Crowder

5
@TJCrowder Bu biraz bilgi ve faydalı cevabınız için teşekkürler . Bu (çok çok garip) özelliği bilmiyordum.
Denys Séguret

4
Bu cevap doğru değil. Soru doğru cevap @TJCrowder tarafından
Drenai

47

'Named' ile .nameok işlevinizin özelliğinin ayarlanmasını istiyorsanız, şanslısınız demektir.

Bir atama ifadesinin sağ tarafında bir ok işlevi tanımlanmışsa, motor sol taraftaki adı alır ve ok işlevini ayarlamak için kullanır .name, örn.

var sayHello = (name) => {
    console.log(name + ' says hello');
}

sayHello.name //=== 'sayHello'

Bunu söyledikten sonra, sorunuz daha fazla 'vinç çekmek için bir ok işlevi alabilir miyim?' Gibi görünüyor. Bunun cevabı büyük bir 'hayır' olmasından korkuyorum.


1
Chrome'un şu anki sürümünde, en azından sayHello.name hala ""; Tüm işlevler gibi sayHello'nun da bir nesne olduğunu unutmayın, böylece isterseniz rastgele özellikler tanımlayabilirsiniz. "Name" öğesine salt okunur olduğu için yazamazsınız, ancak diyebilirsinizHello.my_name = "sayHello"; Sizi ne aldığından emin değilim, çünkü bunu işlev gövdesi içinde yapamazsınız.
Dtipson

2
Yanılmışım: İsim doğrudan değiştirilemese de, bunu şu şekilde yapılandırabilirsiniz: Object.defineProperty (sayHello, 'name', {value: 'sayHello'})
Dtipson

1
"Eğer sağ tarafta bir ok fonksiyonu tanımlanmışsa [..]" bunun kaynağı nedir? Spesifikasyonda bulamıyorum. Alıntı yapmak için sadece bir referansa ihtiyacınız var.
Gajus

@Dtipson: Bunun nedeni, modern motorların nameES2015 spesifikasyonunun gerektirdiği her yerde özelliği ayarlamamış olmasıdır; onlar buna ulaşacaklar. Chrome uyumluluk listesindeki son şeylerden biri ve Chrome 50'de bile yok (Chrome 51 sonunda olacak). Ayrıntılar . Ancak OP özellikle bunu yapmaya karar verdi (tuhaf bir şekilde).
TJ Crowder

Bu adı toString'e alabilir miyim? Geçersiz kılmaya çalıştım, ama sonra işlev gövdesine nasıl erişeceğimi bilmiyorum.
Qwerty

0

Bunun ES7 ile mümkün olduğu görülüyor: https://babeljs.io/blog/2015/06/07/react-on-es6-plus#arrow-functions

Verilen örnek şöyledir:

class PostInfo extends React.Component {
  handleOptionsButtonClick = (e) => {
    this.setState({showOptionsModal: true});
  }
}

ES6 ok işlevlerinin gövdesi, bunları çevreleyen kodla aynı sözcük bilgisini paylaşır, bu da ES7 özellik başlatıcılarının kapsamı nedeniyle bize istenen sonucu verir.

Babil ile bu çalışmayı sağlamak için en deneysel ES7 aşama 0 sözdizimini etkinleştirmem gerektiğini unutmayın. Webpack.config.js dosyamda babel yükleyiciyi şöyle güncelledim:

{test: /\.js$/, exclude: /node_modules/, loader: 'babel?stage=0'},

6
Bu tam olarak adlandırılmış bir ok işlevi değil. Bu, kurucuda örnek yöntemleri oluşturmak için bir kısayoldur ve bunun nasıl alakalı olduğunu merak ediyorum.
Bergi

Merhaba @Bergi, bunun orijinal yazarın amacı olup olmadığından emin değilim, ancak nesne ile aynı kapsamda bir adlandırılmış işlev oluşturmaya çalışıyordum. Eğer bu tekniği kullanmazsak ve sınıf yapıcısına dahil etmemiz gereken uygun kapsamı elde etmek istiyorsak. this.handleOptionsButtonClick = this.handleOptionsButtonClick.bind(this);
Hamish Currie

8
Eh, constructor() { this.handleOptionsButtonClick = (e) => {…}; }cevabınızdaki koda tamamen eşdeğer olan, ancak zaten ES6'da çalışan bu kadar kolay kullanabilirsiniz . Kullanmanıza gerek yok .bind.
Bergi

1
Btw, "adlandırılmış işlev" ile "(örnek) yöntemi" ve "kapsam" ile " thisbağlam" karıştırdığınızı düşünüyorum
Bergi

1
@tdecs: Evet yapabilirsiniz; Jörg yanılıyor. adlı adlandırılmış bir ok işlevini let a = () => {};tanımlar . Ayrıntılar . a
TJ Crowder

0

Aslında ok işlevlerini (en azından krom 77'den itibaren ...) adlandırmanın bir yolu bunu yapmaktır:

"use strict";
let fn_names = {};
fn_names.foo = () => { throw new Error(); };
console.log("foo.name is: " + foo.name);
try {
  foo();
} catch (e) {
  console.log(e.stack);
}

resim açıklamasını buraya girin


teorik olarak fn('yourName', ()=>{})% 100 doğru ok fonksiyon semantiğini koruyabilen bir babil makrosu oluşturabilir veya daha iyisi "adlandırılmış ok fonksiyonu sözdizimi" için bir babel eklentisi oluşturabilir fn yourName() => {}. Bunların her ikisi de yukarıdaki koda kadar derlenir. Bence oklar öyle olurdu BADA55
Devin G Rhode

-1

Ben LoginClass adında bir sınıf var ve bu sınıf içinde ben yazdım sen adam feryat örneği can adlı ok işlevini yazmak için adlandırılmış işlevi ok adlı successAuth sınıf LoginClass {

    constructor() {

    }

    successAuth = (dataArgs)=> { //named arow function

    }

}

1
Yanıt olarak gönderdiğiniz koda bir açıklama eklemek her zaman daha iyidir, böylece ziyaretçilerin bunun neden iyi bir cevap olduğunu anlamalarına yardımcı olur.
abarisone

Bu OP yapması istemiyor söylediklerini yapar ve güvenir bu teklife sadece Stage 2'de ve belki de ES2017 yapacak değil mi (ama ES2018 yapma olasılığı olduğunu düşünüyorum ve transpilers bunu destekledi Aylarca). Ayrıca, önceki birkaç cevabı etkili bir şekilde çoğaltır, bu da yararlı değildir.
TJ Crowder

-2

BU ES6

Evet, peşinde olduğun şeyin böyle bir şey olduğunu düşünüyorum:

const foo = (depth) => {console.log("hi i'm Adele")}
foo -> // the function itself
foo() -> // "hi i'm Adele"

Bu örneği denedim, iyi çalışıyor. Olumsuz oy vermek için iyi bir neden var mı? Bu kullanım istenmeyen herhangi bir yan etki yaratıyor mu veya önemli bir noktayı kaçırıyor muyum? Şüphelerimi netleştirmedeki yardımınız takdir edilecektir.
FullMoon

@GaneshAdapa: Downvotes bekliyorum çünkü bu OP'nin tam olarak yapmak istemediği şeyi daha fazla bilgi vermeden yapmasını öneriyor.
TJ Crowder

-2

İşlevler oluşturmak için işlev bölümünü ve ok bölümünü atlayabilirsiniz. Misal:

 class YourClassNameHere{

   constructor(age) {
     this.age = age;
   }

   foo() {
     return "This is a function with name Foo";
   }

   bar() {
     return "This is a function with name bar";
   }

 }

let myVar = new YourClassNameHere(50);
myVar.foo();
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.