this 指向问题

Posted 悔创阿里-杰克马

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了this 指向问题相关的知识,希望对你有一定的参考价值。

你不懂JS: this 与对象原型 第二章: this豁然开朗! 在第一章中,我们摒弃了种种对this的误解,并且学习了this是一个完全根据调用点(函数是如何被调用的)而为每次函数调用建立的绑定。 调用点(Call-site) 为了理解this绑定,我们不得不理解调用点:函数在代码中被调用的位置(不是被声明的位置)。我们必须考察调用点来回答这个问题:这个this指向什么? 一般来说寻找调用点就是:“找到一个函数是在哪里被调用的”,但不总是那么简单,比如某些特定的编码模式会使 真正的 调用点变得不那么明确。 考虑 调用栈(call-stack) (使我们到达当前执行位置而被调用的所有方法的堆栈)是十分重要的。我们关心的调用点就位于当前执行中的函数 之前 的调用。 我们来展示一下调用栈和调用点: function baz() { // 调用栈是: `baz` // 我们的调用点是global scope(全局作用域) console.log( "baz" ); bar(); // `bar` // 我们的调用点位于`baz` console.log( "bar" ); foo(); // `bar` -> `foo` // 我们的调用点位于`bar` console.log( "foo" ); } baz(); // 。与使用4种标准的this规则不同的是,箭头函数从封闭它的(function或global)作用域采用this绑定。 我们来展示一下箭头函数的词法作用域: function foo() { // 返回一个arrow function return (a) => { // 这里的`this`是词法上从`foo()`采用 console.log( this.a ); }; } var obj1 = { a: 2 }; var obj2 = { a: 3 }; var bar = foo.call( obj1 ); bar.call( obj2 ); // 2, 不是3! 在foo()中创建的箭头函数在词法上捕获foo()调用时的this,不管它是什么。因为foo()被this绑定到obj1,bar(被返回的箭头函数的一个引用)也将会被this绑定到obj1。一个箭头函数的词法绑定是不能被覆盖的(就连new也不行!)。 最常见的用法是用于回调,比如事件处理器或计时器: function foo() { setTimeout(() => { // 这里的`this`是词法上从`foo()`采用 console.log( this.a ); },100); } var obj = { a: 2 }; foo.call( obj ); // 2 虽然箭头函数提供除了使用bind(..)外,另外一种在函数上来确保this的方式,这看起来很吸引人,但重要的是要注意它们本质是用被广泛理解的词法作用域来禁止了传统的this机制。在ES6之前,我们为此已经有了相当常用的模式,这些模式几乎和ES6的箭头函数的精神没有区别: function foo() { var self = this; // 词法上捕获`this` setTimeout( function(){ console.log( self.a ); }, 100 ); } var obj = { a: 2 }; foo.call( obj ); // 2 虽然对不想用bind(..)的人来说self = this和箭头函数都是看起来不错的“解决方案”,但它们实质上逃避了this而非理解和接受它。 如果你发现你在写this风格的代码,但是大多数或全部时候,你都用词法上的self = this或箭头函数“技巧”抵御this机制,那么也许你应该: 仅使用词法作用域并忘掉虚伪的this风格代码。 完全接受this风格机制,包括在必要的时候使用bind(..),并尝试避开self = this和箭头函数的“词法this”技巧。 一个程序可以有效地同时利用两种风格的代码(词法和this),但是在同一个函数内部,特别是对同种类型的查找,混合这两种机制通常是自找很难维护的代码,而且可能是聪明过了头。 复习 为执行中的函数判定this绑定需要找到这个函数的直接调用点。找到之后,4种规则将会以 这个 优先顺序施用于调用点: 被new调用?使用新构建的对象。 被call或apply(或 bind)调用?使用指定的对象。 被持有调用的环境对象调用?使用那个环境对象。 默认:strict mode下是undefined,否则就是全局对象。 小心偶然或不经意的 默认绑定 规则调用。如果你想“安全”地忽略this绑定,一个像ø = Object.create(null)这样的“DMZ”对象是一个很好的占位值,来保护global对象不受意外的副作用影响。 与这4种绑定规则不同,ES6的箭头方法使用词法作用域来决定this绑定,这意味着它们采用封闭他们的函数调用作为this绑定(无论它是什么)。它们实质上是ES6之前的self = this代码的语法替代品。

以上是关于this 指向问题的主要内容,如果未能解决你的问题,请参考以下文章

面向对象this指向问题

this的指向问题

this指向问题new的过程

this指向问题

JavaScript原型对象this指向问题

this的指向问题