Fe-interview: [js] 第33天 说说你对this的理解

Created on 18 May 2019  ·  13Comments  ·  Source: haizlin/fe-interview

第33天 说说你对this的理解

js

Most helpful comment

基本上可以归为四类,
全局this 是window
函数this 是调用者
构造函数的this 是new 之后的新对象
call 和 apply bind的this第一个参数

All 13 comments

js 中有两个重要概念:作用域和原型链

我个人感觉
作用域对应函数式开发,闭包是主要工具
原型链对应对象式开发,this 是主要工具,把一些操作封装在一个工具包上,然后用 this 来调用

this在不同场景下指向也不同,比如有可能指向new出来的对象,可能指向全局对象,通过apply/call/bind还可以指向传入的第一个参数,等等。。。

this

指的是当前运行环境的上下文。当然这个this是会发生改变的 如 bind call apply

基本上可以归为四类,
全局this 是window
函数this 是调用者
构造函数的this 是new 之后的新对象
call 和 apply bind的this第一个参数

不严谨说法,谁调用这个函数,this就指向谁。
通常来说,this指向该函数的执行上下文。
arrow function 指向它上一级的执行上下文。

JavaScript 中的 this 用一句话来概括,就是在执行时确定的。从现象上来看,就是谁调用了某个方法,那么这个方法中的 this 指向谁。

下面是最常见的例子:

const obj = {
  sayThis: function() {
    console.log(this);
  }
};

obj.sayThis(); // obj
const globalSay = obj.sayThis;
globalSay(); // window 浏览器中的 global 对象

谁调用了某个方法,那么这个方法中的 this 指向谁

这个“谁”我们可以通过 . 操作符来判断。比如 obj.sayThis(),这里就是 obj 调用了 sayThis 方法,所以 this 指向 obj。而后一个 globalSay() 是直接调用的,在 JavaScript 中会把这个方法绑在全局(window)上,所以本质就是 window.globalSay(),自然这里的 this 就指向了 window

JavaScript 给我们提供了 apply/call/bind 三种方法来改变 this 的指向。在 ES6 的语法中还提供了箭头函语法,让我们在代码书写时就能确定 this 的指向(编译时绑定)。唯一需要注意的就是要避开箭头函数带来的坑。

把上面的例子改为箭头函数,结果完全不同。

const obj = {
  sayThis: () => {
    console.log(this);
  }
};

obj.sayThis(); // window 因为 JavaScript 没有块作用域,所以在定义 sayThis 的时候,里面的 this 就绑到 window 上去了
const globalSay = obj.sayThis;
globalSay(); // window 浏览器中的 global 对象

参考文章:
前端基础进阶(五):全方位解读 this
深入解读 React 组件中的 "this" - 知乎

https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/objects-classes/ch2.md
判定 this
按照优先顺序来总结一下从函数调用的调用点来判定 this 的规则了。按照这个顺序来问问题,然后在第一个规则适用的地方停下。
1、函数是通过 new 被调用的吗(new 绑定)?如果是,this 就是新构建的对象。
var bar = new foo()
2、函数是通过 call 或 apply(或bind) 被调用?如果是,this 就是那个被明确指定的对象。
var bar = foo.call( obj2 )
3、函数是通过环境对象(也称为拥有者或容器对象)被调用的吗(隐含绑定)?如果是,this 就是那个环境对象。
var bar = obj1.foo()
4、否则,使用默认的 this(默认绑定):如果在 strict mode 下,就是 undefined,否则是 global 对象。
var bar = foo()
如果你传递 null 或 undefined 作为 call、apply 或 bind 的 this 绑定参数,那么这些值会被忽略掉,使用默认的this。“更安全”的做法是:为了 this 而传递一个特殊创建好的对象,创建完全为空的对象的最简单方法就是 Object.create(null)(见第五章)。Object.create(null) 和 {} 很相似,但是没有指向 Object.prototype 的委托,所以它比 {} “空得更彻底”。
与这四种绑定规则不同,ES6 的箭头方法使用词法作用域来决定 this 绑定,这意味着它们采用封闭他们的函数调用作为 this 绑定。它们实质上是 ES6 之前的 self = this 代码的语法替代品。

  • 全局this指向window
  • 函数执行时,就指向执行时的函数
  • 构造函数的指向new它的对象
  • 箭头函数不会改变函数的指向
  • 可以通过apply call bind方法来改变函数的指向,指向就是第一次参数
  1. 在普通函数中,this指向window

  2. 在对象中this指向这个对象,但是有特殊情况
    特殊例子
    在其被调用时才确定this指向

  3. 定时器,延时器里的this指向是window

  4. 构造函数中的this指向是new实例化之后的实例

  5. apply,call,bind会改变this指向
    apply改变this指向,第二个参数是数组
    call改变this指向,第二参数是一个一个参数
    bind改变this指向,但是不会立即执行,返回一个新的函数

箭头函数
函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象

一般情况

函数中的this永远指向函数的调用者(在代码执行时才能确定),谁最终调用这个函数,this就指向谁

  • 在全局环境中,this指向window(如果开启严格模式,this将指向undefined)
  • 如果函数是通过new绑定的(构造函数),那么this就指向new出来的对象
  • 如果函数是通过对象调用的,那么this就指向这个对象(但要小心this绑定丢失,尤其要注意将函数作为值向函数中传入赋值时发生隐式丢失)
  • 如果函数是通过callapplybind进行绑定,那么this就指向被绑定的对象

箭头函数

箭头函数中的this例外,它指向定义时所在的位置。或者可以说箭头函数的this继承自外层作用域,只要确定了外层作用域的this,就知道箭头函数中的this指向谁了。

如果函数是独立调用的话this就指向的是全局对象,如果是对象调用那么就指向的是这个对象,并且通过call/apply可以改变this指向,对比箭头函数中的this指向的是父级作用于中的this,并且通过call/apply无法改变this指向。

基本上可以归为四类,
全局this 是window
函数this 是调用者
构造函数的this 是new 之后的新对象
call 和 apply bind的this第一个参数

this的指向不是在编写的时候确定的,是在执行的时候确定的。分为四类:

  1. 默认绑定:非严格模式下this指向全局对象,严格模式下指向undefined
  2. 隐式绑定:如果函数被一个对象调用,this指向该对象
  3. 显示绑定:使用 call apply bind 改变this指向,指向第一个参数
  4. new绑定:构造函数的this 指向new之后的新对象

箭头函数中没有this绑定,必须通过查找作用域链来决定其值,如果箭头函数被非箭头函数所包含,this指向最近一层非箭头函数的this,否则是undefined

Was this page helpful?
0 / 5 - 0 ratings

Related issues

undefinedYu picture undefinedYu  ·  3Comments

haizhilin2013 picture haizhilin2013  ·  3Comments

haizhilin2013 picture haizhilin2013  ·  3Comments

haizhilin2013 picture haizhilin2013  ·  3Comments

haizhilin2013 picture haizhilin2013  ·  3Comments