Heim  >  Artikel  >  Web-Frontend  >  Was ist das? Eine ausführliche Analyse dazu in JavaScript

Was ist das? Eine ausführliche Analyse dazu in JavaScript

青灯夜游
青灯夜游nach vorne
2022-08-04 17:02:241864Durchsuche

Was ist das? Der folgende Artikel wird Ihnen dies in JavaScript vorstellen und auf die Unterschiede zwischen verschiedenen Aufrufmethoden von Funktionen eingehen. Ich hoffe, er wird Ihnen hilfreich sein!

Was ist das? Eine ausführliche Analyse dazu in JavaScript

JavaScript中的this格外的不一样,比如Java语言中的this是在代码的执行阶段是不可更改,而JavaScript的this是在调用阶段进行绑定。因为这一性质所以给了thisViel Platz zum Spielen. Im strikten Modus und im nicht strikten Modus ist es jedoch etwas anders, und die unterschiedlichen Aufrufmethoden der Funktion führen auch hier zu einigen Unterschieden.

Was ist das?

Zunächst definieren wir Folgendes: Dies ist eine Variable, die beim Erstellen des Ausführungskontexts festgelegt wird und während der Ausführung nicht geändert werden kann.

Der sogenannte Ausführungskontext ist der Prozess, bei dem die JavaScript-Engine einige Variablen, Funktionen, dieses deklariert, die intern im Code verwendet werden, bevor ein Teil des Codes ausgeführt wird, und diese dann speichert in variablen Objekten. Dieses „Code-Snippet“ enthält: globaler Code (Code innerhalb des Skript-Tags), interner Funktionscode, interner Auswertungscode. Auch die uns bekannte Scope-Kette wird hier gespeichert, in Array-ähnlicher Form im Attribut [[Scopes]] der entsprechenden Funktion.

Dies wird nur während der Funktionsaufrufphase bestimmt, das heißt, die Ausführungskontexterstellungsphase wird zugewiesen und im Variablenobjekt gespeichert. Diese Funktion führt auch zu einer Variabilität: Das heißt, wenn die Funktion auf unterschiedliche Weise aufgerufen wird, kann der Wert unterschiedlich sein.

Wir haben oben gesagt, dass sich dies im strikten Modus und im nicht strikten Modus unterschiedlich verhält:

var a = 1;
function fun() {
   'use strict';
    var a = 2;
      return this.a;
}
fun();//报错 Cannot read property 'a' of undefined
  • Im strikten Modus zeigt dies auf undefiniert;

var a = 1;
function fun() {
    var a = 2;
      return this.a;
}
fun();//1
  • Im nicht strikten Modus zeigt dies auf Fenster;

Der gleiche Code oben verhält sich in verschiedenen Modi unterschiedlich, da dies im strikten Modus und im nicht strikten Modus unterschiedlich ist.

Fazit: Wenn eine Funktion unabhängig aufgerufen wird, zeigt sie im strikten Modus auf undefiniert. Wenn sie im nicht strikten Modus auf undefiniert zeigt, zeigt sie automatisch auf das globale Objekt (Fenster im Browser)

Mehr Lassen Sie mich erwähnen, dass dies in der globalen Umgebung auf Sie selbst hinweist:

this.a = 1;
var b = 1;
c = 1;
console.log(this === window)//true
//这三种都能得到想要的结果,全局上下文的变量对象中存在这三个变量

Noch etwas: Was passiert, wenn dies in der Funktion nicht verwendet wird? Schauen Sie sich ein Beispiel an:

var a = 1000;
var obj = {
    a: 1,
      b: this.a + 1
}
function fun() {
    var obj = {
          a: 1,
        c: this.a + 2 //严格模式下这块报错 Cannot read property 'a' of undefined
    }
    return obj.c;
}
console.log(fun());//1002
console.log(obj.b);//1001

In diesem Fall zeigt dies immer noch auf das Fenster. Dann können wir eine separate Schlussfolgerung ziehen:

Wenn obj global deklariert wird, zeigt dies in den internen Eigenschaften von obj auf das globale Objekt. Wenn obj in einer Funktion deklariert wird, zeigt dies auf undefiniert im strikten Modus und auf undefiniert im nicht -strict-Modus Wird automatisch so konvertiert, dass er auf das globale Objekt zeigt.

Okay, ich habe es gerade ausprobiert und kenne den Unterschied zwischen dem strikten und dem nicht strikten Modus. Die in unserem täglichen Leben am häufigsten verwendete Methode ist jedoch die Verwendung dieser Methode, die ich auch erwähnt habe Über die verschiedenen Arten, dies in Funktionen aufzurufen, gibt es immer noch Unterschiede. Welche Methoden gibt es also, um Funktionen aufzurufen? Vier Typen:

  • Direkter Aufruf
  • als Objektmethode in der globalen Umgebung oder als gewöhnliche Funktion
  • Verwenden Sie „Apply“ und rufen Sie
  • als Konstruktor auf

Die folgenden vier Situationen sind:

Direkter Aufruf

Das obige Beispiel ist eigentlich ein direkter Aufruf, aber ich habe beschlossen, ein anderes Beispiel zu schreiben:

var a = 1;
var obj  =  {
    a: 2,
      b: function () {
        function fun() {
          return this.a
        }
       console.log(fun());
    }
} 
obj.b();//1

Obwohl die Fun-Funktion in der obj.b-Methode definiert ist, handelt es sich immer noch um eine gewöhnliche Funktion, die auf undefiniert in nicht strenger Weise verweist mode und zeigt automatisch auf das globale Objekt. Wie erwartet meldet der strikte Modus den Fehler undefiniert.a ist nicht eingerichtet, a ist nicht definiert.

Das Wichtige sei noch einmal gesagt: Wenn eine Funktion unabhängig aufgerufen wird, zeigt dies im strikten Modus auf undefiniert. Wenn dies im nicht strikten Modus auf undefiniert zeigt, zeigt es automatisch auf das globale Objekt (Fenster im Browser). ).

Als Methode eines Objekts

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

bDie von b referenzierte anonyme Funktion wird als Methode von obj aufgerufen. Dies zeigt auf das Objekt, das sie aufruft. Das ist Objekt. Was ist, wenn Methode b nicht als Objektmethode aufgerufen wird? Was bedeutet das? Das ist es:

rrree

Wie oben stellt sich heraus, dass das Ausführungsergebnis der t-Funktion die globale Variable 1 ist. Warum? Dies betrifft den Speicherplatz von Javascript, das heißt, das b-Attribut des obj-Objekts speichert einen Verweis auf die anonyme Funktion, der als Zeiger verstanden werden kann. Wenn t ein Wert zugewiesen wird, wird kein separater Speicherplatz zum Speichern der neuen Funktion geöffnet. Stattdessen speichert t einen Zeiger, der auf diese Funktion zeigt. Dies entspricht der Ausführung dieses Pseudocodes:

var a = 1;
var obj = {
  a: 2,
  b: function() {
    return this.a;
  }
}
var t = obj.b;
console.log(t());//1

Zu diesem Zeitpunkt ist t ein Zeiger auf die Fun-Funktion. Wenn Sie die oben genannten Regeln anwenden, ist das Ausdrucken von 1 natürlich leicht zu verstehen.

使用apply,call

关于apply和call是干什么的怎么用本文不涉及,请移驾:applycall

这是个万能公式,实际上上面直接调用的代码,我们可以看成这样的:

function fun() {
      return this.a;
}
fun();//1
//严格模式
fun.call(undefined)
//非严格模式
fun.call(window)

这时候我们就可以解释下,为啥说在非严格模式下,当函数this指向undefined的时候,会自动指向全局对象,如上,在非严格模式下,当调用fun.call(undefined)的时候打印出来的依旧是1,就是最好的证据。

为啥说是万能公式呢?再看函数作为对象的方法调用:

var a = 1;
var obj = {
  a: 2,
  b: function() {
    return this.a;
  }
}
obj.b()
obj.b.call(obj)

如上,是不是很强大,可以理解为其它两种都是这个方法的语法糖罢了,那么apply和call是不是真的万能的呢?并不是,ES6的箭头函数就是特例,因为箭头函数的this不是在调用时候确定的,这也就是为啥说箭头函数好用的原因之一,因为它的this固定不会变来变去的了。关于箭头函数的this我们稍后再说。

作为构造函数

何为构造函数?所谓构造函数就是用来new对象的函数,像FunctionObjectArrayDate等都是全局定义的构造函数。其实每一个函数都可以new对象,那些批量生产我们需要的对象的函数就叫它构造函数罢了。注意,构造函数首字母记得大写。

function Fun() {
  this.name = 'Damonre';
  this.age = 21;
  this.sex = 'man';
  this.run = function () {
    return this.name + '正在跑步';
  }
}
Fun.prototype = {
  contructor: Fun,
  say: function () {
    return this.name + '正在说话';
  }
}
var f = new Fun();
f.run();//Damonare正在跑步
f.say();//Damonare正在说话

如上,如果函数作为构造函数用,那么其中的this就代表它即将new出来的对象。为啥呢?new做了啥呢?

伪代码如下:

function Fun() {
  //new做的事情
  var obj = {};
  obj.__proto__ = Fun.prototype;//Base为构造函数
  obj.name = 'Damonare';
  ...//一系列赋值以及更多的事
  return obj
}

也就是说new做了下面这些事:

  • 创建一个临时对象
  • 给临时对象绑定原型
  • 给临时对象对应属性赋值
  • 将临时对象return

也就是说new其实就是个语法糖,this之所以指向临时对象还是没逃脱上面说的几种情况。

当然如果直接调用Fun(),如下:

function Fun() {
  this.name = 'Damonre';
  this.age = 21;
  this.sex = 'man';
  this.run = function () {
    return this.name + '正在跑步';
  }
}
Fun();
console.log(window)

其实就是直接调用一个函数,this在非严格模式下指向window,你可以在window对象找到所有的变量。

另外还有一点,prototype对象的方法的this指向实例对象,因为实例对象的__proto__已经指向了原型函数的prototype。这就涉及原型链的知识了,即方法会沿着对象的原型链进行查找。

箭头函数

刚刚提到了箭头函数是一个不可以用call和apply改变this的典型。

我们看下面这个例子:

var a = 1;
var obj = {
  a: 2
};
var fun = () => console.log(this.a);
fun();//1
fun.call(obj)//1

以上,两次调用都是1。

那么箭头函数的this是怎么确定的呢?箭头函数会捕获其所在上下文的  this 值,作为自己的 this,也就是说箭头函数的this在词法层面就完成了绑定。apply,call方法只是传入参数,却改不了this。

var a = 1;
var obj = {
  a: 2
};
function fun() {
    var a = 3;
    let f = () => console.log(this.a);
      f();
};
fun();//1
fun.call(obj);//2

如上,fun直接调用,fun的上下文中的this值为window,注意,这个地方有点绕。fun的上下文就是此箭头函数所在的上下文,因此此时f的this为fun的this也就是window。当fun.call(obj)再次调用的时候,新的上下文创建,fun此时的this为obj,也就是箭头函数的this值。

再来一个例子:

function Fun() {
    this.name = 'Damonare';
}
Fun.prototype.say = () => {
    console.log(this);
}
var f = new Fun();
f.say();//window

有的同学看到这个例子会很懵逼,感觉上this应该指向f这个实例对象啊。不是的,此时的箭头函数所在的上下文是__proto__所在的上下文也就是Object函数的上下文,而Object的this值就是全局对象。

那么再来一个例子:

function Fun() {
    this.name = 'Damonare';
      this.say = () => {
        console.log(this);
    }
}
var f = new Fun();
f.say();//Fun的实例对象

如上,this.say所在的上下文,此时箭头函数所在的上下文就变成了Fun的上下文环境,而因为上面说过当函数作为构造函数调用的时候(也就是new的作用)上下文环境的this指向实例对象。

【相关推荐:javascript学习教程

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

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