Skip to content

1. 对象

1.1 什么是对象

在 JavaScript 中,对象( Object)是一种复合数据类型,用于存储多个相关的数据和功能。

对象就像是现实生活中的"东西",例如:

  • 一部手机: 有品牌、型号、颜色等属性,有打电话、发短信等方法
  • 一个学生: 有姓名、年龄、学号等属性,有学习、考试等方法
  • 一本书: 有书名、作者、出版社等属性,有阅读、借阅等方法

对象的特点:

  • 键值对集合: 对象由一组属性(键)和对应的值组成
  • 无序性: 对象中的属性没有固定顺序
  • 动态性: 可以随时添加、删除、修改属性
  • 引用类型: 对象是引用类型,存储的是内存地址

对象的组成:

javascript
// 一个学生对象示例
const student = {
    // 属性: 存储数据
    name: '张三',
    age: 18,
    gender: '男',
    major: '计算机科学',

    // 方法: 存储函数
    sayHello: function() {
        console.log('大家好,我是' + this.name);
    },

    study: function(subject) {
        console.log(this.name + '正在学习' + subject);
    }
};

对象与基本类型的区别:

类型特点示例
基本类型存储单个值,按值传递let a = 10;
对象类型存储多个值,按引用传递let obj = { name: '张三' };
javascript
// 基本类型 - 按值传递
let num1 = 10;
let num2 = num1;
num2 = 20;
console.log(num1); // 10, num1 不受影响

// 对象类型 - 按引用传递
let obj1 = { name: '张三' };
let obj2 = obj1; // obj2 指向同一个对象
obj2.name = '李四';
console.log(obj1.name); // 李四, obj1 也被修改

1.2 对象的使用

1.2.1 对象的基本语法

创建对象的方式:

javascript
// 方式一: 字面量创建 (推荐)
const person = {
    name: '张三',
    age: 18
};

// 方式二: new Object() 创建
const person2 = new Object();
person2.name = '李四';
person2.age = 20;

// 方式三: 构造函数创建
function Person(name, age) {
    this.name = name;
    this.age = age;
}

const person3 = new Person('王五', 22);

对象字面量语法:

javascript
const obj = {
    // 属性名: 属性值
    name: '张三',
    age: 18,
    isStudent: true,
    hobbies: ['读书', '运动', '编程'],

    // 方法 (函数)
    greet: function() {
        console.log('你好,我是' + this.name);
    },

    // ES6 简写方法
    sayHello() {
        console.log('你好,我是' + this.name);
    }
};

属性名的命名规则:

javascript
const obj = {
    // 标准命名
    name: '张三',
    age: 18,
    _private: '私有属性',

    // 使用特殊字符的属性名需要加引号
    'user-name': 'user001',
    'first name': '张',
    'class': '一班',

    // 数字作为属性名
    1: '第一个值',
    2: '第二个值'
};

// 特殊属性名的访问
console.log(obj['user-name']); // user001
console.log(obj['1']); // 第一个值

1.2.2 对象属性的增删改查

1. 查询属性

javascript
const person = {
    name: '张三',
    age: 18,
    gender: '男',
    score: 90
};

// 方式一: 点表示法 (推荐)
console.log(person.name);   // 张三
console.log(person.age);    // 18

// 方式二: 方括号表示法 (适用于动态属性名)
console.log(person['name']);   // 张三
console.log(person['age']);    // 18

// 动态属性名的使用
const propName = 'gender';
console.log(person[propName]); // 男

// 检查属性是否存在
console.log('name' in person);      // true
console.log('address' in person);   // false

console.log(person.hasOwnProperty('name'));     // true
console.log(person.hasOwnProperty('address'));  // false

2. 添加属性

javascript
const person = {
    name: '张三',
    age: 18
};

// 添加单个属性
person.gender = '男';
person['school'] = '清华大学';

console.log(person);
// { name: '张三', age: 18, gender: '男', school: '清华大学' }

// 动态添加属性
const newProps = {
    hobbies: ['读书', '运动'],
    score: 90,
    isStudent: true
};

Object.assign(person, newProps);
console.log(person);
// { name: '张三', age: 18, gender: '男', school: '清华大学',
//   hobbies: ['读书', '运动'], score: 90, isStudent: true }

3. 修改属性

javascript
const person = {
    name: '张三',
    age: 18,
    score: 80
};

// 修改属性值
person.name = '李四';
person['age'] = 20;
person.score = 95;

console.log(person);
// { name: '李四', age: 20, score: 95 }

// 批量修改属性
Object.assign(person, {
    name: '王五',
    score: 98
});

console.log(person);
// { name: '王五', age: 20, score: 98 }

4. 删除属性

javascript
const person = {
    name: '张三',
    age: 18,
    gender: '男',
    score: 90
};

// 删除属性
delete person.gender;
delete person['score'];

console.log(person);
// { name: '张三', age: 18 }

// 检查删除结果
console.log('gender' in person);  // false
console.log('score' in person);   // false

属性操作的完整示例:

javascript
const student = {
    name: '张三',
    age: 18
};

console.log('初始对象:', student);
// { name: '张三', age: 18 }

// 查询
console.log('姓名:', student.name); // 张三

// 添加
student.gender = '男';
student.major = '计算机科学';
console.log('添加属性后:', student);
// { name: '张三', age: 18, gender: '男', major: '计算机科学' }

// 修改
student.age = 19;
student.major = '软件工程';
console.log('修改属性后:', student);
// { name: '张三', age: 19, gender: '男', major: '软件工程' }

// 删除
delete student.gender;
console.log('删除属性后:', student);
// { name: '张三', age: 19, major: '软件工程' }

1.2.3 对象方法的定义与使用

定义对象方法:

javascript
// 方式一: 传统方式
const person = {
    name: '张三',
    age: 18,

    sayHello: function() {
        console.log('你好,我是' + this.name);
    }
};

// 方式二: ES6 简写方式 (推荐)
const person2 = {
    name: '李四',
    age: 20,

    sayHello() {
        console.log('你好,我是' + this.name);
    }
};

// 方式三: 箭头函数 (注意:this 指向问题)
const person3 = {
    name: '王五',
    age: 22,

    sayHello: () => {
        console.log('你好,我是' + this.name); // undefined
    }
};

调用对象方法:

javascript
const person = {
    name: '张三',
    age: 18,

    sayHello() {
        console.log('你好,我是' + this.name);
    },

    introduce() {
        console.log(`我叫${this.name},今年${this.age}岁`);
    }
};

// 调用方法
person.sayHello();    // 你好,我是张三
person.introduce();   // 我叫张三,今年18岁

方法参数的使用:

javascript
const calculator = {
    add(a, b) {
        return a + b;
    },

    subtract(a, b) {
        return a - b;
    },

    multiply(a, b) {
        return a * b;
    },

    divide(a, b) {
        if (b === 0) {
            throw new Error('除数不能为0');
        }
        return a / b;
    }
};

// 调用带参数的方法
console.log(calculator.add(5, 3));      // 8
console.log(calculator.subtract(5, 3)); // 2
console.log(calculator.multiply(5, 3)); // 15
console.log(calculator.divide(6, 3));   // 2

this 关键字:

javascript
const person = {
    name: '张三',
    age: 18,

    // this 指向调用这个方法的对象
    sayHello() {
        console.log('this.name =', this.name);
    },

    compareWith(otherPerson) {
        if (this.age > otherPerson.age) {
            console.log(this.name + '比' + otherPerson.name + '大');
        } else {
            console.log(this.name + '比' + otherPerson.name + '小');
        }
    }
};

const otherPerson = {
    name: '李四',
    age: 20
};

person.sayHello(); // this.name = 张三
person.compareWith(otherPerson); // 张三比李四小

对象的常见方法:

javascript
const person = {
    name: '张三',
    age: 18,
    gender: '男',

    // 获取信息
    getInfo() {
        return {
            name: this.name,
            age: this.age,
            gender: this.gender
        };
    },

    // 更新信息
    updateInfo(newInfo) {
        Object.assign(this, newInfo);
    },

    // 打印信息
    printInfo() {
        console.log(`姓名: ${this.name}, 年龄: ${this.age}, 性别: ${this.gender}`);
    },

    // 判断是否成年
    isAdult() {
        return this.age >= 18;
    }
};

// 使用方法
console.log(person.getInfo());
// { name: '张三', age: 18, gender: '男' }

person.updateInfo({ age: 19, gender: '女' });
console.log(person.getInfo());
// { name: '张三', age: 19, gender: '女' }

person.printInfo();
// 姓名: 张三, 年龄: 19, 性别: 女

console.log(person.isAdult()); // true

方法作为回调函数:

javascript
const math = {
    base: 10,

    // 方法可以作为回调函数
    add: function(a, b) {
        return a + b;
    }
};

const numbers = [1, 2, 3, 4, 5];

// 使用对象方法
const doubled = numbers.map(function(num) {
    return math.add(num, num);
});
console.log(doubled); // [2, 4, 6, 8, 10]

// 使用对象方法的简化版本
const doubled2 = numbers.map(num => math.add(num, num));
console.log(doubled2); // [2, 4, 6, 8, 10]

对象方法的实际应用示例:

javascript
// 学生管理系统
const student = {
    name: '张三',
    studentId: '2024001',
    scores: {
        math: 90,
        english: 85,
        chinese: 88
    },

    // 计算平均分
    getAverageScore() {
        const scores = Object.values(this.scores);
        const sum = scores.reduce((total, score) => total + score, 0);
        return (sum / scores.length).toFixed(2);
    },

    // 获取最高分科目
    getMaxScoreSubject() {
        let maxSubject = '';
        let maxScore = 0;

        for (const subject in this.scores) {
            if (this.scores[subject] > maxScore) {
                maxScore = this.scores[subject];
                maxSubject = subject;
            }
        }

        return {
            subject: maxSubject,
            score: maxScore
        };
    },

    // 更新成绩
    updateScore(subject, score) {
        if (this.scores.hasOwnProperty(subject)) {
            this.scores[subject] = score;
            console.log(`${subject} 成绩已更新为 ${score}`);
        } else {
            console.log('科目不存在');
        }
    },

    // 打印成绩单
    printReport() {
        console.log(`=== ${this.name} 的成绩单 ===`);
        console.log(`学号: ${this.studentId}`);
        console.log('----------------');
        for (const subject in this.scores) {
            console.log(`${subject}: ${this.scores[subject]}`);
        }
        console.log('----------------');
        console.log(`平均分: ${this.getAverageScore()}`);
        console.log('==================');
    }
};

// 使用学生对象
console.log('平均分:', student.getAverageScore()); // 平均分: 87.67

const maxScore = student.getMaxScoreSubject();
console.log('最高分科目:', maxScore); // 最高分科目: { subject: 'math', score: 90 }

student.updateScore('math', 95); // math 成绩已更新为 95
student.printReport();
// === 张三 的成绩单 ===
// 学号: 2024001
// ----------------
// math: 95
// english: 85
// chinese: 88
// ----------------
// 平均分: 89.33
// ==================

对象方法的注意事项:

javascript
// 注意1: this 的指向
const obj = {
    name: '张三',

    // 普通函数 - this 指向对象
    regularMethod() {
        console.log(this.name); // 张三
    },

    // 箭头函数 - this 继承外层作用域
    arrowMethod: () => {
        console.log(this.name); // undefined (在浏览器中可能是 window.name)
    }
};

// 注意2: 方法中的嵌套函数
const obj2 = {
    name: '李四',

    method() {
        // 嵌套函数中的 this 不再指向对象
        function inner() {
            console.log(this.name); // undefined
        }
        inner();

        // 解决方法1: 使用箭头函数
        const inner2 = () => {
            console.log(this.name); // 李四
        };
        inner2();

        // 解决方法2: 保存 this
        const self = this;
        function inner3() {
            console.log(self.name); // 李四
        }
        inner3();
    }
};

// 注意3: 解构会丢失 this
const obj3 = {
    name: '王五',
    greet() {
        console.log('你好,我是' + this.name);
    }
};

const { greet } = obj3;
greet(); // 你好,我是undefined

// 解决方法: 使用 bind
const greet2 = obj3.greet.bind(obj3);
greet2(); // 你好,我是王五

1.3 对象的遍历

1.3.1 for...in 循环

for...in 循环用于遍历对象的可枚举属性:

javascript
const person = {
    name: '张三',
    age: 18,
    gender: '男',
    city: '北京'
};

// 遍历对象属性名(键)
for (let key in person) {
    console.log(key); // name, age, gender, city
}

// 遍历对象属性值
for (let key in person) {
    console.log(person[key]); // 张三, 18, 男, 北京
}

// 同时遍历键和值
for (let key in person) {
    console.log(`${key}: ${person[key]}`);
}
// name: 张三
// age: 18
// gender: 男
// city: 北京

for...in 的注意事项:

javascript
// 注意1: 会遍历原型链上的可枚举属性
const obj = { a: 1, b: 2 };
Object.prototype.c = 3; // 添加原型属性

for (let key in obj) {
    console.log(key); // a, b, c (包括原型上的 c)
}

// 解决方法: 使用 hasOwnProperty 检查
for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
        console.log(key); // a, b (只输出对象自身的属性)
    }
}

// 注意2: 属性顺序不一定按创建顺序
const obj2 = {};
obj2.z = 'last';
obj2.a = 'first';
obj2.m = 'middle';

for (let key in obj2) {
    console.log(key); // 数字类型先按顺序,字符串类型按插入顺序
}

1.3.2 Object.keys()

Object.keys() 返回对象自身可枚举属性的键数组:

javascript
const person = {
    name: '张三',
    age: 18,
    gender: '男'
};

// 获取所有键
const keys = Object.keys(person);
console.log(keys); // ['name', 'age', 'gender']

// 结合 forEach 遍历
Object.keys(person).forEach(key => {
    console.log(key, person[key]);
});
// name 张三
// age 18
// gender 男

1.3.3 Object.values()

Object.values() 返回对象自身可枚举属性的值数组:

javascript
const person = {
    name: '张三',
    age: 18,
    gender: '男'
};

// 获取所有值
const values = Object.values(person);
console.log(values); // ['张三', 18, '男']

// 遍历值
Object.values(person).forEach(value => {
    console.log(value);
});
// 张三
// 18
// 男

1.3.4 Object.entries()

Object.entries() 返回对象自身可枚举属性的键值对数组:

javascript
const person = {
    name: '张三',
    age: 18,
    gender: '男'
};

// 获取键值对数组
const entries = Object.entries(person);
console.log(entries);
// [['name', '张三'], ['age', 18], ['gender', '男']]

// 遍历键值对
Object.entries(person).forEach(([key, value]) => {
    console.log(`${key}: ${value}`);
});
// name: 张三
// age: 18
// gender: 男

// 将对象转为 Map
const map = new Map(Object.entries(person));
console.log(map.get('name')); // 张三

1.3.5 Object.getOwnPropertyNames()

Object.getOwnPropertyNames() 返回对象自身所有属性(包括不可枚举属性)的键数组:

javascript
const obj = { a: 1, b: 2 };
Object.defineProperty(obj, 'c', {
    value: 3,
    enumerable: false // 不可枚举
});

console.log(Object.keys(obj));           // ['a', 'b'] (不包括不可枚举属性)
console.log(Object.getOwnPropertyNames(obj)); // ['a', 'b', 'c'] (包括所有属性)

1.3.6 遍历方法对比

方法返回值包含不可枚举属性包含原型链属性
for...in
Object.keys()键数组
Object.values()值数组
Object.entries()键值对数组
Object.getOwnPropertyNames()键数组

1.3.7 实际应用示例

示例1: 对象深拷贝

javascript
function deepCopy(obj) {
    const copy = {};
    for (let key in obj) {
        if (obj.hasOwnProperty(key)) {
            if (typeof obj[key] === 'object' && obj[key] !== null) {
                copy[key] = deepCopy(obj[key]); // 递归拷贝
            } else {
                copy[key] = obj[key];
            }
        }
    }
    return copy;
}

const original = {
    name: '张三',
    age: 18,
    address: {
        city: '北京',
        district: '海淀区'
    }
};

const copied = deepCopy(original);
console.log(copied);

示例2: 对象属性统计

javascript
function countProperties(obj) {
    const stats = {
        total: 0,
        types: {
            string: 0,
            number: 0,
            boolean: 0,
            object: 0,
            function: 0,
            undefined: 0
        }
    };

    Object.values(obj).forEach(value => {
        stats.total++;
        const type = typeof value;
        if (stats.types.hasOwnProperty(type)) {
            stats.types[type]++;
        }
    });

    return stats;
}

const data = {
    name: '张三',
    age: 18,
    isStudent: true,
    address: { city: '北京' },
    greet: function() { console.log('你好'); },
    nothing: undefined
};

console.log(countProperties(data));
// {
//   total: 6,
//   types: {
//     string: 1,
//     number: 1,
//     boolean: 1,
//     object: 1,
//     function: 1,
//     undefined: 1
//   }
// }

示例3: 对象属性过滤

javascript
function filterObject(obj, condition) {
    const result = {};
    Object.entries(obj).forEach(([key, value]) => {
        if (condition(key, value)) {
            result[key] = value;
        }
    });
    return result;
}

const person = {
    name: '张三',
    age: 18,
    gender: '男',
    city: '北京',
    score: 90,
    isStudent: true
};

// 过滤出字符串类型的属性
const stringProps = filterObject(person, (key, value) => typeof value === 'string');
console.log(stringProps);
// { name: '张三', gender: '男', city: '北京' }

// 过滤出数值类型的属性
const numberProps = filterObject(person, (key, value) => typeof value === 'number');
console.log(numberProps);
// { age: 18, score: 90 }

示例4: 对象属性转换

javascript
function transformObject(obj, transformFn) {
    const result = {};
    Object.entries(obj).forEach(([key, value]) => {
        result[key] = transformFn(key, value);
    });
    return result;
}

const data = {
    name: 'zhang san',
    age: '18',
    score: '90'
};

// 将字符串数字转为数字
const transformed = transformObject(data, (key, value) => {
    if (!isNaN(value) && value !== '') {
        return Number(value);
    }
    return value;
});

console.log(transformed);
// { name: 'zhang san', age: 18, score: 90 }

示例5: 对象比较

javascript
function compareObjects(obj1, obj2) {
    const keys1 = Object.keys(obj1);
    const keys2 = Object.keys(obj2);

    if (keys1.length !== keys2.length) {
        return false;
    }

    for (let key of keys1) {
        if (!obj2.hasOwnProperty(key)) {
            return false;
        }
        if (obj1[key] !== obj2[key]) {
            return false;
        }
    }

    return true;
}

const obj1 = { name: '张三', age: 18 };
const obj2 = { name: '张三', age: 18 };
const obj3 = { name: '李四', age: 18 };

console.log(compareObjects(obj1, obj2)); // true
console.log(compareObjects(obj1, obj3)); // false

示例6: 对象合并

javascript
function mergeObjects(...objects) {
    const result = {};
    objects.forEach(obj => {
        Object.entries(obj).forEach(([key, value]) => {
            result[key] = value;
        });
    });
    return result;
}

const obj1 = { name: '张三', age: 18 };
const obj2 = { gender: '男', city: '北京' };
const obj3 = { score: 90, isStudent: true };

const merged = mergeObjects(obj1, obj2, obj3);
console.log(merged);
// { name: '张三', age: 18, gender: '男', city: '北京', score: 90, isStudent: true }

1.3.8 遍历的注意事项

javascript
// 注意1: 遍历时不要直接修改对象
const obj = { a: 1, b: 2, c: 3 };

// 错误: 直接修改可能导致问题
for (let key in obj) {
    delete obj[key]; // 可能导致意外的行为
}

// 正确: 创建新对象
const filtered = {};
for (let key in obj) {
    if (obj[key] > 1) {
        filtered[key] = obj[key];
    }
}
console.log(filtered); // { b: 2, c: 3 }

// 注意2: 使用 const 避免意外的键修改
Object.keys(obj).forEach(key => {
    // key = 'newKey'; // 不会影响原对象
    console.log(obj[key]);
});

// 注意3: 处理嵌套对象
const nestedObj = {
    user: {
        name: '张三',
        info: {
            age: 18,
            address: {
                city: '北京'
            }
        }
    }
};

// 递归遍历嵌套对象
function traverseObject(obj, path = '') {
    Object.entries(obj).forEach(([key, value]) => {
        const currentPath = path ? `${path}.${key}` : key;
        if (typeof value === 'object' && value !== null) {
            traverseObject(value, currentPath);
        } else {
            console.log(`${currentPath}: ${value}`);
        }
    });
}

traverseObject(nestedObj);
// user.name: 张三
// user.info.age: 18
// user.info.address.city: 北京

1.3.9 最佳实践

javascript
// 最佳实践1: 优先使用 Object.keys/values/entries
const obj = { name: '张三', age: 18 };

// 推荐: 使用 Object.keys
Object.keys(obj).forEach(key => {
    console.log(key, obj[key]);
});

// 其次: 使用 for...in (记得用 hasOwnProperty)
for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
        console.log(key, obj[key]);
    }
}

// 最佳实践2: 根据需求选择合适的方法
// 只需要键: Object.keys()
// 只需要值: Object.values()
// 需要键值对: Object.entries() 或 for...in

// 最佳实践3: 性能考虑
const largeObj = {}; // 假设有很多属性

// 性能较好: for...in
for (let key in largeObj) {
    if (largeObj.hasOwnProperty(key)) {
        // 处理
    }
}

// 现代浏览器性能也不错: Object.keys()
Object.keys(largeObj).forEach(key => {
    // 处理
});

2. JS内置对象

JavaScript 提供了许多内置对象,这些对象提供了各种功能和方法,可以直接使用。

2.1 Math 对象

Math 对象用于执行数学任务,它不是构造函数,不需要用 new 调用。

2.1.1 常用数学常量

javascript
// 圆周率
console.log(Math.PI); // 3.141592653589793

// 自然对数的底
console.log(Math.E); // 2.718281828459045

// 其他常量
console.log(Math.SQRT2);  // 2 的平方根: 1.4142135623730951
console.log(Math.SQRT1_2); // 1/2 的平方根: 0.7071067811865476
console.log(Math.LN2);    // 2 的自然对数: 0.6931471805599453
console.log(Math.LN10);   // 10 的自然对数: 2.302585092994046
console.log(Math.LOG2E);  // 以 2 为底 e 的对数: 1.4426950408889634
console.log(Math.LOG10E); // 以 10 为底 e 的对数: 0.4342944819032518

2.1.2 常用数学方法

取整方法

javascript
const num = 3.7;

// 向上取整: 返回大于等于给定数字的最小整数
console.log(Math.ceil(3.1));  // 4
console.log(Math.ceil(3.9));  // 4
console.log(Math.ceil(-3.9)); // -3

// 向下取整: 返回小于等于给定数字的最大整数
console.log(Math.floor(3.9));  // 3
console.log(Math.floor(3.1));  // 3
console.log(Math.floor(-3.1)); // -4

// 四舍五入: 返回最接近的整数
console.log(Math.round(3.4));  // 3
console.log(Math.round(3.5));  // 4
console.log(Math.round(-3.5)); // -3 (注意: -3.5 四舍五入到 -3)

// 截断小数: 返回数字的整数部分
console.log(Math.trunc(3.9));  // 3
console.log(Math.trunc(-3.9)); // -3

// 取整数部分 (使用位运算)
console.log(~~3.9);  // 3
console.log(~~-3.9); // -3

最大值和最小值

javascript
// 获取多个数字中的最大值
console.log(Math.max(1, 5, 3, 9, 2)); // 9
console.log(Math.max(...[1, 5, 3, 9, 2])); // 9

// 获取多个数字中的最小值
console.log(Math.min(1, 5, 3, 9, 2)); // 1
console.log(Math.min(...[1, 5, 3, 9, 2])); // 1

// 应用: 获取数组中的最大值和最小值
const numbers = [15, 8, 23, 42, 7];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
console.log(`最大值: ${max}, 最小值: ${min}`); // 最大值: 42, 最小值: 7

幂运算和开方

javascript
// 幂运算: x 的 y 次方
console.log(Math.pow(2, 3));  // 8 (2 的 3 次方)
console.log(Math.pow(5, 2));  // 25 (5 的 2 次方)
console.log(Math.pow(4, 0.5)); // 2 (4 的 0.5 次方 = 平方根)

// 平方根
console.log(Math.sqrt(16));  // 4
console.log(Math.sqrt(2));   // 1.4142135623730951
console.log(Math.sqrt(-1));  // NaN

// 立方根
console.log(Math.cbrt(8));   // 2
console.log(Math.cbrt(27));  // 3

绝对值

javascript
console.log(Math.abs(5));   // 5
console.log(Math.abs(-5));  // 5
console.log(Math.abs(-3.14)); // 3.14
console.log(Math.abs(0));   // 0

随机数

javascript
// 生成 0 到 1 之间的随机小数 (包括 0, 不包括 1)
console.log(Math.random()); // 例如: 0.123456789...

// 生成指定范围内的随机整数 (例如: 0-9)
function getRandomInt(max) {
    return Math.floor(Math.random() * max);
}
console.log(getRandomInt(10)); // 0-9 之间的整数

// 生成指定范围内的随机整数 (例如: min-max)
function getRandomIntInRange(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandomIntInRange(1, 10)); // 1-10 之间的整数

// 生成随机颜色
function getRandomColor() {
    const r = Math.floor(Math.random() * 256);
    const g = Math.floor(Math.random() * 256);
    const b = Math.floor(Math.random() * 256);
    return `rgb(${r}, ${g}, ${b})`;
}
console.log(getRandomColor()); // 例如: rgb(123, 45, 67)

// 从数组中随机选择一个元素
function randomChoice(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
}
const fruits = ['苹果', '香蕉', '橙子', '葡萄'];
console.log(randomChoice(fruits)); // 随机选择一个水果

三角函数

javascript
// 角度转弧度
function toRadians(degrees) {
    return degrees * (Math.PI / 180);
}

// 弧度转角度
function toDegrees(radians) {
    return radians * (180 / Math.PI);
}

// 正弦
console.log(Math.sin(Math.PI / 2)); // 1 (90 度的正弦值)
console.log(Math.sin(0)); // 0

// 余弦
console.log(Math.cos(0)); // 1
console.log(Math.cos(Math.PI)); // -1 (180 度的余弦值)

// 正切
console.log(Math.tan(Math.PI / 4)); // 1 (45 度的正切值)

// 反正弦
console.log(Math.asin(1)); // 1.5707963267948966 (Math.PI / 2)

2.1.3 Math 对象的实际应用

应用1: 计算圆的面积和周长

javascript
function calculateCircle(radius) {
    const area = Math.PI * Math.pow(radius, 2);
    const circumference = 2 * Math.PI * radius;
    return {
        area: area.toFixed(2),
        circumference: circumference.toFixed(2)
    };
}

console.log(calculateCircle(5));
// { area: "78.54", circumference: "31.42" }

应用2: 随机生成验证码

javascript
function generateCode(length = 4) {
    const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
    let code = '';
    for (let i = 0; i < length; i++) {
        code += chars[Math.floor(Math.random() * chars.length)];
    }
    return code;
}

console.log(generateCode()); // 例如: A7B9
console.log(generateCode(6)); // 例如: X3Y5Z2

应用3: 数值范围限制

javascript
function clamp(value, min, max) {
    return Math.max(min, Math.min(value, max));
}

console.log(clamp(50, 0, 100));   // 50 (在范围内)
console.log(clamp(-10, 0, 100));  // 0 (低于最小值)
console.log(clamp(150, 0, 100));  // 100 (高于最大值)

2.2 Date 对象

Date 对象用于处理日期和时间。

2.2.1 创建日期对象

javascript
// 创建当前日期时间
const now = new Date();
console.log(now); // 当前日期和时间

// 创建指定日期
const date1 = new Date('2024-01-15');
console.log(date1); // 2024-01-15T00:00:00.000Z

const date2 = new Date(2024, 0, 15); // 月份从 0 开始,0 表示 1 月
console.log(date2); // 2024-01-15T00:00:00.000Z

const date3 = new Date(2024, 0, 15, 10, 30, 0); // 年, 月, 日, 时, 分, 秒
console.log(date3); // 2024-01-15T02:30:00.000Z (北京时间会自动转换)

// 使用时间戳创建
const date4 = new Date(1705276800000);
console.log(date4); // 2024-01-15T00:00:00.000Z

2.2.2 获取日期和时间

javascript
const date = new Date();

// 获取年份 (4位)
console.log(date.getFullYear()); // 例如: 2024

// 获取月份 (0-11)
console.log(date.getMonth()); // 0 表示 1 月,11 表示 12 月

// 获取日期 (1-31)
console.log(date.getDate()); // 例如: 15

// 获取星期 (0-6, 0 表示周日)
console.log(date.getDay()); // 例如: 1 (周一)

// 获取小时 (0-23)
console.log(date.getHours()); // 例如: 14

// 获取分钟 (0-59)
console.log(date.getMinutes()); // 例如: 30

// 获取秒 (0-59)
console.log(date.getSeconds()); // 例如: 45

// 获取毫秒 (0-999)
console.log(date.getMilliseconds()); // 例如: 123

// 获取时间戳 (从 1970-01-01 00:00:00 UTC 开始的毫秒数)
console.log(date.getTime()); // 例如: 1705276800000
console.log(Date.now()); // 当前时间的时间戳

2.2.3 设置日期和时间

javascript
const date = new Date();

// 设置年份
date.setFullYear(2025);
console.log(date.getFullYear()); // 2025

// 设置月份 (0-11)
date.setMonth(11); // 12 月
console.log(date.getMonth()); // 11

// 设置日期
date.setDate(25);
console.log(date.getDate()); // 25

// 设置小时
date.setHours(10);
console.log(date.getHours()); // 10

// 设置分钟
date.setMinutes(30);
console.log(date.getMinutes()); // 30

// 设置秒
date.setSeconds(0);
console.log(date.getSeconds()); // 0

// 设置时间戳
date.setTime(1705276800000);
console.log(date.getTime()); // 1705276800000

2.2.4 日期格式化

javascript
const date = new Date();

// toString() - 返回本地日期字符串
console.log(date.toString());
// 例如: Mon Jan 15 2024 14:30:45 GMT+0800 (中国标准时间)

// toDateString() - 只返回日期部分
console.log(date.toDateString());
// 例如: Mon Jan 15 2024

// toTimeString() - 只返回时间部分
console.log(date.toTimeString());
// 例如: 14:30:45 GMT+0800 (中国标准时间)

// toISOString() - 返回 ISO 8601 格式
console.log(date.toISOString());
// 例如: 2024-01-15T06:30:45.000Z

// 自定义格式化
function formatDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, '0');
    const day = String(date.getDate()).padStart(2, '0');
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');

    return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
}

console.log(formatDate(date)); // 例如: 2024-01-15 14:30:45

// 格式化为中文日期
function formatChineseDate(date) {
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();
    const weekDays = ['日', '一', '二', '三', '四', '五', '六'];
    const weekDay = weekDays[date.getDay()];

    return `${year}年${month}月${day}日 星期${weekDay}`;
}

console.log(formatChineseDate(date)); // 例如: 2024年1月15日 星期一

2.2.5 日期计算

javascript
// 计算两个日期之间的天数差
function daysBetween(date1, date2) {
    const diffTime = Math.abs(date2 - date1);
    const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));
    return diffDays;
}

const start = new Date('2024-01-01');
const end = new Date('2024-01-15');
console.log(daysBetween(start, end)); // 14

// 添加天数
function addDays(date, days) {
    const result = new Date(date);
    result.setDate(result.getDate() + days);
    return result;
}

const today = new Date();
const nextWeek = addDays(today, 7);
console.log(nextWeek); // 一周后的日期

// 判断是否是今天
function isToday(date) {
    const today = new Date();
    return date.getDate() === today.getDate() &&
           date.getMonth() === today.getMonth() &&
           date.getFullYear() === today.getFullYear();
}

// 判断是否是工作日 (周一到周五)
function isWeekday(date) {
    const day = date.getDay();
    return day > 0 && day < 6; // 0 是周日,6 是周六
}

// 计算倒计时
function countdown(targetDate) {
    const now = new Date();
    const target = new Date(targetDate);
    const diff = target - now;

    if (diff <= 0) {
        return '时间已到';
    }

    const days = Math.floor(diff / (1000 * 60 * 60 * 24));
    const hours = Math.floor((diff % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
    const minutes = Math.floor((diff % (1000 * 60 * 60)) / (1000 * 60));
    const seconds = Math.floor((diff % (1000 * 60)) / 1000);

    return `${days}天 ${hours}小时 ${minutes}分钟 ${seconds}秒`;
}

console.log(countdown('2024-12-31'));

2.3 Array 对象

Array 对象用于处理数组,提供了丰富的方法。

2.3.1 数组创建

javascript
// 方式一: 字面量创建
const arr1 = [1, 2, 3, 4, 5];

// 方式二: 构造函数创建
const arr2 = new Array(1, 2, 3, 4, 5);

// 方式三: 创建指定长度的空数组
const arr3 = new Array(5); // [undefined × 5]

// 方式四: Array.of() (推荐)
const arr4 = Array.of(1, 2, 3, 4, 5);
const arr5 = Array.of(5); // [5] (注意: 与 new Array(5) 不同)

2.3.2 数组常用方法

添加和删除元素

javascript
const fruits = ['苹果', '香蕉'];

// push() - 在末尾添加元素
fruits.push('橙子');
console.log(fruits); // ['苹果', '香蕉', '橙子']

// pop() - 删除末尾元素
const last = fruits.pop();
console.log(last); // 橙子
console.log(fruits); // ['苹果', '香蕉']

// unshift() - 在开头添加元素
fruits.unshift('葡萄');
console.log(fruits); // ['葡萄', '苹果', '香蕉']

// shift() - 删除开头元素
const first = fruits.shift();
console.log(first); // 葡萄
console.log(fruits); // ['苹果', '香蕉']

数组转换

javascript
// toString() - 转为字符串
const arr = [1, 2, 3, 4, 5];
console.log(arr.toString()); // "1,2,3,4,5"

// join() - 用指定分隔符连接成字符串
console.log(arr.join('-')); // "1-2-3-4-5"
console.log(arr.join(''));  // "12345"

// split() - 字符串转数组
const str = '1,2,3,4,5';
console.log(str.split(',')); // ['1', '2', '3', '4', '5']

数组查找

javascript
const fruits = ['苹果', '香蕉', '橙子', '葡萄', '苹果'];

// indexOf() - 查找元素,返回索引,不存在返回 -1
console.log(fruits.indexOf('苹果'));   // 0
console.log(fruits.indexOf('梨子'));    // -1
console.log(fruits.indexOf('苹果', 1)); // 4 (从索引 1 开始查找)

// lastIndexOf() - 从后往前查找
console.log(fruits.lastIndexOf('苹果')); // 4

// includes() - 判断是否包含元素
console.log(fruits.includes('苹果')); // true
console.log(fruits.includes('梨子')); // false

// find() - 查找符合条件的第一个元素
const numbers = [1, 5, 10, 15, 20];
const found = numbers.find(num => num > 10);
console.log(found); // 15

// findIndex() - 查找符合条件的第一个元素的索引
const index = numbers.findIndex(num => num > 10);
console.log(index); // 3

数组迭代

javascript
const numbers = [1, 2, 3, 4, 5];

// forEach() - 遍历数组
numbers.forEach((num, index, array) => {
    console.log(`索引 ${index}: ${num}`);
});

// map() - 映射,返回新数组
const doubled = numbers.map(num => num * 2);
console.log(doubled); // [2, 4, 6, 8, 10]

// filter() - 过滤,返回符合条件的新数组
const evens = numbers.filter(num => num % 2 === 0);
console.log(evens); // [2, 4]

// reduce() - 归约,累加
const sum = numbers.reduce((total, num) => total + num, 0);
console.log(sum); // 15

// some() - 是否有元素满足条件
const hasEven = numbers.some(num => num % 2 === 0);
console.log(hasEven); // true

// every() - 是否所有元素都满足条件
const allPositive = numbers.every(num => num > 0);
console.log(allPositive); // true

数组排序

javascript
const numbers = [3, 1, 4, 1, 5, 9, 2, 6];

// sort() - 排序 (默认按字符串排序)
numbers.sort();
console.log(numbers); // [1, 1, 2, 3, 4, 5, 6, 9]

// 数字排序 (需要提供比较函数)
const nums = [3, 1, 4, 1, 5, 9, 2, 6];
nums.sort((a, b) => a - b); // 升序
console.log(nums); // [1, 1, 2, 3, 4, 5, 6, 9]

nums.sort((a, b) => b - a); // 降序
console.log(nums); // [9, 6, 5, 4, 3, 2, 1, 1]

// 对象数组排序
const users = [
    { name: '张三', age: 25 },
    { name: '李四', age: 20 },
    { name: '王五', age: 30 }
];

users.sort((a, b) => a.age - b.age);
console.log(users);
// [
//   { name: '李四', age: 20 },
//   { name: '张三', age: 25 },
//   { name: '王五', age: 30 }
// ]

// reverse() - 反转数组
const arr = [1, 2, 3, 4, 5];
arr.reverse();
console.log(arr); // [5, 4, 3, 2, 1]

2.3.3 数组去重

javascript
// 方法一: 使用 Set
const arr1 = [1, 2, 2, 3, 4, 4, 5];
const unique1 = [...new Set(arr1)];
console.log(unique1); // [1, 2, 3, 4, 5]

// 方法二: 使用 filter 和 indexOf
const arr2 = [1, 2, 2, 3, 4, 4, 5];
const unique2 = arr2.filter((item, index) => arr2.indexOf(item) === index);
console.log(unique2); // [1, 2, 3, 4, 5]

// 方法三: 使用 reduce
const arr3 = [1, 2, 2, 3, 4, 4, 5];
const unique3 = arr3.reduce((acc, item) => {
    if (!acc.includes(item)) {
        acc.push(item);
    }
    return acc;
}, []);
console.log(unique3); // [1, 2, 3, 4, 5]

2.4 String 对象

String 对象用于处理字符串。

2.4.1 字符串常用方法

javascript
const str = 'Hello World';

// 获取长度
console.log(str.length); // 11

// 获取字符
console.log(str.charAt(0)); // 'H'
console.log(str[0]);        // 'H' (推荐)

// 获取字符编码
console.log(str.charCodeAt(0)); // 72

// 查找子串
console.log(str.indexOf('World')); // 6
console.log(str.indexOf('world')); // -1 (大小写敏感)
console.log(str.includes('World')); // true

// 判断开头和结尾
console.log(str.startsWith('Hello')); // true
console.log(str.endsWith('World'));  // true

// 截取字符串
console.log(str.slice(0, 5));   // 'Hello'
console.log(str.slice(6));      // 'World'
console.log(str.substring(0, 5)); // 'Hello'
console.log(str.substr(6, 5));    // 'World'

// 大小写转换
console.log(str.toUpperCase()); // 'HELLO WORLD'
console.log(str.toLowerCase()); // 'hello world'

// 去除空白
const str2 = '  hello  ';
console.log(str2.trim()); // 'hello'
console.log(str2.trimStart()); // 'hello  '
console.log(str2.trimEnd());   // '  hello'

2.4.2 字符串替换和分割

javascript
const str = 'Hello World Hello';

// replace() - 替换 (只替换第一个)
console.log(str.replace('Hello', 'Hi')); // 'Hi World Hello'

// replaceAll() - 替换所有
console.log(str.replaceAll('Hello', 'Hi')); // 'Hi World Hi'

// split() - 分割字符串
const str3 = 'apple,banana,orange';
console.log(str3.split(',')); // ['apple', 'banana', 'orange']

// 限制分割次数
console.log(str3.split(',', 2)); // ['apple', 'banana']

2.4.3 字符串重复和填充

javascript
// repeat() - 重复字符串
console.log('abc'.repeat(3)); // 'abcabcabc'

// padStart() - 开头填充
console.log('5'.padStart(2, '0')); // '05'
console.log('123'.padStart(5, '0')); // '00123'

// padEnd() - 结尾填充
console.log('5'.padEnd(2, '0')); // '50'
console.log('123'.padEnd(5, '0')); // '12300'

2.5 JSON 对象

JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。

2.5.1 JSON.parse()

将 JSON 字符串转换为 JavaScript 对象:

javascript
const jsonStr = '{"name": "张三", "age": 18, "isStudent": true}';

// 解析 JSON 字符串
const obj = JSON.parse(jsonStr);
console.log(obj); // { name: '张三', age: 18, isStudent: true }
console.log(obj.name); // 张三

// 解析数组
const arrStr = '[1, 2, 3, 4, 5]';
const arr = JSON.parse(arrStr);
console.log(arr); // [1, 2, 3, 4, 5]

// 带错误处理
try {
    const invalidJson = '{"name": "张三", age: 18}'; // 缺少引号
    const result = JSON.parse(invalidJson);
} catch (error) {
    console.log('JSON 解析失败:', error.message);
}

2.5.2 JSON.stringify()

将 JavaScript 对象转换为 JSON 字符串:

javascript
const obj = {
    name: '张三',
    age: 18,
    isStudent: true,
    hobbies: ['读书', '运动']
};

// 转换为 JSON 字符串
const jsonStr = JSON.stringify(obj);
console.log(jsonStr);
// {"name":"张三","age":18,"isStudent":true,"hobbies":["读书","运动"]}

// 格式化输出 (缩进 2 个空格)
const formatted = JSON.stringify(obj, null, 2);
console.log(formatted);
// {
//   "name": "张三",
//   "age": 18,
//   "isStudent": true,
//   "hobbies": [
//     "读书",
//     "运动"
//   ]
// }

// 过滤属性
const filtered = JSON.stringify(obj, ['name', 'age']);
console.log(filtered); // {"name":"张三","age":18}

2.5.3 JSON 实际应用

javascript
// 存储数据到 localStorage
const user = {
    id: 1,
    name: '张三',
    email: 'zhangsan@example.com'
};

// 存储
localStorage.setItem('user', JSON.stringify(user));

// 读取
const storedUser = JSON.parse(localStorage.getItem('user'));
console.log(storedUser); // { id: 1, name: '张三', email: 'zhangsan@example.com' }

// 深拷贝对象
function deepClone(obj) {
    return JSON.parse(JSON.stringify(obj));
}

const original = { name: '张三', age: 18 };
const cloned = deepClone(original);
console.log(cloned); // { name: '张三', age: 18 }

Released under the MIT License.