JS 中 this 的用法

382 阅读6分钟

前言

最近稍稍有点空闲,复习一下基础知识。说起 JavaScript 这门语言让人头疼的地方, 就绕不开 「this」 关键字的指向问题。

翻阅各大 IT 牛人的博客和相关网站之后......过程就不详细描述了!!

总之,学习完之后,我就"人不住手" 地总结了一下学到的知识,分享给大家。

学习this的必要

JavaScript 是一门基于原型的编程语言,我们可以通过使用关键词 new 和 「this」 来实现代码的复用。

通过学习 「this」 等相关知识,能帮助你更好了解这门语言的设计模式和特性,加深你对代码的理解与使用。

this是什么?this指向谁?

  • this」 是 JS 关键字,代表了一个空间地址。
  • this」 是一个指针,指向函数运行时所在的环境。

通俗讲,就是谁调用了函数,函数内的 「this」 就指向谁。因此,我们想知道 「this」 指向谁,就一定要清楚到底是谁调用了函数。(PS:哈哈哈,说了句废话。)

this的四种调用

接下来,我将用实际例子来展示 「this」 的四种调用方式。

条件允许的情况下,请跟随代码案例练习与分析,这将有助于你形成更可靠的记忆。

默认调用

独立函数调用时,「this」 指向 window 对象。

image

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

image

对象调用

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

image

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

image

call、apply、bind强制绑定

通过 call、apply、bind 改变函数的 「this」 指向。

绑定后无论怎么调用,也不会改变其「this」指向。

image

new 绑定调用

老生常谈,先看看 JS 中 new 关键字做了什么:

  1. 在内存中创建一个新对象
  2. 将新对象的_proto_指向构造函数的原型prototype对象
  3. 将构造函数的作用域赋值给新对象,(this指向新对象)
  4. 执行构造函数中的代码(给这个新对象加属性和方法)
  5. 返回新对象,如果这个函数没有返回其他对象。

得出结论:

使用 new 调用函数,返回的对象的「this」始终指向自身。

image

拓展 —— 箭头函数的this

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

通过例子认识下:

image

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

修改下代码:

image

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

image

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

例1:

image

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

例2:

image

我们发现,obj 里的「this」指向的是全局的 window 对象,那么就很好理解了,箭头函数继承了 obj 中的「this」,也指向了全局 window 对象。

最后,我们可以通过箭头函数实现强制绑定「this」的效果。

没修改前的代码:

image

以上例子是我们讲解对象调用时的例子,我们不难发现,直接用 obj 对象去调用和独立调用时输出的结果不一致。如果你有仔细阅读文章的话,应该不难理解造成这种情形的原因。

接下来,我们通过箭头函数改造下代码,使我们复制的引用,独立调用时「this」也指向 obj

修改后的代码:

image

this 的设计缺陷

上述的代码片段,相信已经涵盖了在工作中大部分可能出现的情况。

但是不得不说,关于 「this」 的很多使用方法是不符合我们人的第一直觉的,导致在日常使用中,会出现各种与预期不符的情况。

那么,那些让人 迷惑的行为 有哪些呢 ?

1. 默认调用时 this 指向全局对象 window

上文已经介绍过了,默认调用函数指向 window 。

在实际工作中,如果想要避免此状况。可以设置严格模式,在严格模式下默认调用函数的 this 指向 undefined 。

你也可以使用 call 等方法来进行强制绑定,也能解决上述问题。

2. 嵌套函数中的 this 不会从外层函数中继承

image

在上述代码中,我们在 fn 方法里添加了 foo 方法,并在 fn 方法中调用 foo 方法。那么,你认为 foo 函数中的 this 指向什么 ?

如果你不清晰 「this」 的使用,按照第一直觉来判断,你可能会觉得 foo 中的 「this」 和外层 fn 函数中的 「this」 都指向 obj 对象。但实际上,你会发现 foo 函数中的 「this」 指向了全局 window 对象,fn 函数中的 「this」 指向 obj 对象。

这当然也是可以解决的:

  1. 在 fn 函数中声明一个变量来存储 「this」,然后在 foo 函数中使用这个变量。
  2. 通过 ES6 中的箭头函数来解决。

之前,我们已经介绍过箭头函数中的 this。那么,你能 使用 ES6 中的箭头函数来解决这个问题 吗?

总结

本篇文章主要介绍了 this 的各种使用方法及其效果。

总结一下要注意的点:

  1. 当函数作为对象的方法调用时,函数中的 this 指向该对象。
  2. 独立调用函数时,在严格模式下,this 值是 undefined,非严格模式下 this 指向的是全局对象 window。
  3. 嵌套函数中的 this 不会继承外层函数的 this 。
  4. ES6 中的箭头函数 this 是继承自父级的 this。

那么本篇文章到此就结束了,相信你阅读完本篇文章之后,在今后实际使用中,能更加游刃有余。


如果发现文章内容有误,欢迎评论指出错误,感谢ing。


如需转载,请征得同意后标明出处。