this 指向问题

this指向问题可谓是js中一个老生常谈的话题了,不论是在实际开发还是前端面试中,this指向问题都或多或少让人“头疼”,因为this的指向涉及的规范实在是太繁多了......但这并不是我们放弃的理由(手动狗头),毕竟只有彻底掌握它所涉及的知识点,才能在开发中活学活用嘛!今天我们就从this指向问题展开,看一看它到都有哪些规则:)

一、一句话总结this指向

关于this的指向,有一种被大家所熟知的说法是:**谁调用它,this就指向谁**,即this的指向是在调用的时候确定的,而不是声明的时候。这种说法虽然不是百分百准确,但也概括了绝大部分场景。

二、执行上下文

既然在总结this指向时说到了“调用”,我们就不得不提到js中一个基础的概念————**执行上下文**(execution context)了。

js中的执行上下文指的是当前执行环境中的变量、函数声明、参数、作用域链、this等信息,分为全局执行上下文和函数执行上下文,他们俩的区别在于全局执行上下文只有一个,函数执行上下文在每次调用函数时候会创建一个新的函数执行上下文。执行上下文也有自己的生命周期,分为创建和执行阶段,创建阶段做的事情包括:生成变量对象、创建arguments、扫描函数声明、扫描变量声明、建立作用域链、**确定this的指向**,执行阶段做的事情大致包括变量赋值、函数引用和执行其他代码等。

一段代码的运行可能会产生多个执行上下文,那怎么去管理这多个执行上下文呢?————执行上下文栈(调用栈),我们知道栈是一种先入后出的数据结构,利用这一特点,js代码可以保证代码执行过程中保持执行时所在的执行上下文环境。

上面提到,执行上下文的创建阶段会确定 this 的指向。因此,关于this指向我们可以确定的一点是:this 的指向是在**调用函数**时根据**执行上下文**所**动态确定**的。

### 三、this绑定规则

1、默认绑定————绑定至全局对象window

观察以下代码:

![image.png](http://ttc-tal.oss-cn-beijing.aliyuncs.com/1628490252/image.png)

在代码中,foo()是直接使用**不带任何修饰的函数引用**进行调用的,因此其内部this为默认绑定规则,即**独立函数调用**时其this会指向全局对象,用之前执行上下文的角度来说,独立函数调用时它处于全局执行上下文。需要注意的是,如果使用严格模式(strict mode),不能将全局对象用于默认绑定,因此this会绑定到undefined。

2、隐式绑定

观察以下代码:![image.png](http://ttc-tal.oss-cn-beijing.aliyuncs.com/1628491149/image.png)

可以看到foo是单独声明的,之后被当作引用属性添加到了obj中。从声明方式上来看,foo函数严格来不属于obj对象,然而,obj.foo()这种调用方式会使用obj执行上下文来引用foo函数,可以说函数foo被调用时obj对象“拥有”或者“包含”它。当函数引用有执行上下文对象时,隐式绑定规则会把函数调用中的this绑定到这个上下文对象。因为调用foo()时this被绑定到obj,因此this.a和obj.a是一样的。

为什么称之为隐式绑定呢?因为我们必须在一个对象内部包含一个指向函数的属性,并通过这个属性间接引用函数,从而把this间接绑定到这个对象上。

ps: 对象属性引用链中**只有上一层或者说最后一层在调用位置中起作用**,这条规则能使我们在嵌套调用中定位this的指向。举个例子:

![image.png](http://ttc-tal.oss-cn-beijing.aliyuncs.com/1628491663/image.png)

3、隐式丢失

观察以下代码:

![image.png](http://ttc-tal.oss-cn-beijing.aliyuncs.com/1628491804/image.png)

看起来bar是obj.foo的一个引用,但是实际上,它引用的是foo函数本身,因此此时的bar()其实是一个不带任何修饰的函数调用,符合默认绑定规则,因此应用了默认绑定。类似情况还有函数作为参数传递,也属于一种隐式赋值。

4、显式绑定

不同于隐式绑定,如果我们不想在对象内部包含函数引用,而想在某个对象上强制调用函数,该怎么做呢?此时可以使用**函数的**call/apply/bind方法(使用方式:f.call()/f.apply()/f.bind())。

这三个方法是如何工作的呢?它们的第一个参数是一个对象,是给this准备的,接着在调用函数时将this绑定到该对象。因为可以直接指定this的绑定对象,因此我们称之为显式绑定。总结来说,他们都是用来改变相关函数 this 指向的,call/apply 是直接进行相关函数调用;bind 不会执行相关函数,而是返回一个新的函数,这个新的函数已经自动绑定了新的 this 指向,手动调用即可。

5、new绑定

我们知道,使用new来调用函数时,会自动执行下面的操作:

(1)创建(或者说构造)一个全新的对象;

(2)这个新对象会被执行[[Prototype]]连接;

(3)这个新对象会绑定到函数调用的this;

(4)如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

使用new来调用函数时,会构造一个新对象并把它绑定到函数调用中的this上。

6、优先级

结论:new绑定>显式绑定(call、apply、bind)>隐式绑定>默认绑定

因此可以按照下面的顺序来进行判断:

(1)函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。

(2)函数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对象。

(3)函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。

(4)如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到window。

四、箭头函数

之前介绍的绑定规则已经可以包含所有正常的函数,但是ES6中新增了一种特殊函数类型:箭头函数。箭头函数并不是使用function关键字定义的,而是使用操作符=>定义的。箭头函数不使用this的四种标准规则,而是根据外层(函数或者全局)作用域来决定this。

具体来说,箭头函数会继承外层函数调用的this绑定(无论this绑定到什么),这其实和ES6之前代码中的self = this机制一样。

五、小结

this 的指向是在调用函数时根据执行上下文所动态确定的。

要判断一个运行中函数的this绑定,就需要找到这个函数的直接调用位置,可以按照下面的顺序来进行判断:

(1)函数是否在new中调用(new绑定)?如果是的话this绑定的是新创建的对象。

(2)函数是否通过call、apply(显式绑定)或者硬绑定调用?如果是的话,this绑定的是指定的对象。

(3)函数是否在某个上下文对象中调用(隐式绑定)?如果是的话,this绑定的是那个上下文对象。

(4)如果都不是的话,使用默认绑定。如果在严格模式下,就绑定到undefined,否则绑定到window。

箭头函数是个例外,它会继承外层函数调用的this绑定(无论this绑定到什么)。

注:参考《你不知道的JavaScript》

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,837评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,551评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,417评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,448评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,524评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,554评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,569评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,316评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,766评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,077评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,240评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,912评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,560评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,176评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,425评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,114评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,114评论 2 352

推荐阅读更多精彩内容