前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >this 指向(一)

this 指向(一)

作者头像
小小范
发布2022-01-18 19:36:17
9490
发布2022-01-18 19:36:17
举报
文章被收录于专栏:持续学习

你可能遇到过这样的 JS 面试题:

代码语言:javascript
复制
var obj = {
  foo: function(){
    console.log(this)
  }
}

var bar = obj.foo
obj.foo() // 打印出的 this 是 obj
bar() // 打印出的 this 是 window

请解释最后两行函数的值为什么不一样。

-------

初学者关于 this 的理解一直很模糊。今天这篇文章就要一次讲清楚了。

而且这个解释,你在别的地方看不到。看懂这篇文章,所有关于 this 的面试题,都是小菜。

有用请点赞。

函数调用

首先需要从函数的调用开始讲起。

JS(ES5)里面有三种函数调用形式:

代码语言:javascript
复制
func(p1, p2) 
obj.child.method(p1, p2)
func.call(context, p1, p2) // 先不讲 apply

一般,初学者都知道前两种形式,而且认为前两种形式「优于」第三种形式。

从看到这篇文章起,你一定要记住,第三种调用形式,才是正常调用形式:

代码语言:javascript
复制
func.call(context, p1, p2)

其他两种都是语法糖,可以等价地变为 call 形式:

代码语言:javascript
复制
func(p1, p2) 等价于
func.call(undefined, p1, p2)

obj.child.method(p1, p2) 等价于
obj.child.method.call(obj.child, p1, p2)

请记下来。(我们称此代码为「转换代码」,方便下文引用)

至此我们的函数调用只有一种形式:

代码语言:javascript
复制
func.call(context, p1, p2)

这样,this 就好解释了

this,就是上面代码中的 context。就这么简单。

this 是你 call 一个函数时传的 context,由于你从来不用 call 形式的函数调用,所以你一直不知道。

先看 func(p1, p2) 中的 this 如何确定:

当你写下面代码时

代码语言:javascript
复制
function func(){
  console.log(this)
}

func()

用「转换代码」把它转化一下,得到

代码语言:javascript
复制
function func(){
  console.log(this)
}

func.call(undefined) // 可以简写为 func.call()

按理说打印出来的 this 应该就是 undefined 了吧,但是浏览器里有一条规则:

如果你传的 context 是 null 或 undefined,那么 window 对象就是默认的 context(严格模式下默认 context 是 undefined)

因此上面的打印结果是 window。

如果你希望这里的 this 不是 window,很简单:

代码语言:javascript
复制
func.call(obj) // 那么里面的 this 就是 obj 对象了

再看 obj.child.method(p1, p2) 的 this 如何确定

代码语言:javascript
复制
var obj = {
  foo: function(){
    console.log(this)
  }
}

obj.foo() 

按照「转换代码」,我们将 obj.foo() 转换为

代码语言:javascript
复制
obj.foo.call(obj)

好了,this 就是 obj。搞定。

回到题目:

代码语言:javascript
复制
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 对象

[ ] 语法

代码语言:javascript
复制
function fn (){ console.log(this) }
var arr = [fn, fn2]
arr[0]() // 这里面的 this 又是什么呢?

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

代码语言:javascript
复制
        arr[0]() 
假想为    arr.0()
然后转换为 arr.0.call(arr)
那么里面的 this 就是 arr 了 :)

经典题目

第一题

代码语言:javascript
复制
function X() {
  return object = {
    name: 'object',
    f1: function (x) {
      x.f2();
    },
    f2: function () {
      console.log(this);
    },
  };
}

var options = {
  name: 'options',
  f1: function () {},
  f2: function () {
    console.log(this);
  },
};

var x = X();
x.f1(options); // 求执行结果

// 1. x is object;
// 2. object.f1(options);
// 3. options.f2(); ==> options.f2.call(options)
// 4. this is options

第二题

代码语言:javascript
复制
function X() {
  return object = {
    name: 'object',
    f1: function (x) {
      x.f2.call(this);
    },
    f2: function () {
      console.log(this);
    },
  };
}

var options = {
  name: 'options',
  f1: function () {},
  f2: function () {
    console.log(this);
  },
};

var x = X();
x.f1(options); // 求执行结果

// 1. x is object;
// 2. object.f1(options);
// 3. x.f2.call(this) ==> options.f2.call(object)
// 4. this is object

第三题

代码语言:javascript
复制
function X() {
  return object = {
    name: 'object',
    options:null , // options:options
    f1: function (x) {
      this.options = x;
      this.f2() // obejct object.f2.call(object)
    },
    f2: function () {
      this.options.f2.call(this); // object.options.f2.call(object)
    },
  };
}

var options = {
  name: 'options',
  f1: function () {},
  f2: function () {
    console.log(this); // object.options.f2.call(object)
  },
};

var x = X();
x.f1(options); // 求执行结果

箭头函数

我不明白为什么需要讨论箭头函数,实际上箭头函数里并没有 this,如果你在箭头函数里看到 this,你直接把它当作箭头函数外面的 this 即可。外面的 this 是什么,箭头函数里面的 this 就还是什么,因为箭头函数本身不支持 this。

有人说「箭头函数里面的 this 指向箭头函数外面的 this」,这很傻,因为箭头函数内外 this 就是同一个东西,并不存在什么指向不指向。

总结

  1. this 就是你 call 一个函数时,传入的第一个参数。(请务必背下来「this 就是 call 的第一个参数」)
  2. 如果你的函数调用形式不是 call 形式,请按照「转换代码」将其转换为 call 形式。

参考链接:

this - JavaScript | MDN (mozilla.org)

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 函数调用
  • 这样,this 就好解释了
  • [ ] 语法
  • 经典题目
  • 箭头函数
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档