this 的指向会被分为几种情况。

1. 全局环境下

  1. console.log(this); // window

2. 普通函数中的 this 指向全局

严格模式下指向 undefined。

  1. function fn(){
  2. console.log(this); // window
  3. }
  4. fn();

即使是嵌套的函数, this 也是指向全局对象

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

3. 通过对象调用, this 指向该对象

let obj = {
    name: "zhangsan",
    talk(){
           console.log(this);    // 整个 obj 
    }
}
obj.talk();
 function foo() {
   console.log(this);
 }
foo();    // window
const obj = { name: "zhangsan" };
obj.talk = foo;
obj.talk();    // {name: "zhangsan"}

4. 事件监听器中的 this,指向事件源

btn.onclick = function(){
    console.log(this);        // <input type="button" value="click me">
}

5. 构造函数中的 this,指向 new 出来的实例对象

function Person(name) {
  this.name = name;
  console.log(this);    // {name:"zhangsan"}
}
let obj = new Person("zhangsan");

之前讲到 new 经历的4个步骤中,就提到了“绑定 this 到空对象”身上。

6. 箭头函数的 this

箭头函数的 this 指向取决于当前箭头函数声明的环境(执行上下文)。

执行上下文又分为:全局执行上下文、函数级别上下文、eval 执行上下文。

因为箭头函数没有自己的 arguments 和 this,它内部的this 是由词法作用域上下文确定。(换句话说,箭头函数需要获取函数定义时所在的 EC 的 this,箭头函数定义在哪个作用域中,它的 this 就继承当前作用域 this 的指向。)

1. 定义在全局指向 window

let fn = () = >{console.log(this)}    // window

2. 对象中的箭头函数

var name = "小w";
let obj = {
  name: "zhangsan",
  talk: () => {
    console.log(this.name);    // 指向了 window,所以打印 小w
  }
}
obj.talk();
/*
    {} 不会生成作用域,即箭头函数声明在全局作用域中,this 指向全局
    通过 var 声明的变量会被认作是 window 的属性 即 var a = 5; window.a == a
*/

3. 普通函数中的箭头函数

function foo(){
  let bar = ()=>{
    console.log(this);    // window,箭头函数没有自己的 this,它的 this 使用 foo 的 this
  }
  bar();
}
foo();

修改 this 的指向

三个方法都可以实现修改 this 指向:

  • call()
  • apply()
  • bind()

需要注意的一点是,箭头函数无法修改指向。call、apply 改变 this 指向的同时,立即自动调用函数。 bind 改变 this 指向并返回一个新函数,需要重新显式调用一次函数。

假设当前存在一个普通函数:

function talk() {
  console.log(this);    //普通函数,this 必定指向全局 window
  console.log(this.girlfriend);     // undefined
}
talk();

如果再存在一个对象,让这个对象去调用这个函数,必定就指向该对象:

const obj = {name: "zhangsan"};
obj.talk = talk;
obj.talk();    // zhangsan

但这种写法并不友好,并且存在局限性,所以通常通过另外 3 种方法去修改 this 的指向。这三个方法都是 函数的方法。
语法:

  • fn.call(target)
  • fn.apply(target)
  • fn.bind(target)()

    改变 this 指向

    function foo() {
    console.log(this);
    };
    const obj = {
    name: "zhangsan"
    };
    foo.call(obj);     // zhangsan
    foo.apply(obj);    // zhangsan
    foo.bind(obj)();    // zhangsan
    

    当有参数传入

  • fn.call(target, 20);

  • fn.apply(target, [20]);
  • fn.bind(target)(20);
    function foo(a) {
    console.log(this, a);
    };
    const obj = {
    name: "zhangsan"
    };
    foo.call(obj, 1);
    foo.apply(obj, [2]);
    foo.bind(obj)(3);