前言
最近稍稍有点空闲,复习一下基础知识。说起 JavaScript 这门语言让人头疼的地方, 就绕不开 「this」 关键字的指向问题。
翻阅各大 IT 牛人的博客和相关网站之后......过程就不详细描述了!!
总之,学习完之后,我就"人不住手" 地总结了一下学到的知识,分享给大家。
学习this的必要
JavaScript 是一门基于原型的编程语言,我们可以通过使用关键词 new 和 「this」 来实现代码的复用。
通过学习 「this」 等相关知识,能帮助你更好了解这门语言的设计模式和特性,加深你对代码的理解与使用。
this是什么?this指向谁?
- 「this」 是 JS 关键字,代表了一个空间地址。
- 「this」 是一个指针,指向函数运行时所在的环境。
通俗讲,就是谁调用了函数,函数内的 「this」 就指向谁。因此,我们想知道 「this」 指向谁,就一定要清楚到底是谁调用了函数。(PS:哈哈哈,说了句废话。)
this的四种调用
接下来,我将用实际例子来展示 「this」 的四种调用方式。
条件允许的情况下,请跟随代码案例练习与分析,这将有助于你形成更可靠的记忆。
默认调用
独立函数调用时,「this」 指向 window 对象。

严格模式下,默认绑定的 「this」 指向 undefined 。

对象调用
如果函数执行时有上下文对象,会把函数里的 「this」 默认绑定到这个上下文对象上。

多层调用时,默认获取最后一层调用的上下文对象。

call、apply、bind强制绑定
通过 call、apply、bind 改变函数的 「this」 指向。
绑定后无论怎么调用,也不会改变其「this」指向。

new 绑定调用
老生常谈,先看看 JS 中 new 关键字做了什么:
- 在内存中创建一个新对象
- 将新对象的_proto_指向构造函数的原型prototype对象
- 将构造函数的作用域赋值给新对象,(this指向新对象)
- 执行构造函数中的代码(给这个新对象加属性和方法)
- 返回新对象,如果这个函数没有返回其他对象。
得出结论:
使用 new 调用函数,返回的对象的「this」始终指向自身。

拓展 —— 箭头函数的this
箭头函数区别于以上介绍的运行规则,而是完全根据外部作用域来决定「this」,但其父级是遵循「this」绑定规则的( 即:如果箭头函数的父级的 「this」 指向 window,那么箭头函数的 「this」 也指向 window )
通过例子认识下:

上述例子,可以发现在 setTimeout 中传入函数时,函数中的「this」 会指向 window 对象,那么怎样让「this」指向 obj 对象?
修改下代码:

发现在我们使用箭头函数之后,使其继承了父函数 obj.fn 的「this」指针,达到了如下相同效果:

看到这里,应该以及理解了箭头函数的「this」是继承来的意思。 让我们再通过几个例子方便去理解箭头函数中的「this」。
例1:

相信你一定很疑惑,为什么上述箭头函数里输出的是 window 对象,那么再看一段代码就清楚了。
例2:

我们发现,obj 里的「this」指向的是全局的 window 对象,那么就很好理解了,箭头函数继承了 obj 中的「this」,也指向了全局 window 对象。
最后,我们可以通过箭头函数实现强制绑定「this」的效果。
没修改前的代码:

以上例子是我们讲解对象调用时的例子,我们不难发现,直接用 obj 对象去调用和独立调用时输出的结果不一致。如果你有仔细阅读文章的话,应该不难理解造成这种情形的原因。
接下来,我们通过箭头函数改造下代码,使我们复制的引用,独立调用时「this」也指向 obj。
修改后的代码:

this 的设计缺陷
上述的代码片段,相信已经涵盖了在工作中大部分可能出现的情况。
但是不得不说,关于 「this」 的很多使用方法是不符合我们人的第一直觉的,导致在日常使用中,会出现各种与预期不符的情况。
那么,那些让人 迷惑的行为 有哪些呢 ?
1. 默认调用时 this 指向全局对象 window
上文已经介绍过了,默认调用函数指向 window 。
在实际工作中,如果想要避免此状况。可以设置严格模式,在严格模式下默认调用函数的 this 指向 undefined 。
你也可以使用 call 等方法来进行强制绑定,也能解决上述问题。
2. 嵌套函数中的 this 不会从外层函数中继承

在上述代码中,我们在 fn 方法里添加了 foo 方法,并在 fn 方法中调用 foo 方法。那么,你认为 foo 函数中的 this 指向什么 ?
如果你不清晰 「this」 的使用,按照第一直觉来判断,你可能会觉得 foo 中的 「this」 和外层 fn 函数中的 「this」 都指向 obj 对象。但实际上,你会发现 foo 函数中的 「this」 指向了全局 window 对象,fn 函数中的 「this」 指向 obj 对象。
这当然也是可以解决的:
- 在 fn 函数中声明一个变量来存储 「this」,然后在 foo 函数中使用这个变量。
- 通过 ES6 中的箭头函数来解决。
之前,我们已经介绍过箭头函数中的 this。那么,你能 使用 ES6 中的箭头函数来解决这个问题 吗?
总结
本篇文章主要介绍了 this 的各种使用方法及其效果。
总结一下要注意的点:
- 当函数作为对象的方法调用时,函数中的 this 指向该对象。
- 独立调用函数时,在严格模式下,this 值是 undefined,非严格模式下 this 指向的是全局对象 window。
- 嵌套函数中的 this 不会继承外层函数的 this 。
- ES6 中的箭头函数 this 是继承自父级的 this。
那么本篇文章到此就结束了,相信你阅读完本篇文章之后,在今后实际使用中,能更加游刃有余。
如果发现文章内容有误,欢迎评论指出错误,感谢ing。
如需转载,请征得同意后标明出处。