this 的值到底是什么?一次说清楚
this 的值到底是什么?一次说清楚
你可能遇到过这样的 JS 面试题:
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window
请解释最后两行函数的值为什么不一样。
-------
初学者关于 this 的理解一直很模糊。今天这篇文章就要一次讲清楚了。
而且这个解释,你在别的地方看不到。看懂这篇文章,所有关于 this 的面试题,都是小菜。
有用请点赞。
函数调用
首先需要从函数的调用开始讲起。
JS(ES5)里面有三种函数调用形式:
func(p1, p2)
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不讲 apply
一般,初学者都知道前两种形式,而且认为前两种形式「优于」第三种形式。
从看到这篇文章起,你一定要记住,第三种调用形式,才是正常调用形式:
func.call(context, p1, p2)
其他两种都是语法糖,可以等价地变为 call 形式:
func(p1, p2) 等价于
func.call(undefined, p1, p2)
obj.child.method(p1, p2) 等价于
obj.child.method.call(obj.child, p1, p2)
请记下来。(我们称此代码为「转换代码」,方便下文引用)
至此我们的函数调用只有一种形式:
func.call(context, p1, p2)
这样,this 就好解释了
this,就是上面代码中的 context。就这么简单。
this 是你 call 一个函数时传的 context,由于你从来不用 call 形式的函数调用,所以你一直不知道。
先看 func(p1, p2) 中的 this 如何确定:
当你写下面代码时
function func(){
console.log(this)
}
func()
用「转换代码」把它转化一下,得到
function func(){
console.log(this)
}
func.call(undefined) // 可以简写为 func.call()
按理说打印出来的 this 应该就是 undefined 了吧,但是浏览器里有一条规则:
如果你传的 context 是 null 或 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)
因此上面的打印结果是 window。
如果你希望这里的 this 不是 window,很简单:
func.call(obj) // 那么里面的 this 就是 obj 对象了
再看 obj.child.method(p1, p2) 的 this 如何确定
var obj = {
foo: function(){
console.log(this)
}
}
obj.foo()
按照「转换代码」,我们将 obj.foo() 转换为
obj.foo.call(obj)
好了,this 就是 obj。搞定。
回到题目:
var obj = {
foo: function(){
console.log(this)
}
}
var bar = obj.foo
obj.foo() // 转换为 obj.foo.call(obj),this 就是 obj
bar()
// 转换为 bar.call()
// 由于没有传 context
// 所以 this 就是 undefined
// 最后浏览器给你一个默认的 this —— window 对象
[ ] 语法
function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 这里面的 this 又是什么呢?
我们可以把 arr[0]( ) 想象为arr.0( ),虽然后者的语法错了,但是形式与转换代码里的 obj.child.method(p1, p2) 对应上了,于是就可以愉快的转换了:
arr[0]()
假想为 arr.0()
然后转换为 arr.0.call(arr)
那么里面的 this 就是 arr 了 :)
箭头函数
我不明白为什么需要讨论箭头函数,实际上箭头函数里并没有 this,如果你在箭头函数里看到 this,你直接把它当作箭头函数外面的 this 即可。外面的 this 是什么,箭头函数里面的 this 就还是什么,因为箭头函数本身不支持 this。
有人说「箭头函数里面的 this 指向箭头函数外面的 this」,这很傻,因为箭头函数内外 this 就是同一个东西,并不存在什么指向不指向。
总结
- this 就是你 call 一个函数时,传入的第一个参数。(请务必背下来「this 就是 call 的第一个参数」)
- 如果你的函数调用形式不是 call 形式,请按照「转换代码」将其转换为 call 形式。
以后你遇到所有跟 this 有关的笔试题,都不会有疑问了。
完。
更多精彩教程,请看我的首页加 QQ 群。
P.S.
- 使用 new 时,情况又不一样,可以看另一篇文章《JS 的 new 到底是干什么的?》。
- 后续篇《你怎么还没搞懂 this? - 知乎专栏》
- 有人说你怎么不讲 strict mode 呢,strict mode 也会影响 this 呀。我认为 strict mode 只是影响了 context 的默认值而已,你看懂此文稍微看看 strict mode 就懂了。我只讲最重要的内容。
- 有人问怎么不讲 bind 对 this 的影响。那是因为 bind 本质就是自动在你调用一个函数的时候,把 context 换掉而已,你看看 bind 的 polyfill 就知道,其核心依然是 apply(跟 call 差不多)。
- 有人问箭头函数,箭头函数其实跟 this 没关系,所以如果你在箭头函数里面看到 this ,就当作是它外面的函数的 this 即可。
this 的值到底是什么?一次说清楚的更多相关文章
- C++ 赋值构造函数的返回值到底有什么用?且返回值是否为引用类型有什么区别吗?
首先定义类Person class Person{ public: string name; Person()=default; //默认构造函数 Person(string nam):name(na ...
- Java的Object.hashCode()的返回值到底是不是对象内存地址?
关于这个问题,查阅了网上的资料,发现证明过程太繁琐,这里我用了反证法. java.lang.Object.hashCode()的返回值到底是不是对象内存地址? hashCode契约 说到这个问题,大家 ...
- JS中this的值到底为何?
之前很久的时间,因为研究不深,对于this的值一直模模糊糊,不是很清楚,最近有空做了一些研究,终于彻底弄明白了this到底为何物. 首先, 先抛出一个定论:”在Javascript中,this关键字永 ...
- 彻底理解this 的值到底是什么?
作者:方应杭 来源:知乎 你可能遇到过这样的 JS 面试题: var obj = { foo: function(){ console.log(this) } } var bar = obj.foo ...
- 转载自知乎大神---this 的值到底是什么?一次说清楚
你可能遇到过这样的 JS 面试题: var obj = { foo: function(){ console.log(this) } } var bar = obj.foo obj.foo() // ...
- input框中的value值到底是什么
value 属性为 input 元素设定值. 对于不同的输入类型,value 属性的用法也不同: type="button", "reset", "s ...
- GET和POST可传递的值到底有多大?
前日,看到这个问题了. 没有深入了解.我的常识里面get最大传递的值为256b,post 是2M.这是很久以前不知在哪看到的.于是又百度一下.看到两篇文章装过来看看: 浅谈 HTTP中Get与Post ...
- this 的值到底是什么?
你可能遇到过这样的 JS 面试题: var obj = { foo: function(){ console.log(this) } } var bar = obj.foo obj.foo() // ...
- cmp的值到底是0还是1还是-1的问题
返回值不局限于这三个数返回负数,表示第一个参数小于第二个参数返回整数,表示第一个参数大于第二个参数返回0,表示他们相等
随机推荐
- spark集群
https://blog.csdn.net/boling_cavalry/article/details/86747258 https://www.cnblogs.com/xuliangxing/p/ ...
- Kafka消费者没有收到通知的分析
今天遇到两位三方人员跟我反馈,某微服务的异步接口功能不正常了,由于该异步接口采用Kafka异步消息的方案,对方说没有收到Kafka给消费者的通知,根据此问题,联系了相关人员进行了分析: (一)明确环境 ...
- vue(五)--双向绑定(v-model)
1.简单使用: 当input里面的值发生变化的时候,就会自动把变化后的值,绑定到Vue对象上去了 <body> <div id="app"> <inp ...
- Java 8 函数式编程
今天打开Oracle Java官网一看,Java已经更新到 13 了 https://www.oracle.com/technetwork/java/javase/jdk-relnotes-index ...
- 如何安装selenium框架
半年前因不满自己工作内容,便到处寻求资料,偶遇分享一套全套教程.开始学习python,后接触selenium有关内容. 前期因为配置环境花了些许时间,后来解决了,回想是如此简单 安装步骤 1.下载py ...
- P1345 [USACO5.4]奶牛的电信Telecowmunication【最小割】【最大流】
题目描述 农夫约翰的奶牛们喜欢通过电邮保持联系,于是她们建立了一个奶牛电脑网络,以便互相交流.这些机器用如下的方式发送电邮:如果存在一个由c台电脑组成的序列a1,a2,...,a(c),且a1与a2相 ...
- 重启监听卡在connecting to的问题
问题描述:lsnrctl start启动监听起不来,一直卡在connecting to半天 1.[oracle@orcl ~]$ lsnrctl start 一直卡半天,就是连不上,按照以前的解决办法 ...
- OpenCV基本绘图函数
线段:line 函数 CV_EXPORTS_W void line(CV_IN_OUT Mat& img, Point pt1, Point pt2, const Scalar& co ...
- Swaps and Inversions HDU - 6318 树状数组+离散化
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> us ...
- 让bat文件自动以管理员身份运行
· 让bat文件自动以管理员身份运行 如何让bat文件自动以管理员身份运行,将这段写在bat文件的前头即可 : %1 mshta vbscript:CreateObject("Shell.A ...
