this 的指向问题

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。

this的指向已经是一个老生常谈的问题,每逢面试都要去复习复习,近来巩固js的基础,决心彻底掌握这个知识点,一劳永逸。说明一下,为了不影响大家的思考过程,下面的代码都不会去注释答案,想知道答案,只需要去控制台执行一下。

四类场景逐一击破

首先,分析this的指向共有四种类型,在分析之前,我们首先带好两个锦囊:
1.函数被调用时(即运行时)才会确定该函数内this的指向。因为在函数中this与arguments是两个特殊的变量,在函数被调用时才会取得它们,而且搜索这两个变量时只会在活动对象范围里面去搜。(有关活动对象与变量对象的知识,请移步到js 中的活动对象 与 变量对象 什么区别?)
2.要确定函数中this的指向,必须先找到该函数被调用的位置。

认准第一种“test()”形式

var a = 1
function test () {console.log(this.a)
}
test()

直接不带任何引用形式去调用函数,则this会指向全局对象,因为没有其他影响去改变this,this默认就是指向全局对象(浏览器是window,Node中是global)的。这个结论是在非严格模式的情况下,严格模式下这个this其实是undefined的。

认准第二种“xxx.test()”形式

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
obj.test()

这种形式对比起第一种,很明显test()已经是名花有主的了!看清楚,是谁呼唤的test()?没错,就是obj,所以this的指向就不言而喻了。一句话,谁去调用这个函数的,这个函数中的this就绑定到谁身上。

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
var obj0 = {a: 3,obj 
}
obj0.obj.test()

即使是这种串串烧的形式,结果也是一样的,test()中的this只对直属上司(直接调用者obj)负责。再来看一个综合点的例子:

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
var testCopy = obj.test
testCopy()

嗯,聪明的你一定想到,换了个名字就能骗到我了!?虽然经过了一波改名换姓,但本质上还不是obj.test()嘛!结果一定和上面一样!唔,请F12在控制台试试,竟然……其实这里并不需要去思考什么,按照我们的套路,我们就认函数调时的样子,有没有看到最后调用的时候跟第一种情况一毛一样?我再介绍一个场景大家一定不会觉得陌生:

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
setTimeout(obj.test)

你可以意淫一下setTimeout的本质,是不是相当于有一个setTimeout函数,接收两个参数:

function setTimeout (fn, time) {// 这里干了一大波不可描述的事情,最后会去调一下你传进来的回调函数fn()
}

看到怎样调用你传进来的函数了吗!?再想想我们第一种形式的标题认准第一种“test()”形式

认准第三种“test.call(xxx) / test.apply(xxx) / test.bind()”形式

看了上面两种形式之后,你可能会想,我非常讨厌上面那些矫情的扭扭捏捏的九曲十八弯的调用方式,让人毫无安全感,我要我自己指定this的指向,我要胜天半子!没问题,我的代码我做主:

var a = 1
function test () {console.log(this.a)
}
var obj = {a: 2,test
}
var testCopy = obj.test
testCopy.call(obj)

可以看到,我们通过call(apply跟call的区别只是传参,作用是一样的,bind有点区别,bind能让我们的函数延迟执行,apply与call调用就执行,所以bind这样的形式我们也称为函数柯里化,这些就不是我们这里要说的啦)来调用testCopy,并且传入了你想要this指向的上下文,那么this就会乖乖按照你的指示行事啦。看到这里,我们也可以想象第一、二种形式其实可以转化成call/apply的形式,有一篇比较棒的文章描述了这样的思考过程,大家也可以看看this 的值到底是什么?一次说清楚

认准第四种“new test()”形式

终于到了最后一种形式了,这种形式比较好认,因为有标志性的new:

var a = 1
function test (a) {this.a = a
}
var b = new test(2)
console.log(b.a)

new这个操作符其实是new了一个新对象出来,而被new的test我们称为构造函数,我们可以在这个构造函数里定义一下将要到来的新对象的一些属性。那么在构造函数里,我们怎样去描述这个还未出生的新对象呢?没错,就是用this。所以构造函数里的this指的就是将要被new出来的新对象。

One more thing

感谢大家看到这里,但还要说最后一种形式。等等,不是说好的只有四种形式吗!稍安勿躁,正常套路下确实只有上面四种,但是有个东西别忘了,就是大家最喜欢的箭头函数。

var a = 1
var test = () => {console.log(this.a)
}
var obj = {a: 2,test
}
obj.test()

来,往上翻一下我们的第一个锦囊,“函数被调用时(即运行时)才会确定该函数内this的指向。”现在函数这两个字要加个词修饰一下,变成普通函数(非箭头函数)才能区别于箭头函数。箭头函数中的this在函数定义的时候就已经确定,它this指向的是它的外层作用域this的指向。

最后

我们最后还要说:“到此为止,真的没有了。”
希望看完这篇文章之后,再有人问this指向的问题,你可以嘴角微微上扬,冷笑一声:“不要再问我this的指向问题了。”
扬长而去。

转自:https://segmentfault.com/a/1190000015438195

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/448382.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C++之全局函数和成员函数的转换

全局函数和成员函数 把全局函数转化成成员函数,通过this指针隐藏左操作数 Test add(Test &t1, Test &t2)》Test add(Test &t2) 把成员函数转换成全局函数,多了一个参数 void printAB()》void printAB(Test *pthis) 函数返回元素和返回引…

HDU 3916 Sequence Decomposition 【贪心】

这道题目的题意就是使用题目中所给的Gate 函数,模拟出输入的结果 当然我们分析的时候可以倒着来,就是拿输入去减 每次Gate 函数都会有一个有效范围 这道题目求的就是,找出一种模拟方法,使得最小的有效范围最大化。 是一道【贪心】…

爆胎

定义 即轮胎爆裂。车辆的缺气(轮胎胎压低于标准胎压)行驶时,随着胎压的下降,轮胎与地面的摩擦成倍增加,胎温急剧升高,轮胎变软,强度急剧下降。这种情况下,如果车辆高速行驶,就可能导致爆胎。…

不要再问我跨域的问题了

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 跨域这两个字就像一块狗皮膏药一样黏在每一个前端开发者身上,无论你在工作上或者面试中无可避免会遇到这个问题。为了应付面…

SSM集合

SSM集成 1. Spring和各个框架的整合 Spring目前是JavaWeb开发中最终的框架,提供一站式服务,可以其他各个框架整合集成 Spring整合方案 1.1. SSH ssh是早期的一种整合方案 Struts2 : Web层框架 Spring : 容器框架 Hibernate &#…

浅谈 CSRF 攻击方式

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 一.CSRF是什么? CSRF(Cross-site request forgery),中文名称:跨站请求伪造&a…

C++之运算符重载(上)

1、概念 所谓重载,就是重新赋予新的含义。函数重载就是对一个已有的函数赋予新的含义,使之实现新功能,因此,一个函数名就可以用来代表不同功能的函数,也就是”一名多用”。 运算符也可以重载。实际上,我们…

手刹

定义 考手刹的专业称呼是辅助制动器,与制动器的原理不同,其是采用钢丝拉线连接到后制动蹄上,以对车子进行制动。作用 用于平地斜坡停车时制动,防止车子在无人状态下自动滑跑,逼免发生交通事故。工作原理 其原…

关于[super dealloc]

销毁一个对象时,需要重写系统的dealloc方法来释放当前类所拥有的对象,在dealloc方法中需要先释放当前类中所有的对象,然后再调用[super dealloc]释放父类中所拥有的对象。如先调用[super dealloc]将释放掉父类中所拥有的对象,当前…

C++之运算符重载(下)

4.提高 1.运算符重载机制 编译器实现运算符重载实际上就是通过函数重载实现的,可分为全局函数方式,也可分为成员函数方式进行重载,并没有改变原操作符的属性和语义。只是针对某个特定类定义一种新的数据类型操作。 2.重载赋值运算符 赋值…

Cookie / Session 的机制与安全

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 Cookie和Session是为了在无状态的HTTP协议之上维护会话状态,使得服务器可以知道当前是和哪个客户在打交道。本文来详细讨论C…

手动挡

定义 手动挡,即用手拨动变速杆才能改变变速器内的齿轮啮合置,改变传动比,从而达到变速的目的。作用 一方面提供了手动的乐趣 另外一方面就是通过手动自主控制转速,还可以迟延或提前换档。驾驶技巧 市区内应直视前方五…

Servlet快速入门及运行流程

一、Servlet快速入门 1.创建一个web工程 2.在JavaResource中src下创建一个包名称为com.myxq.servlet 3.在创建的servlet包当中创建一个class文件起名为FirstServlet 4.进入该class实现一个Servlet接口,实现它未实现的方法 重点看service方法在该方法当中写入一句话进…

C++之多继承

1.基础知识 1.1 类之间的关系 has-A,uses-A 和 is-A has-A 包含关系,用以描述一个类由多个“部件类”构成。实现has-A关系用类成员表示,即一个类中的数据成员是另一种已经定义的类。 常和构造函数初始化列表一起使用 uses-A 一个类部分地…

自动挡

定义 所谓自动挡,就是不用驾驶者去手动换档,车辆会根据行驶的速度和交通情况自动选择合适的档位行驶。作用 能根据路面状况自动变速,使驾驶者可以全神贯地注视路面交通而不会被换档搞得手忙脚乱。工作原理 自动变速器&#xff0c…

聊一聊 cookie

我们看到的 cookie 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 我自己创建了一个网站,网址为http://ppsc.sankuai.com。在这个网页中我设置了几个cookie:JS…

跨域资源共享 CORS 详解

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到教程。 CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览…

油门

定义 油门是内燃机上控制燃料供量的装置。作用 是汽车发动机与摩托车油箱之间的阀门,控制汽油的量。操作注意 1.空车起步勿用大油门,以小油门为宜,负荷起步则以中油门为宜。 2.启动时将油门放在合适位,使机件不易磨损。…

C++之泛型编程(模板)

1.模板综述 背景 有时候许多函数或子程序的逻辑结构是一样的,只是要处理的数据类型不一样有时候多个类具有相同逻辑的成员函数和成员变量,只是成员变量的数据类型以及成员函数的参数类型不一样模板就是解决数据类型不一致造成代码冗余的一种机制&#xf…

Base64转PDF、PDF转IMG(使用pdfbox插件)

--添加依赖 <!-- https://mvnrepository.com/artifact/org.apache.pdfbox/pdfbox --><dependency> <groupId>org.apache.pdfbox</groupId> <artifactId>pdfbox</artifactId> <version>2.0.12</version></dependency&…