函数调用
JavaScript 函数调用
Section titled “JavaScript 函数调用”JavaScript 函数在定义时不会执行,而是在被调用(或执行)时才执行。函数被调用的方式,除其他因素外,决定了其 this 关键字的值。
调用函数有几种方式,每种方式都对 this 和函数行为产生影响。
this 关键字
Section titled “this 关键字”在 JavaScript 中,this 是一个特殊的关键字,其值由函数被调用的方式(即其执行上下文)决定。它指向当前“拥有”或“正在执行”该代码的对象。
this 的值不是静态的;它是动态的,取决于调用上下文。
this 是一个关键字,而不是变量。它的值不能直接赋值。 |
|---|
调用 JavaScript 函数的方式
Section titled “调用 JavaScript 函数的方式”函数内部的代码只在函数被调用时执行。让我们探索主要的调用模式:
1. 作为函数调用(直接调用)
Section titled “1. 作为函数调用(直接调用)”这是最直接的函数调用方式。
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 指向全局对象通常不被推荐,因为它可能导致难以调试的问题,并降低代码的可移植性。
2. 作为方法调用(方法调用)
Section titled “2. 作为方法调用(方法调用)”当一个函数是一个对象的属性,并使用该对象来调用时,它就是方法调用。
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: 103. 作为构造函数调用(构造函数调用)
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!!这些方法对于控制函数(尤其是在回调函数和事件处理程序中)的执行上下文非常强大。
箭头函数与 this
Section titled “箭头函数与 this”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 调用)。
this 行为总结:
Section titled “this 行为总结:”- 直接调用:
window/global(非严格模式),undefined(严格模式)。 - 方法调用: 拥有该方法的对象。
- 构造函数调用: 新创建的实例。
call()/apply()/bind(): 显式提供的thisArg。- 箭头函数: 词法继承自包围它的作用域。
理解这些调用模式及其对 this 的影响是掌握 JavaScript 的基石。