Heim >Web-Frontend >js-Tutorial >Was ist das Magische daran in JavaScript?

Was ist das Magische daran in JavaScript?

藏色散人
藏色散人nach vorne
2021-09-19 17:11:481947Durchsuche
Dieses Schlüsselwort ist einer der komplexesten Mechanismen in JavaScript. Es handelt sich um ein ganz besonderes Schlüsselwort, das im Umfang aller Funktionen automatisch definiert wird. Doch selbst sehr erfahrenen JavaScript-Entwicklern fällt es schwer zu sagen, worauf genau es verweist.

Was ist das?

Auf die Funktion selbst verweisen?

Allein aufgrund der wörtlichen Bedeutung könnte man leicht annehmen, dass dies auf die Funktion selbst hinweist. Wir können uns ein Beispiel ansehen.

function foo() {
    this.count = this.count ? this.count + 1 : 1;
}

for (let i = 0; i < 5; i++) {
    foo();
}
console.log(foo.count); // undefined

Sie können sehen, dass die Ausgabe von foo.count nicht die erwartete 5 ist, sondern die zu Beginn zugewiesene 0. Mit anderen Worten: 5,而是一开始赋值的0。也就是说this其实并没有指向函数本身

指向作用域?

还有一种比较常见的误解是,this指向了函数的作用域。

function foo() {
    var a = 2;
    bar();
}
function bar() {
    console.log(this.a);
}

foo(); // undefined

这段代码中,bar在foo中运行,输出this.a得到的却是undefined。也就是说this也不是指向函数的作用域的

这也不是,那也不是,this到底是什么呢?在函数执行过程中,会创建一个执行上下文(一个记录),this就是这个上下文中的一个属性,在执行过程中用到。而this的指向则是取决于函数在哪里被调用。

this的绑定规则

this的绑定有四条可以遵循的规则,下面将一一介绍。

1.默认绑定

独立函数调用,非严格模式下,指向window;严格模式下指向undefined。 这里说的独立函数可以理解成除开后面三种情况的一般函数调用。

// 非严格模式
var name = &#39;Willem&#39;;
function foo() {
    console.log(this.name);
}
foo(); // Willem

// 执行时启用严格模式
(function() {
    &#39;use strict&#39;;
    foo(); // Willem
    bar(); // Cannot read property &#39;name&#39; of undefined
})();

// 函数体使用严格模式
function bar() {
    &#39;use strict&#39;;
    console.log(this.name);
}

上述代码中,分别在普通环境中输出Willem,说明指向的确实是window对象。需要特别注意的一点是:严格模式下指向undefined指的是函数体内启用了严格模式,而不是调用时。

2. 隐式绑定

隐式绑定说的是,在函数执行时,是否被某个对象拥有或包含。换句话说,在函数运行时,是否是作为某个对象的属性的方式运行的,这样说还是不是很清楚,来个栗子:

function foo() {
    console.log(this.a);
}
var a = 1;
var obj = {
    a: 2,
    foo
};
obj.foo(); // 2
var obj2 = {
    a: 3,
    obj
};
obj2.obj.foo(); // 2

示例中,foo被当做了obj的一个属性进行执行,此时obj作为了函数的上下文,此时this指向了obj,this.a等价于obj.a。在对象属性链式的调用中,只有最后一层会对调用位置产生影响,也就是说最后一层会影响this指向。

有很多前端的小伙伴面试时或许还见过这样的题:

function foo() {
    console.log(this.a);
}
var a = 1;
var obj = {
    a: 2,
    foo
};
var bar = obj.foo;
bar(); // 1

这是隐式绑定最常见的一个问题,隐式丢失:被隐式绑定的函数会丢失绑定对象。虽然bar是对obj.foo的一个引用,但实际上引用的还是foo函数本身,bar函数就是一个独立函数的调用,参考第一条,此时this指向了window|undefined

还有一种经典的回调函数的this指向问题也是隐式丢失。

function foo() {
    console.log(this.a);
}
function doFoo(fn) {
    fn();
}
var a = 1;
var obj = {
    a: 2,
    foo
};
doFoo(obj.foo); // 1

小结:在隐式绑定中,赋值的情况下(回调是隐式赋值)需要特别注意隐式丢失的问题 。

3. 显示绑定

JavaScript中的Function提供了两个方法callapply,传入的第一个参数是一个对象,会把this绑定到这个对象。如果是传入的是一个原始值(字符串、数字、布尔),会被转换成它的对象形式(new String(), new Boolean(), new Number())。

function foo() {
    console.log(this.a);
}
var obj = {
    a: 1
};
foo.call(obj); // 1

虽然我们可以使用callapply显式指定this的指向,但是还是会存在丢失绑定的问题。可以通过所谓的硬绑定(bind函数)来解决,这里就不过多赘述了。

4. new

最后要介绍的是使用newDies deutet nicht wirklich auf die Funktion selbst hin
.

    Punkt auf Umfang?
  1. Ein weiteres häufiges Missverständnis ist, dass dies auf den Umfang der Funktion hinweist.
  2. function Foo(a) {
        this.a = a;
    }
    
    var bar = new Foo(2);
    bar.a; // 2
  3. In diesem Code wird bar in foo ausgeführt und die Ausgabe von this.a ist undefiniert. Mit anderen Worten:
  4. Dies weist nicht auf den Umfang der Funktion hin.
Es ist nicht dies, es ist nicht das, was ist das? Während der Ausführung der Funktion wird ein Ausführungskontext (ein Datensatz) erstellt. Dies ist ein Attribut in diesem Kontext und wird während der Ausführung verwendet. Der Sinn davon hängt davon ab, wo die Funktion aufgerufen wird.

Diese Bindungsregeln

Diese Bindung hat vier Regeln, die befolgt werden können, die im Folgenden einzeln vorgestellt werden.

1. Standardbindung

ist ein unabhängiger Funktionsaufruf, der auf das Fenster zeigt, im strikten Modus. Die hier erwähnten unabhängigen Funktionen können mit Ausnahme der folgenden drei Situationen als allgemeine Funktionsaufrufe verstanden werden. rrreeeIm obigen Code wird Willem in der normalen Umgebung ausgegeben, was darauf hinweist, dass es sich tatsächlich um das Fensterobjekt handelt, auf das gezeigt wird. Eine Sache, die besondere Aufmerksamkeit erfordert, ist: , der im strikten Modus auf undefiniert zeigt, bezieht sich auf die Tatsache, dass der strikte Modus im Funktionskörper aktiviert ist, nicht beim Aufruf.
2. Implizite Bindung

Implizite Bindung bedeutet, ob im Besitz eines Objekts ist oder von diesem eingeschlossen wird, wenn die Funktion ausgeführt wird. Mit anderen Worten, wenn die Funktion ausgeführt wird, ist nicht ganz klar, ob sie als Attribut eines Objekts ausgeführt wird. Hier ist ein Beispiel: 🎜rrreee🎜Im Beispiel wird foo zu diesem Zeitpunkt als Attribut ausgeführt , obj dient als Kontext der Funktion und zeigt auf obj. this.a ist äquivalent zu obj.a. Beim Aufruf der Objekteigenschaftskette wirkt sich nur die letzte Ebene auf die aufrufende Position aus, was bedeutet, dass die letzte Ebene den This-Zeiger beeinflusst. 🎜🎜Viele Front-End-Freunde haben diese Frage möglicherweise in Interviews gesehen: 🎜rrreee🎜Dies ist das häufigste Problem bei der impliziten Bindung. 🎜Impliziter Verlust: Implizit gebundene Funktionen verlieren das gebundene Objekt 🎜. Obwohl „bar“ ein Verweis auf obj.foo ist, bezieht es sich tatsächlich auf die Funktion „bar“ und ist ein Aufruf einer unabhängigen Funktion /code> . 🎜🎜Es gibt auch dieses Zeigeproblem einer klassischen Callback-Funktion, das ebenfalls implizit verloren geht. 🎜rrreee🎜Zusammenfassung: Bei der impliziten Bindung muss beim Zuweisen von Werten (Rückrufe sind implizite Zuweisungen) besonderes Augenmerk auf das Problem des impliziten Verlusts gelegt werden. 🎜🎜3. Anzeigebindung🎜🎜Funktion in JavaScript bietet zwei Methoden call und apply. Der erste übergebene Parameter ist ein Objekt, das an dieses Objekt gebunden wird. Wenn ein primitiver Wert (String, Zahl, Boolean) übergeben wird, wird er in seine Objektform (new String(), new Boolean(), new Number()) konvertiert. 🎜rrreee🎜Obwohl wir call und apply verwenden können, um den Sinn davon explizit anzugeben, besteht immer noch das Problem, dass die Bindung verloren geht. Es kann durch die sogenannte harte Bindung (Bind-Funktion) gelöst werden, daher werde ich hier nicht auf Details eingehen. 🎜🎜4. Neu🎜🎜Das Letzte, was ich vorstellen möchte, ist die Verwendung von neu, um die Bindung von neu in js und neu in zu ändern andere Sprachen völlig anders. 🎜Neuer Ausführungsprozess: 🎜🎜🎜 Erstellen Sie ein leeres Objekt. 🎜🎜 Führen Sie das Andocken des Prototyps am aktuellen leeren Objekt durch. 🎜🎜 Geben Sie das Ergebnis der Funktionsausführung oder das aktuelle leere Objekt zurück. 🎜🎜rrreee🎜 Wenn Sie new zum Aufrufen einer Funktion verwenden, erstellen wir eine neues Objekt und binden Sie es im Funktionsaufruf daran. 🎜🎜Priorität🎜🎜Lassen Sie uns abschließend kurz über die Prioritätsbeziehung sprechen: neue > implizite Bindung > 🎜🎜Empfohlenes Lernen: „🎜🎜JavaScript-Grundlagen-Tutorial🎜🎜“🎜🎜🎜

Das obige ist der detaillierte Inhalt vonWas ist das Magische daran in JavaScript?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:segmentfault.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen