Bir ok işlevinde 'bunu' bağlayabilir misin?


134

Bir süredir ES6 ile deneyler yapıyorum ve küçük bir problemle karşılaştım.

Ok işlevlerini kullanmayı gerçekten seviyorum ve ne zaman yapabilsem onları kullanıyorum.

Ancak, onları bağlayamayacağınız anlaşılıyor!

İşte işlev:

var f = () => console.log(this);

İşte işlevi bağlamak istediğim nesne:

var o = {'a': 42};

Ve burada ben bağlamak nasıl olduğunu fiçin o:

var fBound = f.bind(o);

Ve sonra arayabilirim fBound:

fBound();

Bunu ( onesne) çıkaracak :

{'a': 42}

Güzel! Güzel! İşe yaramaması dışında. oNesnenin çıktısını almak yerine, nesneyi çıkarır window.

Öyleyse bilmek istiyorum: ok işlevlerini bağlayabilir misiniz? (Ve eğer öyleyse, nasıl?)


Yukarıdaki kodu Google Chrome 48 ve Firefox 43'te test ettim ve sonuç aynı.


29
Ok işlevlerinin tüm thisamacı, üst kapsamlarını kullanmalarıdır.
loganfsmyth

Yanıtlar:


159

Bir ok işlevinde yeniden bağlanamazsınız this. Her zaman tanımlandığı bağlam olarak tanımlanacaktır. Eğer gerekiyorsa thisanlamlı olması için normal bir işlevi kullanmalısınız.

Gönderen ECMAScript 2015 Spec :

Bir ArrowFunction içindeki argümanlara, super, this veya new.target'e yapılan herhangi bir referans, sözcüksel olarak çevreleyen bir ortamda bir bağlamaya çözümlenmelidir. Tipik olarak bu, hemen çevreleyen bir işlevin İşlev Ortamı olacaktır.


7
Bu cevabın ilk cümlesi yanlış. Muhtemelen soru aynı zamanda kafa karıştırıcı olduğu için ve this. İkisi birbiriyle ilişkilidir, ancak aynı değildir. thisbir ok işlevinin içinde her zaman thiskapsama alanından 'miras alır' . Bu, ok işlevlerinin bir özelliğidir. Ancak bindbir ok işlevinin diğer tüm parametrelerini yine de yapabilirsiniz . Sadece değil this.
Stijn de Witt

54

Tam olması için, olabilir yeniden bağlamak fonksiyonları ok, sadece anlamını değiştiremezsiniz this.

bind hala fonksiyon argümanları için bir değere sahiptir:

((a, b, c) => {
  console.info(a, b, c) // 1, 2, 3
}).bind(undefined, 1, 2, 3)()

Burada deneyin: http://jsbin.com/motihanopi/edit?js,console


1
(Ok) işlevinin bağlı olduğu nesneyi referans vermeden this(ki bu, sözcüksel olarak tanımlanır) saptamanın veya kullanmanın bir yolu var mı ?
Florrie

3
Bağlam için bir bağımsız değişken kullanın: ((bağlam) => {someOtherFunction.apply (bağlam)}). Bind (willBeIgnored, bağlam) ()
cvazac

13

Gönderen MDN'yi :

Bir ok işlevi ifadesi, işlev ifadelerine kıyasla daha kısa bir sözdizimine sahiptir ve bu değeri sözcüksel olarak bağlar (kendi this, arguments, super veya new.target değerlerini bağlamaz). Ok işlevleri her zaman anonimdir.

Bu, istediğiniz thisgibi bir değeri bağlayamayacağınız anlamına gelir .


6

Yıllar boyunca js geliştiricileri bağlam bağlama ile mücadele thisettiler, javascript'te neden değiştiğini sordular , bağlam bağlama ve thisjavascript ile thisdiğer OOP dillerinin çoğundaki anlamı arasındaki fark nedeniyle yıllar içinde bu kadar çok kafa karışıklığı yaşadılar.

Bütün bunlar beni neden, neden, neden diye sormaya yönlendiriyor! neden bir ok işlevini yeniden başlatmayasınız! Özel olarak oluşturulan nerede olanlar bu sorunları ve karışıklıkları ve kullanmak zorunda kalmamak tüm çözmek bindya callveya başka türlü yolu fonksiyonunun kapsamını korumak için.

TL; DR

Hayır, ok işlevlerini yeniden bağlayamazsınız.


7
Ok işlevleri, her şeyden önce daha temiz ve daha hızlı bir sözdizimi sağlamak için oluşturulmuştur. Lambda-hesabı düşünün. İşlevsel JS programcılarının hayatını rahatsız eden OO-fanatiklerinin, çağrı bağlamını belirleme özgürlüğünü ellerinden alma fırsatını yakalaması çok kötü.
Marco Faustinelli

5
Kullanmak thisişlevsel değildir. lambdas olmalıdır arguments => output. Dışarıdan bir bağlama ihtiyacınız varsa, onu thisaktarın. OO modellerinin dile geçişini kolaylaştıran şeyin kendisi var . O olmadan "javascript sınıfı" terimini asla duymazdınız.
erich2k8

3
Sen edebilirsiniz ok fonksiyonlarını rebind. Sadece değil this.
Stijn de Witt

6

Bir ok işlevinin içindeki binddeğeri değiştirmek için kullanamazsınız this. Bununla birlikte, eski ok işleviyle aynı şeyi yapan yeni bir normal işlev oluşturabilir ve ardından her zamanki gibi yeniden bağlamak için callveya düğmesini kullanabilirsiniz .bindthis

Biz kullanmak evalnormal bir fonksiyonu olarak geçmek ok fonksiyonunu yeniden burada çağrıyı sonra kullanmak callfarklı bir ile çağırmak için this:

var obj = {value: 10};
function arrowBind(context, fn) {
  let arrowFn;
  (function() {
    arrowFn = eval(fn.toString());
    arrowFn();
  }).call(context);
}
arrowBind(obj, () => {console.log(this)});


3
Bir ok işlevini farklı bir bağlama bağlama yönteminin bu örneğini paylaştığınız için teşekkür ederiz! Yanıtı gelecekteki okuyucuların anlamasını kolaylaştırmak için, belki de kodun nasıl ve neden çalıştığını açıklayacak şekilde düzenleyebilirsiniz ?
Florrie

4

ES6 Ok İşlevleri "Bunu" JavaScript'te Gerçekten Çözüyor mu?

Yukarıdaki bağlantı, ok işlevlerinin işlevlerle thisdeğişmediğini açıklamaktadır bind, call, apply.

Çok güzel bir örnekle anlatılıyor.

node v4"beklenen" davranışı görmek için bunu çalıştırın ,

this.test = "attached to the module";
var foo = { test: "attached to an object" };
foo.method = function(name, cb){ 
    // bind the value of "this" on the method 
    // to try and force it to be what you want 
    this[name] = cb.bind(this); };
foo.method("bar", () => { console.log(this.test); });
foo.bar(); 

Cevabın kendisinde daha alakalı bilgiler sağlamanızı isteyin, örnek bir kod veya soruların düzenlenmiş versiyonları olabilir
Jithin Scaria

// "beklenen" davranışı görmek için bunu düğüm v4'te çalıştırın this.test = "modüle bağlı"; var foo = {test: "bir nesneye eklendi"}; foo.method = function (name, cb) {// "this" değerini yönteme bağla // denemek ve onu istediğin gibi olmaya zorlamak için [isim] = cb.bind (this); }; foo.method ("bar", () => {console.log (this.test);}); ) (foo.bar;
Prithvi Raj Vuppalapati

Burada ilginç olan, bunu denemek ve ardından foo.method ('bar', () => {console.log (this.test);}); foo.method ('bar', function () {console.log (this.test);}); - "modüle eklenmiş" birinci sürüm günlükleri ve "bir nesneye eklenmiş" ikinci günlükler - Ok işlevlerini kullanarak "bunun" daha kararlı bir şekilde ele alınmasını gerçekten tercih ederim. Yine de farklı desenler kullanarak diğer efektleri elde edebilirsiniz ve sonuçlar daha okunaklı ve tahmin edilebilir IMO'dur.
Metodisyen


2

Kısa, Sen CAN NOT bağlama fonksiyonlarını ok ama okumaya:

Aşağıda thiskonsolda yazan şu ok işlevine sahip olduğunuzu hayal edin :

const myFunc = ()=> console.log(this);

Dolayısıyla, bunun için hızlı düzeltme normal işlevi kullanmak olacaktır, bu nedenle şu şekilde değiştirin:

function myFunc() {console.log(this)};

Daha sonra bindveya callveya kullanarak herhangi bir sözlü ortama bağlayabilirsiniz apply:

const bindedFunc = myFunc.bind(this);

ve durumunda arayın bind.

bindedFunc();

Bunu eval()yapmak için kullanmanın da kesinlikle önerilmeyen yolları vardır .


function myFuncbağlanabilir olmanın yanı sıra davranışsal olarak farklıdır daha yakın bir eşleşme olacaktır const myFunc = function() {...}. Ayrıca eval kullanarak neyi kastettiğinizi merak ediyorum, çünkü bu daha önce hiçbir cevabın burada paylaştığını düşünmediğim bir yaklaşım - bunun nasıl yapıldığını görmek ilginç olurdu ve sonra neden bu kadar cesaret kırıldığını okuyun.
Florrie

1

Belki bu örnek size yardımcı olur:

let bob = {
   _name: "Bob",
   _friends: ["stackoverflow"],
   printFriends:(x)=> {
      x._friends.forEach((f)=> {
         console.log(x._name + " knows " + f);
      });
   }
}

bob.printFriends = (bob.printFriends).bind(null,bob);
bob.printFriends();


gøød stuff ... hafif intérésting
Aleks
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.