2016-10-29 4 views
4

Ich benutze React seit einiger Zeit, und ich habe mich mit dem Konzept vertraut gemacht, dass ich meine Komponentenmethoden manuell an meine Komponenteninstanz binden muss, da React die Entscheidung getroffen hat, "nicht idiomatisch" zu sein:Tun ES2015-Klassen "nicht autobind"?

Deshalb haben wir uns entschieden, diese nicht in die Klasse von React eingebaut zu haben. Sie können Methoden in Ihrem Konstruktor immer noch explizit vorbinden, wenn gewünscht wird.

class Counter extends React.Component { 
    constructor() { 
    super(); 
    this.tick = this.tick.bind(this); 
    } 
    tick() { 
    ... 
    } 
    ... 
} 

- https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html

Wir können deutlich die Auswirkungen dieses in diesem Beispiel http://jsbin.com/citafaradu/2/edit?js,console,output, aus dieser ähnlichen Frage sehen: How to properly bind current object context in ES6 using babelify

jedoch jemand fragte mich kürzlich, ob es ein Unterschied war zwischen prototypbasierten Klassen und neuen ES2015-Klassen. Intuitiv sollte diese Antwort ein nachdrückliches "Nein!" Sein., da die resultierenden Instanz-Objekte natürlich normale Prototypen haben und sich ... gut verhalten, wie JS-Objekte! Und was wäre die Verwendung von Instanzmethoden, die nicht an die Instanz gebunden sind?

Ich habe versucht, für jede Indikation zu suchen, dass diese „idomatically“ von es6 Klassen wahr wäre, aber alles drehte ich mich von anderen Fragen nach oben waren Devs Reaktion, mit Antworten wie folgt aus:

Klassen Reagieren des ES6 haben keine automatische bindung. Dies wird hier dokumentiert: https://facebook.github.io/react/docs/reusable-components.html#no-autobinding

Der Grund dafür ist, dass ES6 Klassen der Javascript haben kein Autobinding weder [sic]. React versucht, Sachen, die bereits in Javascript sind, nicht neu zu erfinden. ES5 hat keine nette Syntax für Klassen, daher musste React eigene Klassen erfinden. Aber jetzt mit ES6-Klassen können wir einfach Standard Javascript verwenden.
- "cody", https://github.com/facebook/react/issues/4065

Jetzt war ich wirklich verwirrt. War das vielleicht ein Trick der JSX-Transpilation? Wirft man einen Blick auf den Ausgang der Render-Methode des Standes Beispiel:

{ 
    key: "render", 
    value: function render() { 
     return React.createElement("div",null, 
     React.createElement("input", { 
      type: "text", onChange: this.handleBindedChange 
     }), 
     React.createElement("br", null), 
     React.createElement("input", { 
      type: "text", onChange: this.handleUnbindedChange 
     }), 
     React.createElement("br", null), 
     React.createElement("p",null,"Result: ",this.state.demo) 
    ); 
    } 
} 

Keine Würfel hier entweder - Der babel Ausgang verwendet Object.defineProperty, die mit ihm absolut binden Funktionen hinzugefügt, um das Objekt sie gebunden sind, .

Und so bin ich ratlos. Die meisten der Antworten, die ich dabei gefunden habe, sind älter als die endgültige es2015-Spezifikation - da ich in der Spezifikation selbst nichts darüber finden kann, gab es eine Änderung, die das Vorgehen des React-Teams ungültig gemacht hätte? Ist das ein seltsames Artefakt der Transpiration, das ich irgendwie falsch interpretiert habe? Reagiert man hinter den Kulissen etwas Verrücktes, um das zu verursachen? Wenn ja, warum würden sie wiederholt behaupten, dass dies getan wurde, um dem ES2015-Standard zu entsprechen? Und wenn nicht, was verursacht das Verhalten im ersten Beispiel?

+0

Ich bin nicht sicher, was du meinst. 'Object.defineProperty' wird nicht" autobind ", das Aufrufen einer Funktion wird das' this' basierend darauf, wie die Funktion aufgerufen wird, genauso wie anderswo einstellen. – loganfsmyth

+0

@loganfsmyth, Object.defineProperty ist nicht das, was mich wirklich interessiert, so sehr, warum die Leute überhaupt von "autobinding" sprechen - die Art und Weise, wie es diskutiert wurde, ist vielleicht die Quelle meiner Verwirrung. – MaxPRafferty

+1

Vielleicht möchten Sie sich hier [http://stackoverflow.com/a/31842627/1048572] ansehen – Bergi

Antwort

3

Ich hatte ähnliche Fragen. Methoden innerhalb Ihrer Klasse können auf andere Methoden in derselben Klasse verweisen, da sie Teil desselben Kontexts sind (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this).

Dieses Beispiel zeigt, dass Methoden in einer Klasse unter this auf Eigenschaften zugreifen können, ohne im Konstruktor gebunden zu sein: http://jsbin.com/tapokotahi/1/edit?js,console,output. Die Methode renderElements ist nicht gebunden, greift jedoch auf this.state zu.

Die Klassenmethoden müssen gebunden (oder als Pfeilfunktionen definiert) werden, wenn sie an Ereignishandler übergeben werden, da sich der Ausführungskontext von dem der Klasse in den des Ereignishandlers ändert.

Ich stimme zu, es scheint verwirrend, wenn wir die React-Dokumente lesen und sie uns sagen, wir müssen die Methoden im Konstruktor binden, aber das ist nur notwendig, wenn die Methoden zu React's Event-Handler wie onClick übergeben.

+0

Ja, einige der Beispiele, die sie gaben, ließ mich meine Haare herausziehen. Überraschung, es ist das selbe alte "dies", das wir kennen und lieben. Ich musste es mir selbst erarbeiten mit: https://jsfiddle.net/zf83ktm1/1/ – MaxPRafferty

+1

@MaxPRafferty "* same old' this' * "- genau das ist die Idee – Bergi

5

Der Grund, warum React automatisch Autobinding erwähnt, ist, weil React.createClass alle Methoden autobinding war. Und diese Methode war die einzige Möglichkeit, Komponenten zu erstellen.

Leute, vor allem diejenigen, die nicht mit JavaScript vertraut sind, haben sich daran gewöhnt, Methoden an andere Komponenten zu übergeben, und this würde "magisch" funktionieren. Diese Funktion verschwand mit der Verwendung nativer ES6-Klassen, sodass sie den Unterschied betonen mussten.

Aber ja, ES6 Klassen sind im Grunde nur syntaktische Zucker für Konstruktor Funktionen + Prototyp. Die Verfahren sind nicht an das Objekt gebunden:

class Foo { 
 
    bar() {} 
 
} 
 

 
const foo = new Foo(); 
 

 
console.log(foo.hasOwnProperty('bar')); // false 
 
console.log(typeof Foo === 'function'); // true 
 
console.log(Foo.prototype.hasOwnProperty('bar')); // true


Aber es musste nicht unbedingt so sein. Python zum Beispiel ist auch prototypbasiert, aber Methoden sind autobound.

+0

Warte, Python ist prototypbasiert? – Bergi

+0

@Bergi: Afaik, ja. –

+1

[Python ist nicht prototypbasiert. In Python-Klassen sind wahre Typen] (https://docs.python.org/3/tutorial/classes.html). –

1

Sie können Sie ES6 Klassenmethoden Auto-bind mit einem kleinen Kessel-Platte im Konstruktor machen:

function autobind() { 
 
    for (let prop of Object.getOwnPropertyNames(Object.getPrototypeOf(this))) { 
 
    if (prop === 'constructor' || typeof this[prop] !== 'function') continue; 
 
    this[prop] = this[prop].bind(this); 
 
    } 
 
} 
 

 
class Test { 
 
    constructor() { 
 
    autobind.call(this); 
 
    this.message = 'hello all!'; 
 
    } 
 
    method1(){ return this.method2(); } 
 
    method2(){ console.log(this.message);} 
 
} 
 
let test = new Test(); 
 
let b = test.method1; 
 
b();