三、函数:代码的“乐高积木”
3.1 函数基础
函数是将一段代码封装起来,给它一个名字,然后在需要时调用它。
函数定义与调用
// JavaScript 函数定义
function greet(name) {
// 参数 name
let message = "你好," + name + "!";
return message; // 返回值
}
// 调用函数
let result = greet("张三");
console.log(result); // "你好,张三!"
# Python 函数定义
def greet(name):
"""这是一个简单的问候函数""" # 文档字符串
message = f"你好,{name}!"
return message
# 调用
result = greet("张三")
print(result)
// Java 函数定义(方法)
public static String greet(String name) {
String message = "你好," + name + "!";
return message;
}
// 调用
String result = greet("张三");
System.out.println(result);
3.2 参数传递的奥秘
值传递 vs 引用传递
// 基本类型(值传递)—— 传递的是值的副本
function modifyNumber(x) {
x = x + 10;
console.log("函数内部:", x); // 15
}
let a = 5;
modifyNumber(a);
console.log("函数外部:", a); // 5(未被修改!)
// 对象类型(引用传递)—— 传递的是引用
function modifyObject(obj) {
obj.age = 30; // 修改对象的属性
console.log("函数内部:", obj.age); // 30
}
let person = { name: "张三", age: 25 };
modifyObject(person);
console.log("函数外部:", person.age); // 30(被修改了!)
重要理解:
数字、字符串、布尔值→传递的是副本,原变量不变
数组、对象→传递的是引用,函数内部修改会影响外部
3.3 函数作用域
作用域决定了变量在哪里可以被访问。
// 全局作用域
let globalVar = "我在任何地方都能被访问";
function testScope() {
// 函数作用域
let localVar = "我只能在函数内部被访问";
console.log(globalVar); // ✅ 可以访问
console.log(localVar); // ✅ 可以访问
}
console.log(globalVar); // ✅ 可以访问
// console.log(localVar); // ❌ 报错:localVar 未定义
# Python 的作用域(LEGB 规则)
x = "全局变量"
def outer():
y = "外部函数变量"
def inner():
z = "内部函数变量"
print(x) # 查找:内部 → 外部 → 全局
print(y)
print(z)
inner()
# print(z) # ❌ 无法访问内部函数变量
outer()
LEGB 查找顺序:
Local:当前函数内部
Enclosing:外层函数
Global:模块全局
Built-in:Python 内置
3.4 高级函数特性
默认参数值
# Python
def greet(name, greeting="你好"):
return f"{greeting},{name}!"
print(greet("张三")) # "你好,张三!"
print(greet("张三", "嗨")) # "嗨,张三!"
// JavaScript
function greet(name, greeting = "你好") {
return `${greeting},${name}!`;
}
⚠️ 陷阱:不要使用可变对象作为默认参数
# ❌ 错误示例
def add_item(item, list=[]): # 默认列表会在函数定义时创建
list.append(item)
return list
print(add_item("a")) # ["a"]
print(add_item("b")) # ["a", "b"] ❌ 意外地累积了
# ✅ 正确做法
def add_item(item, list=None):
if list is None:
list = []
list.append(item)
return list
print(add_item("a")) # ["a"]
print(add_item("b")) # ["b"]
可变参数(args 和 *kwargs)
# *args:接收任意多个位置参数(打包为元组)
def sum_all(*numbers):
total = 0
for num in numbers:
total += num
return total
print(sum_all(1, 2, 3, 4, 5)) # 15
# **kwargs:接收任意多个关键字参数(打包为字典)
def print_info(**info):
for key, value in info.items():
print(f"{key}: {value}")
print_info(name="张三", age=25, city="北京")
// JavaScript 的剩余参数(类似 *args)
function sumAll(...numbers) {
return numbers.reduce((total, num) => total + num, 0);
}
// 收集剩余参数
function introduce(name, ...hobbies) {
console.log(`${name} 喜欢:${hobbies.join("、")}`);
}
箭头函数(JavaScript)
// 传统函数
function add(a, b) {
return a + b;
}
// 箭头函数(简洁写法)
const add = (a, b) => a + b;
// 只有一个参数可省略括号
const double = x => x * 2;
// 无参数需要空括号
const greet = () => "你好";
// 返回对象需要括号包裹
const createUser = name => ({ name: name, createdAt: new Date() });
箭头函数 vs 普通函数:
箭头函数没有自己的 this(继承外层)
不能用作构造函数(不能 new)
没有 arguments 对象
递归函数
函数调用自身,适用于树形结构、分治算法等场景。
# 经典案例:计算阶乘 n! = n * (n-1) * ... * 1
def factorial(n):
# 基线条件:必须有一个终止条件
if n <= 1:
return 1
# 递归条件:函数调用自身
return n * factorial(n - 1)
print(factorial(5)) # 120
# 执行过程:
# factorial(5) = 5 * factorial(4)
# = 5 * (4 * factorial(3))
# = 5 * (4 * (3 * factorial(2)))
# = 5 * (4 * (3 * (2 * factorial(1))))
# = 5 * (4 * (3 * (2 * 1)))
# = 120
递归 vs 循环:
来源:
https://ltglu.cn/