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 = 'Willem'; function foo() { console.log(this.name); } foo(); // Willem // 执行时启用严格模式 (function() { 'use strict'; foo(); // Willem bar(); // Cannot read property 'name' of undefined })(); // 函数体使用严格模式 function bar() { 'use strict'; 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提供了两个方法call
和apply
,传入的第一个参数是一个对象,会把this绑定到这个对象。如果是传入的是一个原始值(字符串、数字、布尔),会被转换成它的对象形式(new String(), new Boolean(), new Number())。
function foo() { console.log(this.a); } var obj = { a: 1 }; foo.call(obj); // 1
虽然我们可以使用call
和apply
显式指定this的指向,但是还是会存在丢失绑定的问题。可以通过所谓的硬绑定(bind函数)
来解决,这里就不过多赘述了。
4. new
最后要介绍的是使用new
Dies deutet nicht wirklich auf die Funktion selbst hin
.
- Punkt auf Umfang? Ein weiteres häufiges Missverständnis ist, dass dies auf den Umfang der Funktion hinweist.
function Foo(a) { this.a = a; } var bar = new Foo(2); bar.a; // 2
In diesem Code wird bar in foo ausgeführt und die Ausgabe von - Dies weist nicht auf den Umfang der Funktion hin.
this.a
ist undefiniert
. Mit anderen Worten: 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 BindungsregelnDiese Bindung hat vier Regeln, die befolgt werden können, die im Folgenden einzeln vorgestellt werden. 1. Standardbindung