在 JavaScript 的世界里,函数不仅是代码的执行单元,更是构建复杂应用的核心积木。正如你的笔记所言:“函数包含一组语句,它们是 JavaScript 的基础模块单元,用于代码复用、信息隐藏和组合调用。” 本文将系统梳理 JavaScript 函数的核心特性——从其对象本质、四种调用模式,到闭包、模块化等高级概念,助你真正掌握这门语言的灵魂。
一、函数即对象:一切皆可赋值
JavaScript 中最颠覆传统编程认知的一点是:函数是头等对象(First-class Object)
function add(a, b) {
return a + b;
}
// 函数可以像普通变量一样被赋值、传递、存储
var myFunc = add;
console.log(myFunc(2, 3)); // 5
// 甚至可以作为对象属性(方法)
var calculator = { operate: add };
✅ 函数对象的特殊性:
- 它拥有普通对象的所有能力(可添加属性、可作为参数传递);
- 唯一区别:它可以通过
()被调用(invoked) ; - 其原型链为:
add → Function.prototype → Object.prototype。
💡 正因函数是对象,我们才能实现回调、高阶函数、闭包等强大模式。
二、函数字面量:声明的四种方式
最常用的是函数字面量(Function Literal) :
// 命名函数(推荐,便于调试)
function greet(name) {
return "Hello, " + name;
}
// 匿名函数(常用于回调)
setTimeout(function() {
console.log("Delayed!");
}, 1000);
此外还有:
- 函数表达式:
const fn = function() {} - 箭头函数(ES6+) :
const fn = () => {}
📌 命名建议:除非作为简短回调,否则优先使用命名函数,提升堆栈可读性。
三、四大调用模式:this 的命运由谁决定?
函数调用时,会自动获得两个“免费”参数:this 和 arguments。而 this 的指向,取决于调用方式。
1. 方法调用模式(Method Invocation)
var obj = {
name: "Alice",
sayHi: function() {
console.log(this.name); // "Alice" —— this 指向 obj
}
};
obj.sayHi();
✅ this 绑定到调用对象,这是面向对象编程的基础。
2. 函数调用模式(Function Invocation)
function sayName() {
console.log(this); // 非严格模式:window;严格模式:undefined
}
sayName(); // 直接调用
⚠️ 危险! 在非严格模式下,this 意外指向全局对象,易引发 bug。
3. 构造器调用模式(Constructor Invocation)
function Person(name) {
this.name = name; // this 指向新创建的实例
}
var p = new Person("Bob");
✅ 使用 new 时:
- 创建新对象;
this绑定到该对象;- 若无显式
return对象,则返回this。
4. Apply/Call 调用模式(Explicit Invocation)
function introduce() {
console.log("I'm " + this.name);
}
var user = { name: "Carol" };
introduce.call(user); // "I'm Carol"
introduce.apply(user); // 同上(参数以数组形式传入)
✅ 显式指定 this,是实现函数借用、绑定上下文的关键。
🌟 现代替代:ES5+ 的
bind()可创建永久绑定this的新函数。
四、参数与返回:灵活但需谨慎
参数:arguments 对象
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
sum(1, 2, 3); // 6
arguments是类数组对象,无map/forEach等方法;- 现代替代:使用 Rest 参数(
...args) 获取真数组:
function sum(...numbers) {
return numbers.reduce((a, b) => a + b, 0);
}
返回值规则
- 无
return→ 返回undefined; - 构造函数中若
return非对象 → 忽略,仍返回this; - 若
return对象 → 返回该对象(覆盖this)。
五、闭包:函数的“记忆”能力
闭包 = 内部函数 + 外部作用域的引用
function counter() {
var count = 0;
return function() {
count++;
return count;
};
}
var c = counter();
console.log(c()); // 1
console.log(c()); // 2 —— count 被“记住”了!
✅ 闭包的价值:
- 数据私有化:
count外部无法直接访问; - 状态保持:函数“记住”了创建时的环境;
- 模块化基础:实现信息隐藏。
六、模块模式:告别全局污染
利用闭包,可构建模块(Module) ——提供接口但隐藏内部状态:
var MyModule = (function() {
var privateVar = "secret";
function privateMethod() {
console.log(privateVar);
}
return {
publicMethod: function() {
privateMethod();
}
};
})();
MyModule.publicMethod(); // "secret"
// MyModule.privateVar → undefined(无法访问)
✅ 优势:
- 避免全局变量冲突;
- 实现封装与解耦;
- 是现代 ES6 模块(
import/export)的思想前身。
七、高级技巧:记忆化、套用与级联
1. 记忆化(Memoization)
缓存计算结果,避免重复运算:
function fibonacci(n, memo = {}) {
if (n in memo) return memo[n];
if (n <= 1) return n;
memo[n] = fibonacci(n - 1, memo) + fibonacci(n - 2, memo);
return memo[n];
}
2. 套用(Currying)
将多参数函数转换为一系列单参数函数:
function add(a) {
return function(b) {
return a + b;
};
}
var add5 = add(5);
add5(3); // 8
3. 级联(Chaining)
方法返回对象自身,支持链式调用:
var obj = {
value: 0,
add: function(x) {
this.value += x;
return this; // 关键:返回 this
},
log: function() {
console.log(this.value);
return this;
}
};
obj.add(2).add(3).log(); // 5
八、异常处理:优雅应对错误
try {
throw new Error("Something went wrong!");
} catch (e) {
console.error(e.message);
} finally {
console.log("Cleanup");
}
throw抛出异常对象(建议用Error实例);catch捕获并处理;finally无论是否出错都会执行。
结语:函数是 JavaScript 的灵魂
从简单的代码复用,到复杂的闭包、模块、高阶函数,JavaScript 的函数机制赋予了开发者极大的表达力。理解其对象本质、this 绑定规则、作用域链与闭包原理,是写出健壮、可维护代码的前提。
正如 Douglas Crockford 所言: “JavaScript 的精华,就在于它的函数。” 掌握函数,你就掌握了这门语言的钥匙。