JS 函数与对象
2025/9/17大约 6 分钟
JavaScript函数与对象
学习目标
- 掌握函数的声明、调用和参数处理
- 理解函数提升和作用域概念
- 熟练使用Math和Date内置对象
- 学会创建和操作自定义对象
函数基础
函数声明与调用
// 函数声明
function greet(name) {
return 'Hello, ' + name + '!';
}
// 函数调用
let message = greet('张三');
console.log(message); // "Hello, 张三!"
// 函数表达式
let add = function(a, b) {
return a + b;
};
let result = add(5, 3);
console.log(result); // 8
函数参数
// 默认参数
function introduce(name, age = 18) {
return `我是${name},今年${age}岁`;
}
console.log(introduce('小明')); // "我是小明,今年18岁"
console.log(introduce('小红', 20)); // "我是小红,今年20岁"
// 可变参数
function sum() {
let total = 0;
for (let i = 0; i < arguments.length; i++) {
total += arguments[i];
}
return total;
}
console.log(sum(1, 2, 3, 4)); // 10
函数返回值
// 有返回值的函数
function multiply(a, b) {
return a * b;
}
// 无返回值的函数(返回undefined)
function sayHello() {
console.log('Hello!');
// 没有return语句,默认返回undefined
}
// 提前返回
function checkAge(age) {
if (age < 18) {
return '未成年';
}
return '成年人';
}
函数提升
// 函数声明会被提升
console.log(sayHi()); // "Hi!" - 可以在声明前调用
function sayHi() {
return 'Hi!';
}
// 函数表达式不会被提升
console.log(sayBye()); // 报错:Cannot access 'sayBye' before initialization
let sayBye = function() {
return 'Bye!';
};
注意
- 函数声明会被完全提升,可以在声明前调用
- 函数表达式只有变量声明被提升,函数体不会提升
Math对象
常用数学方法
// 基本数学运算
console.log(Math.abs(-5)); // 5 绝对值
console.log(Math.ceil(4.3)); // 5 向上取整
console.log(Math.floor(4.7)); // 4 向下取整
console.log(Math.round(4.5)); // 5 四舍五入
// 最大值和最小值
console.log(Math.max(1, 3, 2)); // 3
console.log(Math.min(1, 3, 2)); // 1
// 幂运算和平方根
console.log(Math.pow(2, 3)); // 8 (2的3次方)
console.log(Math.sqrt(16)); // 4 (16的平方根)
// 随机数
console.log(Math.random()); // 0-1之间的随机数
// 生成指定范围的随机整数
function randomInt(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(randomInt(1, 10)); // 1-10之间的随机整数
Math常量
console.log(Math.PI); // 3.141592653589793 圆周率
console.log(Math.E); // 2.718281828459045 自然对数的底数
Date对象
创建日期对象
// 创建当前日期
let now = new Date();
console.log(now);
// 创建指定日期
let birthday = new Date('2000-01-01');
let specificDate = new Date(2023, 11, 25); // 注意:月份从0开始
console.log(birthday);
console.log(specificDate);
获取日期信息
let date = new Date();
console.log(date.getFullYear()); // 年份
console.log(date.getMonth()); // 月份(0-11)
console.log(date.getDate()); // 日期(1-31)
console.log(date.getDay()); // 星期(0-6,0是周日)
console.log(date.getHours()); // 小时(0-23)
console.log(date.getMinutes()); // 分钟(0-59)
console.log(date.getSeconds()); // 秒(0-59)
设置日期信息
let date = new Date();
date.setFullYear(2024);
date.setMonth(5); // 6月(月份从0开始)
date.setDate(15);
date.setHours(14, 30, 0); // 14:30:00
console.log(date);
日期格式化
let date = new Date();
// 转换为字符串
console.log(date.toString()); // 完整日期时间字符串
console.log(date.toDateString()); // 日期部分
console.log(date.toTimeString()); // 时间部分
// 本地化格式
console.log(date.toLocaleDateString()); // 本地日期格式
console.log(date.toLocaleTimeString()); // 本地时间格式
// 自定义格式化函数
function formatDate(date) {
let year = date.getFullYear();
let month = String(date.getMonth() + 1).padStart(2, '0');
let day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
console.log(formatDate(new Date())); // "2023-12-25"
自定义对象
对象创建
// 对象字面量
let person = {
name: '张三',
age: 25,
city: '北京'
};
// 使用构造函数
let car = new Object();
car.brand = '丰田';
car.model = '卡罗拉';
car.year = 2023;
console.log(person);
console.log(car);
访问对象属性
let student = {
name: '李四',
age: 20,
grade: '大二',
'favorite-subject': '数学' // 包含特殊字符的属性名
};
// 点语法
console.log(student.name); // "李四"
console.log(student.age); // 20
// 方括号语法
console.log(student['name']); // "李四"
console.log(student['favorite-subject']); // "数学"
// 动态属性访问
let property = 'grade';
console.log(student[property]); // "大二"
对象方法
let calculator = {
result: 0,
add: function(num) {
this.result += num;
return this; // 返回自身,支持链式调用
},
subtract: function(num) {
this.result -= num;
return this;
},
multiply: function(num) {
this.result *= num;
return this;
},
getResult: function() {
return this.result;
},
reset: function() {
this.result = 0;
return this;
}
};
// 链式调用
let result = calculator.add(10).multiply(2).subtract(5).getResult();
console.log(result); // 15
遍历对象
let book = {
title: 'JavaScript教程',
author: '张三',
pages: 300,
price: 59.9
};
// for...in 循环
for (let key in book) {
console.log(key + ': ' + book[key]);
}
// Object.keys() 方法
let keys = Object.keys(book);
console.log(keys); // ['title', 'author', 'pages', 'price']
// Object.values() 方法
let values = Object.values(book);
console.log(values); // ['JavaScript教程', '张三', 300, 59.9]
// Object.entries() 方法
let entries = Object.entries(book);
console.log(entries); // [['title', 'JavaScript教程'], ...]
对象的复制和合并
let original = {
name: '原始对象',
value: 100
};
// 浅拷贝
let copy1 = Object.assign({}, original);
let copy2 = { ...original }; // ES6展开语法
// 对象合并
let defaults = {
color: 'blue',
size: 'medium'
};
let options = {
color: 'red',
weight: 'light'
};
let merged = Object.assign({}, defaults, options);
console.log(merged); // { color: 'red', size: 'medium', weight: 'light' }
// 使用展开语法合并
let merged2 = { ...defaults, ...options };
console.log(merged2);
实际应用示例
学生成绩管理系统
点击展开示例
let gradeManager = {
students: [],
addStudent: function(name, scores) {
let student = {
name: name,
scores: scores,
average: this.calculateAverage(scores)
};
this.students.push(student);
},
calculateAverage: function(scores) {
let sum = scores.reduce((total, score) => total + score, 0);
return Math.round(sum / scores.length * 100) / 100;
},
getTopStudent: function() {
if (this.students.length === 0) return null;
return this.students.reduce((top, current) => {
return current.average > top.average ? current : top;
});
},
getClassAverage: function() {
if (this.students.length === 0) return 0;
let totalAverage = this.students.reduce((sum, student) => {
return sum + student.average;
}, 0);
return Math.round(totalAverage / this.students.length * 100) / 100;
}
};
// 使用示例
gradeManager.addStudent('张三', [85, 92, 78, 90]);
gradeManager.addStudent('李四', [88, 85, 92, 87]);
gradeManager.addStudent('王五', [76, 82, 79, 85]);
console.log('班级平均分:', gradeManager.getClassAverage());
console.log('最高分学生:', gradeManager.getTopStudent());
最佳实践
函数设计原则
- 单一职责:每个函数只做一件事
- 参数验证:检查参数的有效性
- 返回值一致:同一函数的返回值类型应保持一致
- 避免副作用:尽量不修改全局变量
// 好的函数设计
function calculateTax(income, rate) {
// 参数验证
if (typeof income !== 'number' || typeof rate !== 'number') {
throw new Error('参数必须是数字');
}
if (income < 0 || rate < 0 || rate > 1) {
throw new Error('参数值无效');
}
return income * rate;
}
对象设计原则
- 属性和方法的合理组织
- 使用有意义的属性名
- 适当的封装
- 避免过深的嵌套
// 好的对象设计
let userAccount = {
// 私有属性(约定以_开头)
_balance: 0,
_transactions: [],
// 公共方法
deposit: function(amount) {
if (amount <= 0) {
throw new Error('存款金额必须大于0');
}
this._balance += amount;
this._addTransaction('deposit', amount);
},
withdraw: function(amount) {
if (amount <= 0) {
throw new Error('取款金额必须大于0');
}
if (amount > this._balance) {
throw new Error('余额不足');
}
this._balance -= amount;
this._addTransaction('withdraw', amount);
},
getBalance: function() {
return this._balance;
},
// 私有方法
_addTransaction: function(type, amount) {
this._transactions.push({
type: type,
amount: amount,
date: new Date(),
balance: this._balance
});
}
};
本章小结
通过本章学习,你应该掌握了:
- ✅ 函数的声明、调用和参数处理
- ✅ 函数提升的概念和注意事项
- ✅ Math对象的常用方法和应用
- ✅ Date对象的创建和操作
- ✅ 自定义对象的创建和操作
- ✅ 对象属性的访问和遍历方法
- ✅ 函数和对象的设计最佳实践
这些知识为后续学习DOM操作和面向对象编程打下了坚实基础。
下一步
接下来我们将学习DOM操作和事件处理,这是前端开发中最重要的技能之一。