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 又是什么呢?

我们可以把 arr0 想象为arr.0( ),虽然后者的语法错了,但是形式与转换代码里的 obj.child.method(p1, p2) 对应上了,于是就可以愉快的转换了:

         arr[0]() 
假想为    arr.0()
然后转换为 arr.0.call(arr)
那么里面的 this 就是 arr 了 :)

总结

this 就是你 call 一个函数时,传入的 context。
如果你的函数调用形式不是 call 形式,请按照「转换代码」将其转换为 call 形式。
以后你遇到所有跟 this 有关的笔试题,都不会有疑问了。

完。

P.S.

1.使用 new 时,情况又不一样,可以看另一篇文章《JS 的 new 到底是干什么的?》
2.后续篇《你怎么还没搞懂 this? – 知乎专栏》
3.有人说你怎么不讲 strict mode 呢,strict mode 也会影响 this 呀。我认为 strict mode 只是影响了 context 的默认值而已,你看懂此文稍微看看 strict mode 就懂了。我只讲最重要的内容。
4.有人问怎么不讲 bind 对 this 的影响。那是因为 bind 本质就是自动在你调用一个函数的时候,把 context 换掉而已,你看看 bind 的 polyfill 就知道,其核心依然是 apply(跟 call 差不多)。

作者:方应杭

36 thoughts on “this 的值到底是什么?一次说清楚”

  1. Wonderful beat ! I would like to apprentice whilst you amend your website, how could i subscribe for a blog web site? The account aided me a appropriate deal. I had been tiny bit acquainted of this your broadcast provided vibrant clear idea|

  2. Hi there! I just wanted to ask if you ever have any problems with hackers? My last blog (wordpress) was hacked and I ended up losing months of hard work due to no backup. Do you have any solutions to prevent hackers?|

  3. Hey just wanted to give you a quick heads up. The words in your post seem to be running off the screen in Chrome. I’m not sure if this is a formatting issue or something to do with web browser compatibility but I figured I’d post to let you know. The style and design look great though! Hope you get the problem resolved soon. Many thanks|

  4. Hey excellent website! Does running a blog similar to this take a great deal of work? I have no expertise in coding however I had been hoping to start my own blog in the near future. Anyhow, should you have any suggestions or techniques for new blog owners please share. I understand this is off topic however I just wanted to ask. Thanks a lot!|

  5. Oh my goodness! Awesome article dude! Thanks, However I am going through problems with your RSS. I don’t know why I am unable to join it. Is there anyone else getting similar RSS problems? Anyone that knows the solution will you kindly respond? Thanx!!|

  6. Asking questions are actually good thing if you are not understanding something fully, however this piece of writing gives nice understanding even.|

  7. I want to to thank you for this great read!! I absolutely enjoyed every bit of it. I’ve got you bookmarked to check out new things you post…|

  8. Quality articles is the important to invite the people to visit the web site, that’s what this website is providing.|

  9. Somebody necessarily assist to make significantly articles I might state. That is the first time I frequented your web page and so far? I amazed with the analysis you made to create this actual put up extraordinary. Great activity!|

  10. Hi there, just became alert to your blog through Google, and found that it is truly informative. I am going to watch out for brussels. I will appreciate if you continue this in future. Lots of people will be benefited from your writing. Cheers!|

  11. Does your blog have a contact page? I’m having a tough time locating it but, I’d like to send you an e-mail. I’ve got some suggestions for your blog you might be interested in hearing. Either way, great website and I look forward to seeing it improve over time.|

  12. I want to to thank you for this very good read!! I certainly enjoyed every little bit of it. I have you saved as a favorite to check out new stuff you post…|

  13. I am extremely inspired with your writing talents and also with the format on your blog. Is that this a paid subject or did you modify it yourself? Either way keep up the excellent quality writing, it is uncommon to look a nice blog like this one these days..|

  14. My brother recommended I might like this web site. He was entirely right. This post actually made my day. You cann’t imagine simply how much time I had spent for this info! Thanks!|

发表评论

电子邮件地址不会被公开。