JS中的this

172 阅读3分钟

前言

在前端的面试中会经常被问到关于this的问题,一听到这个问题是关于this的。第一反应就是,哎,就问个这啊,听起来是那么熟悉,而且经常会用到,但是回答的时候就傻眼了,该怎么说呢,从哪说呢,瞬间就冷场了。

var obj = {
 foo: function(){
   console.log(this)
 }
}
var bar = obj.foo
obj.foo()  // 打印出的 this 是 obj
bar()  // 打印出的 this 是 window

这到题在面试中还是很常见的,看到这道题的时候答案几乎是连蒙带猜写出来的,而且一点底气都没有的。下面就开始把对this的了解总结一下。

this 是什么

this是在函数被调用的时候确定的,它的指向取决于调用函数的地方,而不是声明函数的地方。当一个函数被调用的时候,会创建一个执行上下文,它包含函数在哪里调用,调用函数的方式,传入的参数信息。this在以下几种场景中会体现出来

  • 作为构造函数被new调用
  • 对象的函数被调用的时候
  • call,apply,bind调用的时候
  • 直接调用函数的时候

下面就对着几种场景分别讨论

call调用

其实我们在开发过程中分不清this的指向,一大部分原因是因为我们没有使用call的方式来调用函数。

常用的调用方式

function fun(a){
    console.log(a);
}

以上我们声明了一个函数fn,在我们需要调用这个函数的时候我们通常是这样写的

fun('a');

函数名后面直接加小括号,简单粗暴,写起来也很方便,但是好多人应该都不知道其实正确的调用函数的方法不是这样的,而应该使用call的方式去掉用,如果我们一开始就知道call的调用方式,那么也就不会对this这么迷惑了。

call的语法

fun.call(thisArg, arg1, arg2, ...)

thisArg

thisArg 是函数运行时指定的this值。需要注意的是,如果这个函数是在非严格模式下运行,则指定为nullundefined的值会自动指向全局对象(window)。

arg1, arg2, ...

指定的参数列表

使用call调用

现在我们在看那道出现频率比较高的this面试题

var obj = {
 foo: function(){
   console.log(this)
 }
}
var bar = obj.foo
obj.foo()  // 打印出的 this 是 obj
bar()   // 打印出的 this 是 window

我们不知道this到底指向的是哪里是因为我们没有使用call的调用方式,现在我们就修改成call的调用方式

var obj = {
 foo: function(){
   console.log(this)
 }
}
var bar = obj.foo
obj.foo.call(obj); // 打印出的 this 是 obj
bar.call(null);  // 打印出的 this 是 window

通过call的方式调用是不是就很明显的看出this是什么了,所以当我们在遇到关于这方面的题之后我们只要想到把函数转换成call的调用方式,那就不会再使我们感到困惑了。

总结

  • fn() 这种调用方式是一种语法糖,可以转换成call的调用方式
  • call的第一个参数就是this
  • 非严格模式下call的第一个参数是null或者undefined,那么this的指向就是window
  • call 才是调用函数的正常方式