复习this指向

33 阅读4分钟

重新整理this指向

好久没有复习this的问题,最近发现又忘记了,需要好好整理一下!

标准函数与箭头函数的不同this行为

this引用的是把函数当成方法调用的上下文对象,指向哪个对象或者这个对象的值是什么取决于使用的方式与环境。在网页的全局上下文中调用函数时,this指向windows

标准函数的this情况

  1. 直接调用,this指向windows;
  2. 对象调用,this指向把函数当成方法调用的对象本身;

箭头函数的this情况

在箭头函数中,this引用的是定义箭头函数的上下文

  • 创建箭头函数时,就已经确定了this指向,不会再改变!!!;
  • 箭头函数内的this指向外层的this

梳理

1.全局普通函数

注意区分严格模式or非严格模式

 let a = 0; // 相当于window.a = 0
 function testWindow() {
        this.a = 1; //window.a = 1 
        console.log(this.a); //this指向window,1
        console.log(window.a); //1
        console.log(this); //window
 }
 testWindow();

2.对象的函数方法

this指向把函数当成方法去调用的对象

let a=2
let obj = {
    a:1,
    b:function(){
        console.log(this)
        console.log(this.a)
    }
}
obj.b() //this指向obj
let foo = obj.b
foo() //普通调用,this指向window

3.构造函数,即new

function Test(a) {
    this.a = a;
    console.log(this.a); 
}

Test.prototype.say = function () {
    console.log(this); 
    console.log(this.a); 
};

var t = new Test(1);//this指向t
console.log(t); //{a:1}

t.say();//this指向t

4.箭头函数

箭头函数的this看外层是否有函数,如果有函数,外层函数的this即是内部箭头函数的this;如果没有,this便是window 箭头函数的 this 是在创建它时外层 this 的指向。这里的重点有两个:

  1. 创建箭头函数时,就已经确定了它的 this 指向。
  2. 箭头函数内的 this 指向外层的 this
  3. 所以要知道箭头函数的 this 就得先知道外层 this 的指向,需要继续在外层应用七步口诀。
obj = {
  func() {
    const arrowFunc = () => {
      console.log(this._name)
    }

    return arrowFunc
  },

  _name: "obj",
}

obj.func()()//箭头函数外部有函数,则箭头函数的this为外层函数的this;外层函数的this为obj(对象调用)

func = obj.func
func()()//箭头函数外部有函数,则箭头函数的this为外层函数的this,外层函数直接调用,this为window

5.箭头函数与new

function Person(name, age) {
  this.name = name;
  this.age = age;
  this.test1 = function () {
    const arrowFunc = () => {
      console.log(this.name);
      console.log(this.age);
    };
    arrowFunc();
  };
  this.test2 = () => {
    console.log(this.name);
    console.log(this.age);
  };
}

let per1 = new Person("test1", 23);
console.log(per1.test1);
per1.test1(); //test里的this指向per1,箭头函数外部有函数test,因此箭头函数的this为test的this,即为per1.因此输出为test1,23
per1.test2(); //test2箭头函数外部有函数为Person,this指向per1,因此结果同上
let test3 = per1.test1;
test3(); //test3为普通调用,arrowFunc里的this为为test3的this即为window,因此为undefined

let test4 = per1.test2; //箭头函数的this,定义了之后就不会改变
test4(); //
let test5 = () => {
  console.log(this.name);
  console.log(this.age);
};
test5(); //undefined

注意test4与test5的区别

6.call、bind、apply

bind()是指Function.prototype.bind():[Function] 实例的 bind()  方法创建一个新函数,当调用该新函数时,它会调用原始函数并将其 this 关键字设置为给定的值,同时,还可以传入一系列指定的参数,这些参数会插入到调用新函数时传入的参数的前面。

  • 多次bind时只认第一次bind值;
  • 箭头函数中的this不会被改变

apply() 和 call() 的第一个参数都是 this,区别在于通过 apply 调用时实参是放到数组中的,而通过 call 调用时实参是逗号分隔的。 bind的优先级最高,即经过bind绑定新的对象后,通过call与apply都无法再进行改变

function func() {
  console.log(this)
}
boundFunc = func.bind(1)
boundFunc.apply(2) // 1,口诀 3 优先

总结

  1. 箭头函数优先级最高;
  2. new
  3. 隐式绑定:bind>call===apply
  4. 对象调用
  5. 直接调用
obj = {
  func() {
    const arrowFunc = () => {
      console.log(this._name)
    }

    return arrowFunc
  },

  _name: "obj",
}

obj.func()()

func = obj.func
func()()

obj.func.bind({ _name: "newObj" })()()

obj.func.bind()()()

obj.func.bind({ _name: "bindObj" }).apply({ _name: "applyObj" })()
  1. obj.func()返回箭头函数,箭头函数的this与外部函数的this一致,this指向obj,因此运行obj.func()()结果为obj._name:'obj';
  2. 箭头函数外部有函数func,this指向window,输出undefined
  3. obj.func()中的this指向新的对象,箭头函数的this与外部函数this一致,为新bind的对象,即为“newObj”;
  4. bind参数为null,即为window,
  5. bind后的对象不能进行修改,因此结果为bindObj