七、this指向及修改this指向

(一)this指向的总结

1、非箭头函数的总结

(1)全局中的this,表示window对象

console.log(this);    // window

(2)普通函数中的this,表示window对象,即表示调用者

function fn() {
    console.log(this);    // window
};
fn();

(3)定时器中普通函数的this,表示window对象

setTimeout(function () {
    console.log(this);    // window
},100);

(4)事件处理函数中的this,表示事件源(事件源可以是一个HTML元素、一个浏览器窗口、一个XMLHttpRequest对象等)

document.body.addEventListener('click',function () {
    console.log(this);    // 事件源,此处表示body这个DOM元素
});

(5)构造函数、对象方法、原型对象中的方法中的this,都表示实例对象

function Dog() {
    this.age = 20;
    this.color = 'black';
    this.eat = function () {
    console.log(this);
  }
};
let d = new Dog;
d.eat();           // 指的是实例对象Dog

(6)构造函数的静态方法(给构造函数直接添加的方法叫做静态方法)中的this表示构造函数

function Pig() {}
Pig.chat = function () {
    console.log(this);
}
Pig.chat();

2、箭头函数的总结

三种情况,详见say()、eat()、wash()

var age = 10;
let obj = {
  age : 20,
  say : () => {
    // 函数作用域,外层就是全局作用域(对象的大括号不是作用域)
    console.log(this.age);  // 10
  },
  eat : function () {
    // 箭头函数中没有this,所以此处的this表示的是外层函数(eat函数)的this,即obj
    let fn = () => {
      console.log(this.age);  // 20
    }
    fn();
  },
  wash : () => {
    // 类似于say()
    function abc() {
      console.log(this.age);  // 10
    }
    abc();
  }
};
obj.say();    // 10
obj.eat();    // 20
obj.wash();   // 10

(二)修改函数中this的指向

注意:下面三个方法中只能通过函数调用(实际一般不使用,一般只使用于底层逻辑,大部分在面试时会问)

1、call

(1)语法

函数.call(新的this,形参1,形参2,...);

(2)举例:

let obj = { age : 20 };
function fn(x,y) {
  console.log(this);
  console.log(x + y);
};
fn();  // 正常调用函数,函数中的this指向window
fn.call(obj,3,4);  // 将this指向为obj,即{age: 20}  7

(3)总结:

  1. 函数.call()表示调用函数,原函数fn得以调用;
  2. 修改了原函数中的this,改成call方法的第一个参数;
  3. 如果原函数有形参,可以通过call方法为原函数传递实参;

2、apply:

与call方法用法几乎一致,只是形参部分略有不同

(1)语法:

函数.apply(新的this,[形参1,形参2,...]);

(2)总结:

  1. 函数.apply()表示调用函数,原函数fn得以调用;
  2. 修改了原函数中的this,改成apply方法的第一个参数;
  3. 如果原函数有形参,可以通过apply方法为原函数传递实参,但是必须使用数组格式;

(3)简单运用:

let arr = [1,8,2,4,3,9,4,6,5];
// 在ES6语法出来之前计算数组最大值的写法
console.log(Math.max.apply(null,[1,8,2,4,3,9,4,6,5]));
// 新语法ES6出现之后有了展开运算符,现在计算数组最大值的写法如下
console.log(Math.max(...arr));

3、bind:

(1)语法:

let 新函数 = 函数.bind(新的this,形参1,形参2,...);
// 新函数与原函数内容一致,只不过新函数的this指向为新的this,如果只有这一行则代码无输出

(2)总结:

  1. 函数.bind()表示创建了一个新函数,并且不会调用任何函数;
  2. 修改了新函数中的this,改成bind方法的第一个参数;
  3. 如果原函数有形参,可以通过bind方法为原函数传递实参;