参考:https://mp.weixin.qq.com/s/b_SojysoGA_Z7WLJrilizg

一、原理

js函数中的this变量指向是什么?这和this所在的函数的声明和调用情况有关

1. 函数作为对象的属性被调用

作为哪个对象的函数调用的,函数中的this就指向哪个对象。如果在全局环境中调用,this指向window(strict模式时候是undefined)

2. 通过call、apply调用

call和apply都是Function.prototype上的方法。

call和apply可以改变this指向。

当函数调用call()和apply()时,函数都会立即执行。 call和apply的第一个参数都是要绑定的对象。

call方法可以传给该函数的参数分别作为自己的多个参数,而apply方法必须将传给该函数的参数合并成一个数组作为自己的一个参数:

  1. const person = {name: 'Sam'};
  2. function log(a, b) {
  3. console.log(this.name, a, b);
  4. }
  5. log.call(person, 1, 2); // Sam 1 2
  6. log.apply(person, [1, 2]); // Sam 1 2

3. bind绑定后的函数

bind可以将函数的this绑定到指定对象,优先级高于call、apply。

bind后返回一个新的函数。

bind时候还可以传入固定参数。

  1. const person = {name: 'Sam'};
  2. function log(a, b) {
  3. console.log(this.name, a, b);
  4. }
  5. const log1 = log.bind(person, 1, 2);
  6. log1(); // Sam 1 2

4. 使用new调用(当做构造函数调用)

如果函数被当做构造函数调用,函数中的this指向的是实例。优先级高于bind

5. 箭头函数

箭头函数中的this指向的是它声明时候所在的函数的this。如果在全局声明,那this指向window。

箭头函数的优先级最高,使用call或者apply不会改变指向,使用bind的话,也不会改变this指向,但是bind指定的参数会传给函数。

二、题目

  1. function showThis () {
  2. console.log(this)
  3. }
  4. function showStrictThis () {
  5. 'use strict'
  6. console.log(this)
  7. }
  8. showThis() // window
  9. showStrictThis() // undefined
  1. var boss = {
  2. name: 'boss',
  3. returnThis () {
  4. return this
  5. }
  6. }
  7. boss.returnThis() === boss // true
  1. var boss1 = {
  2. name: 'boss1',
  3. returnThis () {
  4. return this
  5. }
  6. }
  7. var boss2 = {
  8. name: 'boss2',
  9. returnThis () {
  10. return boss1.returnThis()
  11. }
  12. }
  13. var boss3 = {
  14. name: 'boss3',
  15. returnThis () {
  16. var returnThis = boss1.returnThis
  17. return returnThis()
  18. }
  19. }
  20. boss1.returnThis() // boss1
  21. boss2.returnThis() // boss1
  22. boss3.returnThis() // window
  1. var boss1 = {
  2. name: 'boss1',
  3. returnThis () {
  4. return this
  5. }
  6. }
  7. var boss2 = {
  8. name: 'boss2',
  9. returnThis: boss1.returnThis
  10. }
  11. boss2.returnThis() //boss2
  1. function returnThis () {
  2. return this
  3. }
  4. var boss1 = { name: 'boss1' }
  5. returnThis() // window
  6. returnThis.call(boss1) // boss1
  7. returnThis.apply(boss1) // boss1
  1. function returnThis () {
  2. return this
  3. }
  4. var boss1 = { name: 'boss1'}
  5. var boss1returnThis = returnThis.bind(boss1)
  6. boss1returnThis() // boss1
  7. var boss2 = { name: 'boss2' }
  8. boss1returnThis.call(boss2) // still boss1
  1. function showThis () {
  2. console.log(this)
  3. }
  4. showThis() // window
  5. new showThis() // showThis
  6. var boss1 = { name: 'boss1' }
  7. showThis.call(boss1) // boss1
  8. new showThis.call(boss1) // TypeError call is not a constructor call不能被用作构造函数
  9. var boss1showThis = showThis.bind(boss1)
  10. boss1showThis() // boss1
  11. new boss1showThis() // showThis
  1. function callback (cb) {
  2. cb()
  3. }
  4. callback(() => { console.log(this) }) // window
  5. var boss1 = {
  6. name: 'boss1',
  7. callback: callback,
  8. callback2 () {
  9. callback(() => { console.log(this) })
  10. }
  11. }
  12. boss1.callback(() => { console.log(this) }) // still window
  13. boss1.callback2() // boss1
  1. var returnThis = () => this
  2. returnThis() // window
  3. new returnThis() // TypeError
  4. var boss1 = {
  5. name: 'boss1',
  6. returnThis () {
  7. var func = () => this
  8. return func()
  9. }
  10. }
  11. returnThis.call(boss1) // still window
  12. var boss1returnThis = returnThis.bind(boss1)
  13. boss1returnThis() // still window
  14. boss1.returnThis() // boss1
  15. var boss2 = {
  16. name: 'boss2',
  17. returnThis: boss1.returnThis
  18. }
  19. boss2.returnThis() // boss2