this

this详解

一、为什么要有this

原因1:不用每次都传上下文(context)

有this的情况:

function uppercaseName() {
    return this.name.toUpperCase();
}

function sayHi() {
    console.log(`Hello, I am ${uppercaseName.call(this)}, and ${this.age} years old.`);
}

let Tom = {
    name: 'tom',
    age: 8
};

let Jerry = {
    name: 'jerry',
    age: 9
};

sayHi.call(Tom);
sayHi.call(Jerry);

没有this的情况:

function uppercaseName(that) {
    return that.name.toUpperCase();
}

function sayHi(that) {
    console.log(`Hello, I am ${uppercaseName(that)}, and ${that.age} years old.`);
}

let Tom = {
    name: 'tom',
    age: 8
};

let Jerry = {
    name: 'jerry',
    age: 9
};

sayHi(Tom);
sayHi(Jerry);

原因2:没有this,class无法实现

class Person {
    constructor(name, age){
        this.name = name;
        this.age = age;
    }

    uppercaseName() {
        return this.name.toUpperCase();
    }

    sayHi() {
        console.log(`Hello, I am ${this.uppercaseName()}, and ${this.age} years old.`);
    }
}

如果没有this,没办法将属性挂载到实例上,属性函数内部也无法相互调用

二、this指向谁

this一般出现在函数中,this的指向取决于函数执行场景,一般分为4个场景:

1、默认:this -> 全局变量(非严格模式)/上下文

var name = 'Tom';

function sayName() {
    console.log(`Hi, I am ${this.name}!`);
}

//this隐式指向全局
sayName(); //严格模式指向undefined,非严格模式下正常

输出:

浏览器:

Hi, I am Tom!

node.js:

TypeError: Cannot read properties of undefined (reading 'name')

全局中this的指向:

  • 浏览器:this -> window

  • node.js:this -> undefined

2、隐式:this -> 调用对象

let Tom = {
  name: "Tom",
  sayName: function () {
    console.log(`Hi, I am ${this.name}!`);
  },
};

Tom.sayName();

function sayHi() {
  console.log(`Hi, I am ${this.name}!`);
}
let Jerry = {
  name: "Jerry",
  sayName: Tom.sayName,
  sayHi: sayHi,
};

Jerry.sayName(); //this隐式指向Jerry
Jerry.sayHi();

输出:

Hi, I am Tom!

Hi, I am Jerry!

Hi, I am Jerry!

3、显式:this -> 指定对象

let Tom = {
  name: "Tom",
  sayName: function () {
    console.log(`Hi, I am ${this.name}!`);
  },
  sayTitle(...titles) {
    this.sayName();
    console.log(`my title: ${[...titles].join("、")}`);
  },
};

Tom.sayName();
Tom.sayTitle("developer");

let Jerry = {
  name: "Jerry",
  sayName: function () {
    console.log(`Hi, I am ${this.name}!`);
  },
};
let Jack = {
  name: "Jack",
};

//this显式指向Jery
Tom.sayTitle.apply(Jerry, ["developer", "programmer", "engineer"]);
Tom.sayTitle.apply(Jack, ["developer", "programmer", "engineer"]);

输出:

Hi, I am Tom!

Hi, I am Tom!

my title: developer

Hi, I am Jerry!

my title: developer、programmer、engineer

TypeError: this.sayName is not a function

4、new:this -> 新对象

new实例化时经典4步中的第3步

function Person(name) {
    this.name = name;
    this.sayName = function () {
        console.log(`Hi, I am ${this.name}!`);
    }
}

//this显式指向Person的实例
let Tom = new Person('Tom');
Tom.sayName();

let Jerry = new Person('Jerry');
Jerry.sayName();

三、破解this的困局

函数的调用方式决定了 this 的值(运行时绑定),this 不能在执行期间被赋值,并且在每次函数被调用时 this 的值也可能会不同:

  • ES5 引入了 bind 方法来设置函数的 this 值,而不用考虑函数如何被调用的。

  • ES6 引入了箭头函数,箭头函数不提供自身的 this 绑定(this 的值将保持为闭合词法上下文的值)。

参考:

Last updated