一、为什么需要函数?先搞懂核心作用
想象你在厨房做饭:每次炒青菜都要重复 "洗菜→切菜→热油→下锅→调味" 这 5 步。如果写代码时重复的逻辑也手动敲三遍,不仅累还容易出错 ------ 这就是函数存在的意义:把重复代码打包成 "万能菜谱",随时调用。
比如计算圆的面积,每次用都要写一遍公式,用函数封装后:
javascript
function calculateArea(radius) {
return 3.14 * radius * radius; // 封装核心逻辑
}
console.log(calculateArea(5)); // 调用时直接传参数,像查菜谱一样方便
二、新手必学的 4 种函数定义方式(附对比表格)
2.1 最 "直白" 的函数声明:function 关键字
语法长这样:
php
function 函数名(参数1, 参数2) {
// 函数体:写具体要做的事
return 结果; // 可选,有返回值时写
}
举个生活例子:像 "说明书式" 的菜谱,先写好步骤再用。
javascript
// 定义:教电脑怎么打招呼
function sayHello(name) {
return `你好,${name}!`;
}
// 调用:直接喊函数名
console.log(sayHello("小明")); // 输出:你好,小明!
什么时候用?
- ✅ 适合提前定义好,后面反复调用的场景(比如工具函数)
- ❌ 不适合写在条件语句里(会有 "变量提升" 陷阱,后面会讲)
2.2 更灵活的函数表达式:赋值给变量
语法长这样:
javascript
const 变量名 = function(参数1, 参数2) {
// 函数体
};
举个生活例子:像 "便签式" 菜谱,随时写在小纸条上用。
javascript
// 定义:把函数当作"值"存到变量里
const add = function(a, b) {
return a + b;
};
// 调用:通过变量名调用
console.log(add(2, 3)); // 输出:5
隐藏技能:
- 可以匿名(不用给函数起名),适合临时用一次的逻辑
- 能放在对象里当 "方法":
javascript
const calculator = {
sum: function(a, b) { // sum是对象的方法
return a + b;
}
};
console.log(calculator.sum(10, 20)); // 输出:30
2.3 极简箭头函数:ES6 语法糖
语法长这样:
javascript
const 变量名 = (参数1, 参数2) => {
// 函数体
return 结果;
};
简化规则:
情况 | 正常写法 | 箭头简化写法 |
---|---|---|
无参数 | () => {} | 直接() => {} |
单参数 | (a) => {} | 可省略括号 a => {} |
单语句且有返回值 | (a,b) => { return a+b; } | 直接(a,b) => a+b |
举个例子:
dart
// 计算数组每个数的平方
const numbers = [1, 2, 3];
const squares = numbers.map(function(num) { // 传统函数表达式
return num * num;
});
// 用箭头函数简化后:
const squares = numbers.map(num => num * num); // 一行搞定!
注意陷阱:
- ❌ 没有自己的this(会继承外层作用域的this,适合处理数组时用)
- ❌ 不能用作构造函数(不能用new关键字创建对象)
2.4 进阶玩法:构造函数(用 new 创建对象)
语法长这样:
javascript
function 构造函数名(参数1, 参数2) {
this.属性名 = 参数1; // 定义对象属性
this.方法名 = function() { ... }; // 定义对象方法
}
举个例子:像 "模板工厂",批量生产同类对象。
javascript
// 定义"人类"模板
function Person(name, age) {
this.name = name;
this.age = age;
this.sayHi = function() {
console.log(`我是${this.name},今年${this.age}岁`);
};
}
// 生产具体对象
const tom = new Person("Tom", 20);
const lisa = new Person("Lisa", 18);
tom.sayHi(); // 输出:我是Tom,今年20岁
关键区别:
- ✅ 函数名首字母大写(约定俗成,方便区分)
- ✅ 必须用new调用(否则this会指向全局对象,导致 bug)
三、终极对比表:到底该选哪一种?
定义方式 | 语法复杂度 | 能否复用 | this 指向 | 适用场景 | 经典错误提醒 |
---|---|---|---|---|---|
函数声明 | ★☆☆☆☆ | ✅ 高 | 调用时决定(默认全局) | 全局工具函数 | 别在 if 里定义!会变量提升 |
函数表达式 | ★★☆☆☆ | ✅ 中 | 取决于所在对象 | 对象方法、回调函数 | 别忘了分号结尾! |
箭头函数 | ★★★☆☆ | ✅ 中 | 继承外层作用域 | 数组遍历、简单逻辑 | 别用在需要自己 this 的地方! |
构造函数 | ★★★★☆ | ✅ 高 | 新创建的对象 | 批量生成对象 | 一定要用 new! |
四、新手常见误区 + 避坑指南
4.1 变量提升是什么鬼?
现象:函数声明可以在定义前调用,而函数表达式不行:
scss
// 函数声明:可以"先调用后定义"
sayHi(); // 输出:你好!
function sayHi() { console.log("你好!"); }
// 函数表达式:先调用会报错
sayHello(); // 报错:sayHello is not a function
const sayHello = function() { console.log("哈喽!"); };
原理:函数声明会被 JavaScript 引擎 "提前读取",而函数表达式是赋值操作,必须先赋值再用。
4.2 箭头函数的 this 为什么总出错?
看下面这个例子:
javascript
const obj = {
name: "小明",
// 错误示范:用箭头函数定义方法
sayName: () => {
console.log(this.name); // 输出:undefined(因为箭头函数的this是外层全局作用域)
}
};
obj.sayName();
// 正确示范:用传统函数表达式
const obj = {
name: "小明",
sayName: function() {
console.log(this.name); // 输出:小明(this指向obj对象)
}
};
obj.sayName();
记住:箭头函数没有自己的this,它的this是定义时所在的作用域(通常是外层函数或全局),而不是调用时的对象。
五、实战练习:用 4 种方式实现同一功能
需求:写一个函数,接收两个数,返回它们的乘积。
5.1 函数声明版
javascript
function multiply(a, b) {
return a * b;
}
console.log(multiply(3, 4)); // 12
5.2 函数表达式版
javascript
const multiply = function(a, b) {
return a * b;
};
console.log(multiply(3, 4)); // 12
5.3 箭头函数版
css
const multiply = (a, b) => a * b;
console.log(multiply(3, 4)); // 12
5.4 构造函数版(虽然不太适合,但演示用)
javascript
function Calculator() {
this.multiply = function(a, b) {
return a * b;
};
}
const calc = new Calculator();
console.log(calc.multiply(3, 4)); // 12
六、总结:一张图记住所有知识点

最后送你一句口诀:
简单逻辑用箭头,对象方法表达式;
重复调用声明式,批量对象构造器。
遇到 this 别慌神,箭头继承外层去,
传统函数看调用,谁调 this 就指谁!
下次遇到函数定义题,按照 "需求→场景→选类型" 三步法,轻松搞定~ 如果你在练习中遇到具体问题,欢迎留言讨论!