CoffeeScript'te bir sınıf oluştururken, tüm örnek yöntemi =>
("yağ oku") işleci ve tüm statik yöntemler ->
işleci kullanılarak tanımlanmalı mıdır?
CoffeeScript'te bir sınıf oluştururken, tüm örnek yöntemi =>
("yağ oku") işleci ve tüm statik yöntemler ->
işleci kullanılarak tanımlanmalı mıdır?
Yanıtlar:
Hayır, kullanacağım kural bu değil.
Yöntemleri tanımlarken fat-arrow için bulduğum en büyük kullanım örneği, bir yöntemi geri arama olarak kullanmak istediğinizde ve bu yöntem örnek alanlarına başvurduğunda:
class A
constructor: (@msg) ->
thin: -> alert @msg
fat: => alert @msg
x = new A("yo")
x.thin() #alerts "yo"
x.fat() #alerts "yo"
fn = (callback) -> callback()
fn(x.thin) #alerts "undefined"
fn(x.fat) #alerts "yo"
fn(-> x.thin()) #alerts "yo"
Gördüğünüz gibi, yağ-okunu kullanmıyorsanız, bir örneğin yöntemine bir geri arama olarak bir referans iletmekte sorun yaşayabilirsiniz. Bunun nedeni, yağ-okunun nesnenin örneğini bağlamasıdır, this
ancak ince-ok, yukarıdaki gibi geri çağırma olarak adlandırılan ince ok yöntemleri, örneğin alanlarına erişemez @msg
veya başka örnek yöntemleri çağıramaz. Son satır, ince okun kullanıldığı durumlar için bir geçici çözüm vardır.
this
İnce oktan çağrılacak olanı kullanmak istediğinizde , aynı zamanda şişman okla alacağınız örnek değişkenleri ne yapmak istiyorsunuz?
this
kullanmak istediğim bir değişkene ayarlandığını varsayalım . Ancak, ben de bir sınıf yöntemi this
başvurmak istiyorum, bu yüzden de sınıfa başvurmak istiyorum . Ben sadece bir ödev arasında seçim yapabilirsiniz this
, bu yüzden her iki değişken kullanmak için en iyi yolu nedir?
Dikkat edilmesi gereken diğer cevaplarda belirtilmeyen bir nokta, gerekli olmadığında yağ okuyla bağlanma işlevlerinin, bu örnekte sadece DummyClass olarak adlandıracağımız bir sınıf gibi istenmeyen sonuçlara yol açabileceğidir.
class DummyClass
constructor : () ->
some_function : () ->
return "some_function"
other_function : () =>
return "other_function"
dummy = new DummyClass()
dummy.some_function() == "some_function" # true
dummy.other_function() == "other_function" # true
Bu durumda işlevler tam olarak ne beklediğini yapar ve yağ okunu kullanmanın hiç bir kaybı yoktur, ancak DummyClass prototipini önceden tanımlandıktan sonra değiştirdiğimizde ne olur (örneğin, bazı uyarıları değiştirme veya bir günlük çıktısını değiştirme) :
DummyClass::some_function = ->
return "some_new_function"
DummyClass::other_function = ->
return "other_new_function"
dummy.some_function() == "some_new_function" # true
dummy.other_function() == "other_new_function" # false
dummy.other_function() == "other_function" # true
Prototipin daha önce tanımlanmış fonksiyonumuzu geçersiz kıldığını görebileceğimiz gibi, some_function'un üzerine yazılmasına neden oluyor, ancak other_function, yağ okunun sınıftaki other_function'un tüm örneklere bağlanmasına neden olduğu durumlarda aynı kalıyor, böylece örnekler sınıflarına geri dönmeyecek bir işlev bulmak
DummyClass::other_function = =>
return "new_other_new_function"
dummy.other_function() == "new_other_new_function" # false
second_dummy = new DummyClass()
second_dummy.other_function() == "new_other_new_function" # true
Şişman ok bile şişman ok olarak işlev görmez, sadece işlevin yeni örneklere bağlanmasına neden olur (beklendiği gibi yeni işlevleri kazanır).
Ancak bu bazı sorunlara yol açar, ya var olan tüm örneklerde (olay işleyicileri dahil) çalışacak bir işleve (örneğin bir günlük tutma işlevini bir çıkış kutusuna veya başka bir şeye geçirme durumunda) ihtiyacımız olursa [kullanamayız orijinal tanımdaki yağ okları], ancak yine de bir olay işleyicideki dahili niteliklere erişmemiz gerekiyor [ince okları değil yağ oklarını kullanmamızın kesin nedeni].
Bunu başarmanın en basit yolu, sadece orijinal sınıf tanımına iki işlevi dahil etmektir, biri yürütmek istediğiniz işlemleri yapan ince bir okla tanımlanmış, diğeri ise ilk işlevi çağırmaktan başka bir şey yapmayan bir yağ oku ile tanımlanmıştır. Örneğin:
class SomeClass
constructor : () ->
@data = 0
_do_something : () ->
return @data
do_something : () =>
@_do_something()
something = new SomeClass()
something.do_something() == 0 # true
event_handler = something.do_something
event_handler() == 0 # true
SomeClass::_do_something = -> return @data + 1
something.do_something() == 1 # true
event_handler() == 1 # true
Bu nedenle, ince / şişman okları ne zaman kullanacağınız dört şekilde oldukça kolay bir şekilde özetlenebilir:
Her iki koşul da sağlandığında yalnızca ince ok işlevleri kullanılmalıdır:
Aşağıdaki koşul gerçekleştiğinde yalnızca yağ oku işlevleri kullanılmalıdır:
Aşağıdaki koşullar gerçekleştiğinde doğrudan ince ok işlevini çağıran yağ ok işlevi kullanılmalıdır:
Aşağıdaki koşullar gerçekleştiğinde doğrudan bir yağ oku (gösterilmemiştir) işlevini çağıran ince ok işlevi kullanılmalıdır:
Tüm yaklaşımlarda, belirli örneklerin davranışının doğru davranıp davranmayacağının örneğin prototip işlevlerinin değiştirilebileceği durumda, örneğin bir işlev bir yağ oku ile tanımlanmış olmasına rağmen, çağrıldığında davranışı bir örnek içinde tutarlı olmayabilir. prototip içinde değiştirilen bir yöntem
Genellikle ->
iyidir.
class Foo
@static: -> this
instance: -> this
alert Foo.static() == Foo # true
obj = new Foo()
alert obj.instance() == obj # true
Statik yöntemin sınıf nesnesini nasıl this
döndürdüğünü ve örneğin, örnek nesnesini nasıl döndürdüğünü unutmayın this
.
Olan şey, çağırma sözdiziminin değerini sağlamasıdır this
. Bu kodda:
foo.bar()
foo
bar()
varsayılan olarak işlevin bağlamı olacaktır . Yani sadece sorta senin istediğin gibi çalışıyor. Yağ okuna yalnızca bu işlevi çağırmak için nokta sözdizimini kullanmayan başka bir şekilde çağırdığınızda ihtiyacınız vardır.
# Pass in a function reference to be called later
# Then later, its called without the dot syntax, causing `this` to be lost
setTimeout foo.bar, 1000
# Breaking off a function reference will lose it's `this` too.
fn = foo.bar
fn()
Her iki durumda da, bu işlevi ilan etmek için şişman bir ok kullanılması, bunların çalışmasına izin verecektir. Ama garip bir şey yapmazsan, genellikle yapmana gerek yok.
Bu yüzden ->
gerçekten ihtiyacınız olana kadar kullanın =>
ve asla =>
varsayılan olarak kullanmayın .
x = obj.instance; alert x() == obj # false!
=>
bir sınıfın statik / örnek yöntemlerinde ne zaman gerekli olacağını açıkladım.
// is not a CoffeeScript comment
oysa # is a CoffeeScript comment
.
setTimeout foo.bar, 1000
"Yanlış yapmak" nasıl ? Bir yağ oku kullanmak setTimeout (-> foo.bar()), 1000
IMHO kullanmaktan çok daha hoş .
setTimeout
elbette bir durum var . Ancak ilk yorumunuz biraz çelişkili ve meşru bir kullanım durumu ortaya koymuyor, ancak nasıl kırılacağını ortaya koyuyor. Basitçe =>
, iyi bir nedenden dolayı gerekmedikçe, özellikle örneklemeye bağlı olması gereken yeni bir işlev oluşturma performans maliyetine sahip olduğu sınıf örneği yöntemlerinde kullanmamanız gerektiğini söylüyorum .
sadece yağ okunu anlama için bir örnek
çalışmıyor: (@canvas undefined)
class Test
constructor: ->
@canvas = document.createElement 'canvas'
window.addEventListener 'resize', ->
@canvas.width = window.innerWidth
@canvas.height = window.innerHeight
eserleri: (@canvas tanımlandı)
class Test
constructor: ->
@canvas = document.createElement 'canvas'
window.addEventListener 'resize', =>
@canvas.width = window.innerWidth
@canvas.height = window.innerHeight