函数调用方式

JavaScript 中调用函数的几种方式及 this 指向

问题

JavaScript 中,调用函数有哪几种方式?

解答

JavaScript 中有 4 种主要的函数调用方式,每种方式的 this 指向不同。

1. 普通函数调用

function greet(name) {
  console.log(`Hello, ${name}!`);
  console.log('this:', this);
}

// 直接调用
greet('Alice');
// 非严格模式:this 指向 window(浏览器)或 global(Node.js)
// 严格模式:this 为 undefined

2. 方法调用

const person = {
  name: 'Bob',
  sayHi() {
    console.log(`Hi, I'm ${this.name}`);
  }
};

// 作为对象方法调用
person.sayHi(); // Hi, I'm Bob
// this 指向调用该方法的对象

// 注意:方法赋值给变量后调用
const fn = person.sayHi;
fn(); // this 不再指向 person

3. 构造函数调用

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

// 使用 new 调用
const alice = new Person('Alice');
alice.greet(); // Hello, Alice
// this 指向新创建的实例对象

4. call / apply / bind 调用

function introduce(age, city) {
  console.log(`I'm ${this.name}, ${age} years old, from ${city}`);
}

const user = { name: 'Tom' };

// call:参数逐个传递
introduce.call(user, 25, 'Beijing');
// I'm Tom, 25 years old, from Beijing

// apply:参数以数组传递
introduce.apply(user, [25, 'Beijing']);
// I'm Tom, 25 years old, from Beijing

// bind:返回绑定 this 的新函数
const boundFn = introduce.bind(user, 25);
boundFn('Shanghai');
// I'm Tom, 25 years old, from Shanghai

补充:箭头函数

const obj = {
  name: 'Arrow',
  // 箭头函数没有自己的 this
  // 继承定义时外层作用域的 this
  sayName: () => {
    console.log(this.name); // undefined(this 指向外层)
  },
  sayNameNormal() {
    const inner = () => {
      console.log(this.name); // Arrow
    };
    inner();
  }
};

obj.sayName();
obj.sayNameNormal();

关键点

  • 普通调用this 指向全局对象(严格模式为 undefined
  • 方法调用this 指向调用方法的对象
  • 构造函数调用this 指向新创建的实例
  • call/apply/bindthis 指向指定的对象
  • 箭头函数:没有自己的 this,继承外层作用域