Heim > Web-Frontend > js-Tutorial > Pfeilfunktionen verstehen

Pfeilfunktionen verstehen

hzc
Freigeben: 2020-06-16 09:41:59
nach vorne
2649 Leute haben es durchsucht

Ich hatte einmal das Gefühl, dass ich die Pfeilfunktionen bereits sehr gut verstand und mich nicht noch einmal täuschen ließ. Aber vor ein paar Tagen bin ich auf ein sehr seltsames Problem gestoßen, nachdem ich lange darüber nachgedacht hatte, dass es sich um eine Falle handelte, die durch die Pfeilfunktion verursacht wurde. Daher gibt es diesen Artikel~

Problembeschreibung

Zum Beispiel habe ich eine Basisklasse Animal, die eine grundlegende Methode sayName hat. Jede nachfolgende Unterklasse, die von ihr erbt, muss die Methode sayName implementieren, um ihre Identität zu beweisen. Die Implementierung des Basisklassencodes ist sehr einfach:

class Animal {
	sayName = () => {
		throw new Error('你应该自己实现这个方法');
  }
}
Nach dem Login kopieren

Also muss ich jetzt von der Animal-Basisklasse erben, um eine Pig-Unterklasse zu implementieren. Die Implementierung ist auch sehr einfach:

class Pig extends Animal {
	sayName() {
		console.log('I am a Pig');
	}
}
Nach dem Login kopieren

Hey, ist es ist so einfach? Wo ist die Falle? Wenn Sie es jedoch tatsächlich ausführen, werden Sie feststellen, dass die Ergebnisse nicht den Erwartungen entsprechen:

Pfeilfunktionen verstehen

Hey, warum passiert das? Was genau ist schief gelaufen? Warum können diese kurzen Codezeilen einen Fehler melden?

Das Problem entdeckt

Nach langem Herumfummeln habe ich schließlich herausgefunden, dass es sich um eine Falle der Pfeilfunktion handelte. Wir müssen lediglich den sayName der Animal-Basisklasse in eine normale Funktion oder den sayName der Pig-Unterklasse in eine Pfeilfunktion ändern, um dieses Problem zu lösen. Was genau passiert also mit den Pfeilfunktionen?

Als ich das schrieb, fiel mir plötzlich ein, dass ich einmal von einem Interviewer zu dieser Frage interviewt wurde! Zu diesem Zeitpunkt fragte der Interviewer nach dem Unterschied zwischen Pfeilfunktionen, gewöhnlichen Klassenfunktionen und Bindungsfunktionen im Konstruktor für Klassen. Die Antwort war damals klar und logisch, doch als es um das Erbe ging, stellte sich alles auf den Kopf. Um die obige Frage zu beantworten, beantworten wir zunächst die Interviewfrage.

Was ist der Unterschied zwischen Pfeilfunktionen, gewöhnlichen Funktionen und der Bindungsfunktion im Konstruktor?

Um dieses Problem intuitiver zu erkennen, können wir den Code von babel verwenden Kompilierungsergebnisse, um den Unterschied besser zu erkennen.

Zuerst geben wir einen einfachen Code ein

class A {
  	constructor() {
		this.b = this.b.bind(this);    	
    }
  
    a() {
    	console.log('a');
    }
	  b() {
    	console.log('b')
    }
    c = () => {
    	console.log('c')
    }
}
Nach dem Login kopieren

Sehen wir uns an, was Babel kompiliert:

"use strict";

function _instanceof(left, right) { if (right != null && typeof Symbol !== "undefined" && right[Symbol.hasInstance]) { return !!right[Symbol.hasInstance](left); } else { return left instanceof right; } }

function _classCallCheck(instance, Constructor) { if (!_instanceof(instance, Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

var A = /*#__PURE__*/function () {
  function A() {
    _classCallCheck(this, A);

    _defineProperty(this, "c", function () {
      console.log(&#39;c&#39;);
    });

    this.b = this.b.bind(this);
  }

  _createClass(A, [{
    key: "a",
    value: function a() {
      console.log(&#39;a&#39;);
    }
  }, {
    key: "b",
    value: function b() {
      console.log(&#39;b&#39;);
    }
  }]);

  return A;
}();
Nach dem Login kopieren

Der größte Teil des kompilierten Codes sind Hilfsfunktionen, die wir uns nur ansehen können Teil der wichtigsten Punkte:

var A = /*#__PURE__*/function () {
  function A() {
    _classCallCheck(this, A);

    _defineProperty(this, "c", function () {
      console.log(&#39;c&#39;);
    });

    this.b = this.b.bind(this);
  }

  _createClass(A, [{
    key: "a",
    value: function a() {
      console.log(&#39;a&#39;);
    }
  }, {
    key: "b",
    value: function b() {
      console.log(&#39;b&#39;);
    }
  }]);

  return A;
}();
Nach dem Login kopieren

Anhand der kompilierten Ergebnisse können wir die Unterschiede untereinander erkennen:

  • Gewöhnliche Funktionen: Nach der Babel-Kompilierung, Wird platziert der Prototyp der Funktion

  • Die Bind-Funktion im Konstruktor: Nach der Kompilierung wird sie nicht nur im Prototyp der Funktion platziert, sondern auch jedes Mal generiert, wenn sie instanziiert wird . Binden Sie die Variable des aktuellen Instanzkontexts (this.b = this.b.bind(this)).

  • Pfeilfunktion: Nachdem Babel kompiliert wurde, wird bei jeder Instanziierung defineProperty aufgerufen, um den Inhalt der Pfeilfunktion an den aktuellen Instanzkontext zu binden.

Den zusammengestellten Ergebnissen nach zu urteilen, ist es für die tatsächliche Entwicklung am besten, Pfeilfunktionen zu verwenden, wenn Sie den Kontext binden müssen. Denn durch die Verwendung der Bind-Methode wird nicht nur eine Prototypfunktion generiert, sondern für jede Instanziierung auch eine zusätzliche Funktion.

Update

Nachdem ich Yu Tengjings Kommentare gelesen hatte, erfuhr ich etwas Wichtigeres.

Klasse behandelt mit = deklarierte Methoden und Variablen als Attribute der Instanz, während ohne = deklarierte Attribute in der Prototypenkette platziert werden. Beispiel:

class A {
    a() {
        
    }
    b = 2;
    c = () => {
    }
}
Nach dem Login kopieren

Für diese Klasse werden bei der Instanziierung b und c als Attribute der Instanz verwendet, während a in der Prototypenkette platziert wird.

Warum wird es dann so umgesetzt? Tatsächlich können wir sehen, dass dies in der tc39-Spezifikation erwähnt wird: Felddeklarationen

In Fällen, in denen die Gleichheitszeichendeklaration direkt geschrieben wird, handelt es sich tatsächlich um die Syntax von Felddeklarationen, die der direkten Deklaration einer solchen entspricht ein Instanzattribut.

Zurück zum Thema

Nachdem wir das vorherige Problem gelöst haben, kehren wir zum Thema zurück. Nachdem wir die Kompilierungsergebnisse der Pfeilfunktion der Klasse unter tatsächlichen Kompilierungsbedingungen verstanden haben, ist es tatsächlich einfacher, unser Problem zu verstehen.

F: Warum tritt ein Ausführungsproblem auf, wenn eine Unterklasse sayName mit einer normalen Funktion deklariert?

A: Wenn eine Unterklasse sayName mit einer normalen Funktion deklariert, wird der von der Unterklasse deklarierte sayName auf dem Prototyp des Konstruktors platziert. Da jedoch der sayName der Basisklasse Pfeilfunktionen verwendet, verfügt jede Instanz direkt über eine sayName-Variable. Gemäß den Zugriffsregeln von JavaScript-Variablen wird zuerst die Variable selbst durchsucht. Wenn sie nicht gefunden werden kann, wird sie in der Prototypenkette durchsucht. Daher finden Sie bei der Suche nach sayName direkt die von der Basisklasse deklarierte Funktion sayName und suchen nicht in der Prototypenkette danach, sodass ein Problem vorliegt.

F: Warum verwendet die Unterklasse die Pfeilfunktion, um sayName zu deklarieren, und es gibt kein Problem bei der Ausführung?

A: Wenn eine es6-Klasse initialisiert wird, führt sie zuerst den Konstruktor der Basisklasse und dann ihren eigenen Konstruktor aus. Daher überschreibt die von der Unterklasse deklarierte Pfeilfunktion sayName nach der Initialisierung der Basisklasse die der Basisklasse, sodass bei der Ausführung kein Problem auftritt.

Zusammenfassung

Ich dachte, ich wüsste die Funktionsweise von Pfeilen sehr gut, aber ich habe mich trotzdem täuschen lassen. Wie erwartet nimmt das Lernen kein Ende! Ich habe aber auch ein tieferes Verständnis für klasseninterne Pfeilfunktionen.

Nachdem ich jedoch von allen im Kommentarbereich daran erinnert wurde, stellte ich fest, dass das Problem nicht tatsächlich durch die Pfeilfunktion verursacht wird. Mit dem =-Zeichen in der Klasse deklarierte Variablen gehören zur Syntax von Felddeklarationen. Auf diese Weise deklarierte Variablen werden direkt in die Eigenschaften der Instanz eingebunden und nicht in die Prototypenkette.

Empfohlenes Tutorial: „JS-Tutorial

Das obige ist der detaillierte Inhalt vonPfeilfunktionen verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
js
Quelle:juejin.cn
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage