Bir sürü react
kod okuyordum ve anlamadığım bu gibi şeyler görüyorum:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
Bir sürü react
kod okuyordum ve anlamadığım bu gibi şeyler görüyorum:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
Yanıtlar:
İlk olarak, bu fonksiyonu iki parametre ile inceleyin…
const add = (x, y) => x + y
add(2, 3) //=> 5
İşte yine kıvrımlı formda…
const add = x => y => x + y
İşte aynı 1 kodu ok fonksiyonları olmadan…
const add = function (x) {
return function (y) {
return x + y
}
}
Odaklan return
Başka bir şekilde görselleştirmeye yardımcı olabilir. Ok işlevlerinin bu şekilde çalıştığını biliyoruz - geri dönüş değerine özellikle dikkat edelim .
const f = someParam => returnValue
Bizim Yani add
işlevi döndüren işlevi - eklediğimiz netlik için parantezleri kullanabilirsiniz. Kalın metin bizim işlevin dönüş değeriadd
const add = x => (y => x + y)
Başka bir deyişle add
, bazı sayılar bir işlev döndürür
add(2) // returns (y => 2 + y)
Kıvrımlı işlevleri çağırma
Körili fonksiyonumuzu kullanabilmek için biraz farklı çağırmalıyız…
add(2)(3) // returns 5
Bunun nedeni, ilk (dış) işlev çağrısının ikinci (iç) bir işlevi döndürmesidir. Sadece ikinci işlevi çağırdıktan sonra sonucu elde ederiz. Çağrıları iki hatta ayırırsak bu daha belirgindir…
const add2 = add(2) // returns function(y) { return 2 + y }
add2(3) // returns 5
Yeni anlayışımızı kodunuza uygulama
related: “Bağlama, kısmi uygulama ve körelme arasındaki fark nedir?”
Tamam, şimdi bunun nasıl çalıştığını anladığımıza göre, kodunuza bakalım
handleChange = field => e => {
e.preventDefault()
/// Do something here
}
Ok işlevlerini kullanmadan temsil ederek başlayacağız…
handleChange = function(field) {
return function(e) {
e.preventDefault()
// Do something here
// return ...
};
};
Ancak, ok işlevleri sözlüksel olarak bağlandığından this
, aslında daha çok şöyle görünecektir…
handleChange = function(field) {
return function(e) {
e.preventDefault()
// Do something here
// return ...
}.bind(this)
}.bind(this)
Belki şimdi bunun ne yaptığını daha net görebiliyoruz. handleChange
Fonksiyon belirtilen bir işlev yaratıyor field
. Bu kullanışlı bir React tekniğidir, çünkü uygulamalarınızın durumunu güncellemek için her girişte kendi dinleyicilerinizi kurmanız gerekir. handleChange
İşlevi kullanarak, change
her alan için dinleyici ayarlanmasına neden olacak tüm yinelenen kodu kaldırabiliriz . Güzel!
1 Burada this
orijinal add
işlev herhangi bir bağlam kullanmadığı için sözcüksel olarak bağlanmak zorunda kalmadım , bu nedenle bu durumda korumak önemli değil.
Daha da fazla ok
Gerekirse ikiden fazla ok işlevi sıralanabilir -
const three = a => b => c =>
a + b + c
const four = a => b => c => d =>
a + b + c + d
three (1) (2) (3) // 6
four (1) (2) (3) (4) // 10
Körili işlevler şaşırtıcı şeyler yapabilir. Aşağıda $
, iki parametreli bir curried fonksiyon olarak tanımlandığını görüyoruz , ancak çağrı sitesinde, herhangi bir sayıda argüman sağlayabiliriz gibi görünüyor. Currying ait soyutlamadır Arity -
const $ = x => k =>
$ (k (x))
const add = x => y =>
x + y
const mult = x => y =>
x * y
$ (1) // 1
(add (2)) // + 2 = 3
(mult (6)) // * 6 = 18
(console.log) // 18
$ (7) // 7
(add (1)) // + 1 = 8
(mult (8)) // * 8 = 64
(mult (2)) // * 2 = 128
(mult (2)) // * 2 = 256
(console.log) // 256
Kısmi uygulama
Kısmi uygulama ilgili bir kavramdır. Fonksiyonun curried formda tanımlanması gerekmemesi dışında, köriye benzer fonksiyonları kısmen uygulamamıza izin verir -
const partial = (f, ...a) => (...b) =>
f (...a, ...b)
const add3 = (x, y, z) =>
x + y + z
partial (add3) (1, 2, 3) // 6
partial (add3, 1) (2, 3) // 6
partial (add3, 1, 2) (3) // 6
partial (add3, 1, 2, 3) () // 6
partial (add3, 1, 1, 1, 1) (1, 1, 1, 1, 1) // 3
İşte partial
kendi tarayıcınızda oynayabileceğiniz çalışan bir demo -
const partial = (f, ...a) => (...b) =>
f (...a, ...b)
const preventDefault = (f, event) =>
( event .preventDefault ()
, f (event)
)
const logKeypress = event =>
console .log (event.which)
document
.querySelector ('input[name=foo]')
.addEventListener ('keydown', partial (preventDefault, logKeypress))
<input name="foo" placeholder="type here to see ascii codes" size="50">
$
konsepti tanıtmak için kullanıldı, ancak istediğinizi adlandırabilirsiniz. Tesadüfen ama tamamen ilgisiz, $
olan jQuery, gibi sevilen kütüphanelerde kullanılan $
sıralama fonksiyonların tamamını kütüphanesine küresel erişim noktası taşımaktadır. Bence başkalarında da kullanılmış. Gördüğünüz bir diğeri _
, alt çizgi ve lodash gibi kütüphanelerde popüler. Hiçbir sembol diğerinden daha anlamlı değildir; Eğer için anlamını atamak sizin programa. Basitçe geçerli JavaScript: D
$
Nasıl kullanıldığına bakarak daha iyi bir anlayış kazanabilirsiniz . Uygulamanın kendisini soruyorsanız, $
değer alan x
ve yeni bir işlev döndüren bir işlevdir k => ...
. İade fonksiyonun gövdesinde baktığımızda, gördüğümüz k (x)
bildiğimiz bu yüzden k
de bir fonksiyon olmalıdır ve sonucu ne olursa olsun k (x)
geri koymak alır edilir $ (...)
, biz döner başka biliyoruz k => ...
ve ona gider ... hala iseniz takılmak, bana bildirin.
abc(1,2,3)
idealden daha azdır abc(1)(2)(3)
. Kod mantığı hakkında zorlamak ve abc fonksiyonunu okumak zor ve fonksiyon çağrısını okumak daha zor. Sadece abc'nin ne yaptığını bilmeden önce, şimdi abc'nin hangi isimsiz işlevlerin geri döndüğünden emin değilsiniz ve iki kez.
Anlamak ok fonksiyonlarının mevcut sözdizimi size 'zincirleme' örneklerde Sağladığınız gibi zaman tanıtan ne davranış bir anlayış verecektir.
Bir ok işlevi blok parantezleri olmadan, birden fazla parametre ile veya birden çok parametre olmadan yazıldığında, işlevin gövdesini oluşturan ifade dolaylı olarak döndürülür. Örneğin, bu ifade başka bir ok işlevidir.
No arrow funcs Implicitly return `e=>{…}` Explicitly return `e=>{…}`
---------------------------------------------------------------------------------
function (field) { | field => e => { | field => {
return function (e) { | | return e => {
e.preventDefault() | e.preventDefault() | e.preventDefault()
} | | }
} | } | }
Ok sözdizimini kullanarak anonim işlevler yazmanın bir diğer avantajı, tanımlandıkları kapsama sözcüksel olarak bağlı olmalarıdır. MDN'deki 'Ok işlevleri' nden :
Bir ok işlevi, ifade ile karşılaştırıldığında daha kısa bir söz dizimi olan işlev ifadeleri ve lexically bağlanan bu değer. Ok işlevleri her zaman anonimdir .
Bu, örneğinizde özellikle bir reactjsuygulama. @ Naomik tarafından işaret edildiği gibi, React'te sıklıkla bir bileşenin üye işlevlerine kullanarak erişirsiniz this
. Örneğin:
Unbound Explicitly bound Implicitly bound
------------------------------------------------------------------------------
function (field) { | function (field) { | field => e => {
return function (e) { | return function (e) { |
this.setState(...) | this.setState(...) | this.setState(...)
} | }.bind(this) |
} | }.bind(this) | }
Genel bir ipucu, yeni JS sözdizimi ve nasıl derleneceği konusunda kafanız karışırsa, babel'i kontrol edebilirsiniz . Örneğin, kodunuzu babil'e kopyalamak ve es2015 ön ayarını seçmek, böyle bir çıktı verir
handleChange = function handleChange(field) {
return function (e) {
e.preventDefault();
// Do something here
};
};
Bunu şöyle düşünün, her ok gördüğünüzde onun yerini alırsınız function
. function parameters
oktan önce tanımlanır.
Yani örneğinizde:
field => // function(field){}
e => { e.preventDefault(); } // function(e){e.preventDefault();}
ve sonra birlikte:
function (field) {
return function (e) {
e.preventDefault();
};
}
// Basic syntax:
(param1, param2, paramN) => { statements }
(param1, param2, paramN) => expression
// equivalent to: => { return expression; }
// Parentheses are optional when there's only one argument:
singleParam => { statements }
singleParam => expression
this
.
Kısa ve basit 🎈
Kısa bir şekilde yazılmış başka bir işlevi döndüren bir işlevdir.
const handleChange = field => e => {
e.preventDefault()
// Do something here
}
// is equal to
function handleChange(field) {
return function(e) {
e.preventDefault()
// Do something here
}
}
İnsanlar neden bunu yapıyor ❓
Özelleştirilebilen bir işlev yazmanız gerektiğinde karşılaştınız mı? Veya sabit parametreleri (bağımsız değişkenler) olan bir geri çağırma işlevi yazmak zorundasınız, ancak işleve daha fazla değişken iletmeniz gerekiyor, ancak genel değişkenlerden kaçınıyor musunuz? Cevabınız " evet " ise, bunu yapmanın yolu budur.
Örneğin, bir button
onClick geri araması var . Ve id
fonksiyona geçmemiz gerekiyor , ancak onClick
sadece bir parametreyi kabul ediyor event
, bu şekilde ekstra parametreler geçiremiyoruz:
const handleClick = (event, id) {
event.preventDefault()
// Dispatch some delete action by passing record id
}
Çalışmayacak!
Bu nedenle, global değişkenler kötülük 😈 olduğundan, diğer değişkenleri kendi değişkenleri kapsamı ile başka bir işlev döndürecek bir işlev yaparız.
Aşağıda fonksiyon handleClick(props.id)}
çağrılır ve bir fonksiyon döndürülür id
ve kapsamı içinde olur! Kaç kez basılacağına bakılmaksızın, id'ler birbirini etkilemez veya değiştirmez, tamamen izole edilirler.
const handleClick = id => event {
event.preventDefault()
// Dispatch some delete action by passing record id
}
const Confirm = props => (
<div>
<h1>Are you sure to delete?</h1>
<button onClick={handleClick(props.id)}>
Delete
</button>
</div
)
Sorunuzdaki örnek , ilk argüman için curried function
kullanılan arrow function
ve bir olan bir implicit return
.
Ok işlevi sözlü olarak bunu bağlar, yani kendi this
argümanları yoktur, ancak this
değeri ekteki kapsamdan alırlar
Yukarıdaki kodun eşdeğeri,
const handleChange = (field) {
return function(e) {
e.preventDefault();
/// Do something here
}.bind(this);
}.bind(this);
Örneğiniz hakkında dikkat edilmesi gereken bir şey daha handleChange
, bir sabit veya işlev olarak tanımlanmasıdır. Muhtemelen bir sınıf yönteminin parçası olarak kullanıyorsunuz veclass fields syntax
yani dış işlevi doğrudan bağlamak yerine, sınıf yapıcısına bağlarsınız
class Something{
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(field) {
return function(e) {
e.preventDefault();
// do something
}
}
}
Örnekte dikkat edilmesi gereken başka bir şey, örtük ve açık dönüş arasındaki farktır.
const abc = (field) => field * 2;
Yukarıda örtük getiri örneği örnektir. değer alanını bağımsız değişken olarak alır ve döndürülecek field*2
işlevi açıkça belirten sonucu döndürür
Açık bir getiri için, açıkça değeri döndürme yöntemini söylerdiniz
const abc = () => { return field*2; }
Ok işlevleri ile ilgili not edilmesi gereken bir başka şey de, kendilerine sahip olmamaları, arguments
ancak ebeveynlerin kapsamından da miras almalarıdır.
Örneğin, sadece bir ok işlevi
const handleChange = () => {
console.log(arguments) // would give an error on running since arguments in undefined
}
Alternatif bir ok fonksiyonu olarak kullanabileceğiniz dinlenme parametreleri
const handleChange = (...args) => {
console.log(args);
}
Tamamen ilgili olmayabilir, ancak bahsedilen soru davayı kullandığından (ve bu SO iş parçacığına çarpmaya devam ediyorum): Burada açıkça belirtilmeyen çift ok işlevinin önemli bir yönü var. Yalnızca 'ilk' ok (işlev) adlandırılır (ve böylece çalışma zamanı tarafından 'ayırt edilebilir'), aşağıdaki oklar anonimdir ve React bakış açısından her render'da 'yeni' nesne olarak sayılır.
Böylece çift ok işlevi, herhangi bir PureComponent bileşeninin her zaman yeniden oluşturulmasına neden olur.
Misal
Değişiklik işleyicisine sahip bir üst bileşene sahipsiniz:
handleChange = task => event => { ... operations which uses both task and event... };
ve şöyle bir render ile:
{
tasks.map(task => <MyTask handleChange={this.handleChange(task)}/>
}
daha sonra bir girişte veya tıklamada kullanılır. Ve hepsi işe yarıyor ve çok hoş görünüyor. ANCAK, ebeveynin yeniden ilişkilendirilmesine neden olacak herhangi bir değişikliğin (tamamen ilgisiz bir durum değişikliği gibi) PureComponent olsalar bile MyTask'ınızın TÜMÜNÜ de yeniden oluşturacağı anlamına gelir.
Bu, 'en' oku ve onu besleyeceğiniz veya özel bir shouldUpdate işlevi yazmak veya adlandırılmış işlevler yazmak (ve bunu manuel olarak bağlamak ...) gibi temel bilgilere geri dönmek gibi birçok yolu hafifletebilir.