Skip to content

函数调用

JavaScript 函数在定义时不会执行,而是在被调用(或执行)时才执行。函数被调用的方式,除其他因素外,决定了其 this 关键字的值。

调用函数有几种方式,每种方式都对 this 和函数行为产生影响。

在 JavaScript 中,this 是一个特殊的关键字,其值由函数被调用的方式(即其执行上下文)决定。它指向当前“拥有”或“正在执行”该代码的对象。

this 的值不是静态的;它是动态的,取决于调用上下文。

this 是一个关键字,而不是变量。它的值不能直接赋值。

函数内部的代码只在函数被调用时执行。让我们探索主要的调用模式:

这是最直接的函数调用方式。

function multiply(a, b) {
return a * b;
}
const result = multiply(10, 2); // result is 20

直接调用中的 this:

  • 非严格模式 (Non-Strict Mode): 如果函数在非严格模式下直接调用(不是作为方法、构造函数或通过 apply/call/bind),this 默认指向全局对象。在浏览器中是 window 对象,在 Node.js 中是 global 对象。
  • 严格模式 (Strict Mode): 在严格模式 ("use strict";) 下,如果函数直接调用,this 将是 undefined。这有助于防止意外修改全局对象。
function showThis() {
console.log(this);
}
showThis(); // In non-strict browser: Window object. In strict mode: undefined.

现代 JavaScript (ES Modules、类) 通常默认运行在严格模式下。依赖 this 指向全局对象通常不被推荐,因为它可能导致难以调试的问题,并降低代码的可移植性。

当一个函数是一个对象的属性,并使用该对象来调用时,它就是方法调用。

const myObject = {
firstName: "John",
lastName: "Doe",
fullName: function() { // Or using ES6 shorthand: fullName() {
return `${this.firstName} ${this.lastName}`;
}
};
const name = myObject.fullName(); // name is "John Doe"

方法调用中的 this:

在这种情况下,this 会被设置为拥有该方法的对象(用于调用该方法的对象)。在上面的例子中,fullName 内部的 this 指向 myObject。

const testObject = {
value: 10,
getValue: function() {
return this.value; // 'this' is testObject
}
};
console.log(testObject.getValue()); // Output: 10

3. 作为构造函数调用(构造函数调用)

Section titled “3. 作为构造函数调用(构造函数调用)”

如果函数使用 new 关键字调用,它就是构造函数调用。这用于创建新的对象。

function Person(firstName, lastName) {
// 'this' refers to the new object being created
// 'this' 指向新创建的对象
this.firstName = firstName;
this.lastName = lastName;
}
const person1 = new Person("Alice", "Wonderland");
// person1 is now { firstName: "Alice", lastName: "Wonderland" }
// person1 现在是 { firstName: "Alice", lastName: "Wonderland" }
console.log(person1.firstName); // Output: Alice

构造函数调用中的 this:

  • 会创建一个新的空对象。
  • 这个新对象会被设置为函数调用的 this 绑定。
  • 新对象会继承构造函数的 prototype 上的属性和方法。
  • 如果函数没有显式返回一个对象,则新对象(即 this)会被自动返回。

4. 使用 call()、apply() 或 bind() 调用函数(间接调用)

Section titled “4. 使用 call()、apply() 或 bind() 调用函数(间接调用)”

JavaScript 函数是对象,它们拥有内置方法:call()、apply() 和 bind()。这些方法允许你调用函数并显式设置 this 的值,无论函数在哪里定义。

call(thisArg, arg1, arg2, ...):

使用指定的 this 值和单独提供的参数来调用函数。

function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const person = { name: "Bob" };
greet.call(person, "Hello", "!"); // Output: Hello, Bob!

apply(thisArg, [argsArray]):

与 call() 类似,但参数以数组(或类数组对象)的形式提供。

greet.apply(person, ["Hi", "..."]); // Output: Hi, Bob...

bind(thisArg, arg1, arg2, ...):

bind() 创建一个新函数,当调用这个新函数时,其 this 关键字被设置为 thisArg,并且可以选择性地预设一系列参数,放在新函数被调用时提供的参数之前。

const greetBob = greet.bind(person, "Hey there");
greetBob("."); // Output: Hey there, Bob.
const greetBobLater = greet.bind(person);
greetBobLater("Good day", "!!"); // Output: Good day, Bob!!

这些方法对于控制函数(尤其是在回调函数和事件处理程序中)的执行上下文非常强大。

ES6 箭头函数 (=>) 在处理 this 方面表现不同。箭头函数没有自己的 this 绑定。相反,它在定义时通过词法方式继承其周围(包围)作用域的 this。

const myObj = {
value: 100,
regularMethod: function() {
console.log("Regular method 'this':", this.value); // 'this' is myObj
// 常规方法中的 'this':即 myObj
setTimeout(function() {
// In this traditional callback, 'this' is window/undefined (in strict mode)
// 在这个传统回调函数中,'this' 是 window/undefined (在严格模式下)
console.log("setTimeout (regular fn) 'this':", this.value); // undefined or error
// setTimeout (常规函数) 中的 'this':undefined 或报错
}, 100);
setTimeout(() => {
// In this arrow function, 'this' is lexically inherited from regularMethod
// 在这个箭头函数中,'this' 是从 regularMethod 词法继承而来
console.log("setTimeout (arrow fn) 'this':", this.value); // 100
// setTimeout (箭头函数) 中的 'this':100
}, 200);
},
arrowMethod: () => {
// 'this' is inherited from the scope where myObj was defined
// 'this' 继承自 myObj 被定义的那个作用域
// NOT myObj itself. Typically window/global or undefined in module scope.
// 而不是 myObj 本身。通常是 window/global 或在模块作用域中是 undefined。
console.log("Arrow method 'this':", this.value); // Likely undefined or error
// 箭头方法中的 'this':很可能是 undefined 或报错
}
};
myObj.regularMethod();
// myObj.arrowMethod(); // Would show 'this' as not myObj
// myObj.arrowMethod(); // 将显示 'this' 不是 myObj

这种词法 this 的行为使得箭头函数特别适合用作回调函数和方法,在这些场景下你需要保留外部函数作用域中的 this 值。

然而,箭头函数通常不适用于需要通过 this 引用对象实例的方法,也不适用于构造函数(它们不能用 new 调用)。

  • 直接调用: window/global(非严格模式),undefined(严格模式)。
  • 方法调用: 拥有该方法的对象。
  • 构造函数调用: 新创建的实例。
  • call()/apply()/bind(): 显式提供的 thisArg。
  • 箭头函数: 词法继承自包围它的作用域。

理解这些调用模式及其对 this 的影响是掌握 JavaScript 的基石。