返回

揭开JavaScript中this指向的神秘面纱

前端

JavaScript中的this指向

this是指向当前对象的指针,它允许函数内部引用上下文中的执行变量。在JavaScript中,this的指向根据函数的调用方式而定。

函数调用

当一个函数作为普通函数调用时,this指向全局对象(在严格模式下为undefined)。

function greet() {
  console.log(this);
}

greet(); // 输出:window

方法调用

当一个函数作为对象的方法调用时,this指向该对象。

const person = {
  name: 'John',
  greet: function() {
    console.log(this);
  }
};

person.greet(); // 输出:{ name: 'John', greet: [Function: greet] }

构造函数调用

当一个函数作为构造函数调用时,this指向新创建的对象。

function Person(name) {
  this.name = name;
}

const john = new Person('John');

console.log(john); // 输出:{ name: 'John' }

箭头函数调用

箭头函数没有自己的this指向,它总是继承父级作用域的this指向。

const person = {
  name: 'John',
  greet: () => {
    console.log(this);
  }
};

person.greet(); // 输出:{ name: 'John', greet: [Function: greet] }

this指向的绑定

this指向的绑定是指在函数调用时确定this指向的过程。JavaScript提供了四种this指向的绑定方式:

  • 默认绑定: 当一个函数作为普通函数调用时,this指向全局对象(在严格模式下为undefined)。
  • 隐式绑定: 当一个函数作为对象的方法调用时,this指向该对象。
  • 显式绑定: 使用call、apply或bind方法可以显式指定this指向。
  • 箭头函数绑定: 箭头函数没有自己的this指向,它总是继承父级作用域的this指向。

作用域链

作用域链是指在函数调用时用来查找变量的顺序。当一个函数被调用时,它会创建一个执行环境,该执行环境包含该函数的变量和参数。如果执行环境中没有某个变量,则会沿着作用域链向上查找,直到找到该变量或者到达全局对象。

function outer() {
  const a = 1;

  function inner() {
    const b = 2;

    console.log(a); // 输出:1
    console.log(b); // 输出:2
  }

  inner();
}

outer();

在这个例子中,inner函数的作用域链包含inner函数的执行环境和outer函数的执行环境。当inner函数调用console.log(a)时,它会在inner函数的执行环境中查找a变量,但没有找到。然后,它会沿着作用域链向上查找,在outer函数的执行环境中找到了a变量,并将其输出。

箭头函数

箭头函数没有自己的this指向,它总是继承父级作用域的this指向。这意味着箭头函数不能改变this指向,也不受显式绑定的影响。

const person = {
  name: 'John',
  greet: () => {
    console.log(this);
  }
};

person.greet(); // 输出:window

在这个例子中,greet方法是一个箭头函数,因此它没有自己的this指向。它继承了父级作用域的this指向,也就是全局对象window。

构造函数

构造函数是一个用来创建对象的函数。当一个构造函数被调用时,它会创建一个新的对象,并将this指向该对象。

function Person(name) {
  this.name = name;
}

const john = new Person('John');

console.log(john); // 输出:{ name: 'John' }

在这个例子中,Person是一个构造函数,它接收一个name参数并将其赋值给this.name属性。当new Person('John')被调用时,它会创建一个新的对象,并将this指向该对象。然后,this.name属性被赋值为'John'。

原型链

原型链是指从一个对象到其父对象的链接。每个对象都有一个原型对象,该原型对象也是一个对象,并有自己的原型对象,依此类推。当一个对象没有某个属性或方法时,它会沿着原型链向上查找,直到找到该属性或方法或者到达原型链的顶端。

function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name}`);
};

const john = new Person('John');

john.greet(); // 输出:Hello, my name is John

在这个例子中,Person是一个构造函数,它创建了一个新的对象john。john对象有一个name属性,但它没有greet方法。当john.greet()被调用时,它会沿着原型链向上查找greet方法,并在Person.prototype对象中找到了它。然后,greet方法被调用,并输出Hello, my name is John。