JavaScript参考手册
本参考手册提供了JavaScript核心语法、内置对象和方法的完整参考,包含详细的语法说明、使用示例和浏览器兼容性信息。使用搜索功能快速查找您需要的内容。
JavaScript版本历史
| 版本 | 发布年份 | 主要特性 | ECMAScript版本 |
|---|---|---|---|
| ES1 | 1997 | 基础语法、类型、函数 | ECMA-262 1st Edition |
| ES3 | 1999 | 正则表达式、异常处理 | ECMA-262 3rd Edition |
| ES5 | 2009 | 严格模式、JSON、数组方法 | ECMA-262 5th Edition |
| ES6/ES2015 | 2015 | 类、模块、箭头函数、Promise | ECMA-262 6th Edition |
| ES2016 | 2016 | 数组includes、指数运算符 | ECMA-262 7th Edition |
| ES2017 | 2017 | async/await、字符串填充 | ECMA-262 8th Edition |
| ES2018 | 2018 | Rest/Spread属性、异步迭代 | ECMA-262 9th Edition |
| ES2019 | 2019 | 数组flat、Object.fromEntries | ECMA-262 10th Edition |
| ES2020 | 2020 | 可选链、空值合并、BigInt | ECMA-262 11th Edition |
| ES2021 | 2021 | 字符串replaceAll、逻辑赋值 | ECMA-262 12th Edition |
| ES2022 | 2022 | 类字段、顶层await、数组at | ECMA-262 13th Edition |
内置对象
JavaScript提供了一系列内置对象,用于处理各种数据类型和执行常见操作。这些对象在全局作用域中可用,无需导入。
全局对象
Object
Object是JavaScript中所有对象的基类。几乎所有对象都是Object的实例。
| 方法/属性 | 描述 | 语法 | 返回值 | ES版本 |
|---|---|---|---|---|
| Object.keys() | 返回对象自身可枚举属性的数组 | Object.keys(obj) |
Array | ES5 |
| Object.values() | 返回对象自身可枚举属性值的数组 | Object.values(obj) |
Array | ES2017 |
| Object.entries() | 返回对象自身可枚举属性的键值对数组 | Object.entries(obj) |
Array | ES2017 |
| Object.assign() | 将一个或多个源对象复制到目标对象 | Object.assign(target, ...sources) |
Object | ES6 |
| Object.freeze() | 冻结对象,使其不可修改 | Object.freeze(obj) |
Object | ES5 |
| Object.seal() | 密封对象,防止添加/删除属性 | Object.seal(obj) |
Object | ES5 |
| Object.create() | 使用指定原型创建新对象 | Object.create(proto) |
Object | ES5 |
| Object.defineProperty() | 定义对象的新属性或修改现有属性 | Object.defineProperty(obj, prop, descriptor) |
Object | ES5 |
| Object.getPrototypeOf() | 返回指定对象的原型 | Object.getPrototypeOf(obj) |
Object | ES5 |
| Object.hasOwn() | 检查对象是否有指定属性(不继承) | Object.hasOwn(obj, prop) |
Boolean | ES2022 |
Object方法示例
Object方法使用示例
const person = {
name: '张三',
age: 25,
city: '北京'
};
// Object.keys()
console.log(Object.keys(person)); // ['name', 'age', 'city']
// Object.values()
console.log(Object.values(person)); // ['张三', 25, '北京']
// Object.entries()
console.log(Object.entries(person));
// [['name', '张三'], ['age', 25], ['city', '北京']]
// Object.assign()
const newPerson = Object.assign({}, person, { age: 26, gender: '男' });
console.log(newPerson);
// { name: '张三', age: 26, city: '北京', gender: '男' }
// Object.freeze()
Object.freeze(person);
person.age = 30; // 严格模式下会报错
console.log(person.age); // 25 (值未改变)
// Object.create()
const student = Object.create(person);
student.grade = 'A';
console.log(student.name); // '张三' (继承自person)
console.log(student.grade); // 'A'
// Object.defineProperty()
Object.defineProperty(person, 'country', {
value: '中国',
writable: false,
enumerable: true,
configurable: false
});
console.log(person.country); // '中国'
// Object.hasOwn()
console.log(Object.hasOwn(person, 'name')); // true
console.log(Object.hasOwn(person, 'toString')); // false (继承的方法)
Math
Math对象提供数学常数和函数。Math的所有属性和方法都是静态的。
| 方法/属性 | 描述 | 语法 | 返回值 | ES版本 |
|---|---|---|---|---|
| Math.PI | 圆周率π | Math.PI |
Number | ES1 |
| Math.E | 自然对数的底数e | Math.E |
Number | ES1 |
| Math.random() | 返回0到1之间的随机数 | Math.random() |
Number | ES1 |
| Math.floor() | 向下取整 | Math.floor(x) |
Number | ES1 |
| Math.ceil() | 向上取整 | Math.ceil(x) |
Number | ES1 |
| Math.round() | 四舍五入 | Math.round(x) |
Number | ES1 |
| Math.max() | 返回最大值 | Math.max(...values) |
Number | ES1 |
| Math.min() | 返回最小值 | Math.min(...values) |
Number | ES1 |
| Math.pow() | 幂运算 | Math.pow(base, exponent) |
Number | ES1 |
| Math.sqrt() | 平方根 | Math.sqrt(x) |
Number | ES1 |
| Math.abs() | 绝对值 | Math.abs(x) |
Number | ES1 |
| Math.sin() | 正弦函数 | Math.sin(x) |
Number | ES1 |
| Math.cos() | 余弦函数 | Math.cos(x) |
Number | ES1 |
| Math.tan() | 正切函数 | Math.tan(x) |
Number | ES1 |
| Math.log() | 自然对数 | Math.log(x) |
Number | ES1 |
| Math.exp() | e的指数 | Math.exp(x) |
Number | ES1 |
Math方法示例
Math方法使用示例
// 数学常数
console.log(Math.PI); // 3.141592653589793
console.log(Math.E); // 2.718281828459045
// 随机数
console.log(Math.random()); // 0.123456789 (随机值)
console.log(Math.floor(Math.random() * 100) + 1); // 1-100的随机整数
// 取整
console.log(Math.floor(3.7)); // 3
console.log(Math.ceil(3.2)); // 4
console.log(Math.round(3.5)); // 4
// 最大值和最小值
console.log(Math.max(1, 2, 3, 4, 5)); // 5
console.log(Math.min(1, 2, 3, 4, 5)); // 1
// 幂运算和平方根
console.log(Math.pow(2, 3)); // 8
console.log(Math.sqrt(16)); // 4
// 三角函数 (参数为弧度)
console.log(Math.sin(Math.PI / 2)); // 1
console.log(Math.cos(Math.PI)); // -1
console.log(Math.tan(Math.PI / 4)); // 1
// 对数和指数
console.log(Math.log(Math.E)); // 1
console.log(Math.exp(1)); // 2.718281828459045
// 实际应用:生成随机颜色
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)
JSON
JSON对象用于解析和序列化JSON数据。
| 方法 | 描述 | 语法 | 返回值 | ES版本 |
|---|---|---|---|---|
| JSON.parse() | 解析JSON字符串为JavaScript对象 | JSON.parse(text, reviver) |
Object/Array | ES5 |
| JSON.stringify() | 将JavaScript值转换为JSON字符串 | JSON.stringify(value, replacer, space) |
String | ES5 |
JSON方法示例
JSON方法使用示例
const person = {
name: '张三',
age: 25,
hobbies: ['读书', '编程', '运动'],
address: {
city: '北京',
country: '中国'
},
isStudent: false,
birthDate: new Date('1998-05-15'),
// 函数不会被序列化
sayHello: function() {
return `你好,我是${this.name}`;
}
};
// JSON.stringify() - 序列化为JSON字符串
const jsonString = JSON.stringify(person);
console.log(jsonString);
// {"name":"张三","age":25,"hobbies":["读书","编程","运动"],"address":{"city":"北京","country":"中国"},"isStudent":false,"birthDate":"1998-05-15T00:00:00.000Z"}
// 使用replacer函数
const filteredJson = JSON.stringify(person, (key, value) => {
if (key === 'age') return undefined; // 过滤age属性
return value;
});
console.log(filteredJson);
// {"name":"张三","hobbies":["读书","编程","运动"],"address":{"city":"北京","country":"中国"},"isStudent":false,"birthDate":"1998-05-15T00:00:00.000Z"}
// 格式化输出
const prettyJson = JSON.stringify(person, null, 2);
console.log(prettyJson);
/*
{
"name": "张三",
"age": 25,
"hobbies": [
"读书",
"编程",
"运动"
],
...
}
*/
// JSON.parse() - 解析JSON字符串
const parsedObject = JSON.parse(jsonString);
console.log(parsedObject.name); // '张三'
console.log(parsedObject.hobbies); // ['读书', '编程', '运动']
// 使用reviver函数
const revivedObject = JSON.parse(jsonString, (key, value) => {
if (key === 'birthDate') return new Date(value);
return value;
});
console.log(revivedObject.birthDate instanceof Date); // true
// 错误处理
try {
const invalidJson = '{"name": "张三", "age": }';
const result = JSON.parse(invalidJson);
} catch (error) {
console.error('JSON解析错误:', error.message);
}
数组方法
Array对象提供了处理数组的各种方法,包括修改、遍历、搜索和转换数组的方法。
常用数组方法
| 方法 | 描述 | 语法 | 返回值 | 改变原数组 | ES版本 |
|---|---|---|---|---|---|
| push() | 在数组末尾添加元素 | arr.push(...items) |
新长度 | 是 | ES1 |
| pop() | 移除并返回最后一个元素 | arr.pop() |
元素 | 是 | ES1 |
| shift() | 移除并返回第一个元素 | arr.shift() |
元素 | 是 | ES1 |
| unshift() | 在数组开头添加元素 | arr.unshift(...items) |
新长度 | 是 | ES1 |
| concat() | 合并数组 | arr.concat(...values) |
新数组 | 否 | ES3 |
| slice() | 返回数组的一部分 | arr.slice(start, end) |
新数组 | 否 | ES3 |
| splice() | 添加/删除元素 | arr.splice(start, deleteCount, ...items) |
被删除元素 | 是 | ES3 |
| indexOf() | 查找元素索引 | arr.indexOf(searchElement, fromIndex) |
索引/-1 | 否 | ES5 |
| lastIndexOf() | 从后向前查找元素索引 | arr.lastIndexOf(searchElement, fromIndex) |
索引/-1 | 否 | ES5 |
| includes() | 检查是否包含元素 | arr.includes(searchElement, fromIndex) |
Boolean | 否 | ES2016 |
| join() | 将数组元素连接为字符串 | arr.join(separator) |
String | 否 | ES1 |
| reverse() | 反转数组顺序 | arr.reverse() |
数组 | 是 | ES1 |
| sort() | 数组排序 | arr.sort(compareFunction) |
数组 | 是 | ES1 |
迭代方法
| 方法 | 描述 | 语法 | 返回值 | ES版本 |
|---|---|---|---|---|
| forEach() | 对每个元素执行函数 | arr.forEach(callback) |
undefined | ES5 |
| map() | 对每个元素执行函数并返回新数组 | arr.map(callback) |
新数组 | ES5 |
| filter() | 返回满足条件的元素组成的新数组 | arr.filter(callback) |
新数组 | ES5 |
| reduce() | 将数组减少为单个值 | arr.reduce(callback, initialValue) |
任意类型 | ES5 |
| reduceRight() | 从右向左将数组减少为单个值 | arr.reduceRight(callback, initialValue) |
任意类型 | ES5 |
| find() | 返回第一个满足条件的元素 | arr.find(callback) |
元素/undefined | ES6 |
| findIndex() | 返回第一个满足条件的元素索引 | arr.findIndex(callback) |
索引/-1 | ES6 |
| some() | 检查是否有元素满足条件 | arr.some(callback) |
Boolean | ES5 |
| every() | 检查所有元素是否满足条件 | arr.every(callback) |
Boolean | ES5 |
| flat() | 将嵌套数组扁平化 | arr.flat(depth) |
新数组 | ES2019 |
| flatMap() | 先映射后扁平化 | arr.flatMap(callback) |
新数组 | ES2019 |
数组方法示例
数组方法综合示例
const numbers = [1, 2, 3, 4, 5, 6];
const fruits = ['苹果', '香蕉', '橙子', '葡萄'];
const mixed = [1, 'hello', true, { name: '张三' }, [7, 8, 9]];
// 基本操作
console.log(fruits.join(', ')); // '苹果, 香蕉, 橙子, 葡萄'
console.log(fruits.includes('香蕉')); // true
console.log(fruits.indexOf('橙子')); // 2
// 添加/删除元素
fruits.push('芒果');
console.log(fruits); // ['苹果', '香蕉', '橙子', '葡萄', '芒果']
const lastFruit = fruits.pop();
console.log(lastFruit); // '芒果'
console.log(fruits); // ['苹果', '香蕉', '橙子', '葡萄']
fruits.unshift('草莓');
console.log(fruits); // ['草莓', '苹果', '香蕉', '橙子', '葡萄']
const firstFruit = fruits.shift();
console.log(firstFruit); // '草莓'
console.log(fruits); // ['苹果', '香蕉', '橙子', '葡萄']
// 切片和拼接
const sliced = fruits.slice(1, 3);
console.log(sliced); // ['香蕉', '橙子']
fruits.splice(1, 2, '桃子', '梨子');
console.log(fruits); // ['苹果', '桃子', '梨子', '葡萄']
// 使用map转换数组
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10, 12]
// 使用filter过滤数组
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4, 6]
// 使用reduce计算总和
const sum = numbers.reduce((total, n) => total + n, 0);
console.log(sum); // 21
// 使用find查找元素
const firstEven = numbers.find(n => n % 2 === 0);
console.log(firstEven); // 2
// 使用some检查条件
const hasEven = numbers.some(n => n % 2 === 0);
console.log(hasEven); // true
// 使用every检查所有元素
const allPositive = numbers.every(n => n > 0);
console.log(allPositive); // true
// 扁平化数组
const nested = [1, [2, [3, [4]]]];
console.log(nested.flat()); // [1, 2, [3, [4]]]
console.log(nested.flat(2)); // [1, 2, 3, [4]]
console.log(nested.flat(Infinity)); // [1, 2, 3, 4]
// flatMap示例
const sentences = ['Hello world', 'JavaScript is awesome'];
const words = sentences.flatMap(sentence => sentence.split(' '));
console.log(words); // ['Hello', 'world', 'JavaScript', 'is', 'awesome']
// 链式调用
const result = numbers
.filter(n => n % 2 === 0)
.map(n => n * 3)
.reduce((sum, n) => sum + n, 0);
console.log(result); // 36 (2*3 + 4*3 + 6*3)
// 排序
const randomNumbers = [3, 1, 4, 1, 5, 9, 2, 6];
console.log(randomNumbers.sort()); // [1, 1, 2, 3, 4, 5, 6, 9]
console.log(randomNumbers.sort((a, b) => b - a)); // [9, 6, 5, 4, 3, 2, 1, 1]
// 反转
console.log(fruits.reverse()); // ['葡萄', '梨子', '桃子', '苹果']
字符串方法
String对象提供了处理文本的各种方法,包括搜索、提取、修改和转换字符串的方法。
常用字符串方法
| 方法 | 描述 | 语法 | 返回值 | ES版本 |
|---|---|---|---|---|
| length | 字符串长度 | str.length |
Number | ES1 |
| charAt() | 返回指定位置的字符 | str.charAt(index) |
String | ES1 |
| charCodeAt() | 返回指定位置字符的Unicode编码 | str.charCodeAt(index) |
Number | ES1 |
| indexOf() | 返回子字符串首次出现的位置 | str.indexOf(searchValue, fromIndex) |
索引/-1 | ES1 |
| lastIndexOf() | 返回子字符串最后出现的位置 | str.lastIndexOf(searchValue, fromIndex) |
索引/-1 | ES1 |
| slice() | 提取字符串的一部分 | str.slice(startIndex, endIndex) |
String | ES3 |
| substring() | 提取字符串的一部分 | str.substring(startIndex, endIndex) |
String | ES1 |
| substr() | 从指定位置提取指定长度的字符串 | str.substr(startIndex, length) |
String | ES3 |
| toUpperCase() | 转换为大写 | str.toUpperCase() |
String | ES1 |
| toLowerCase() | 转换为小写 | str.toLowerCase() |
String | ES1 |
| trim() | 移除两端空白字符 | str.trim() |
String | ES5 |
| trimStart() | 移除开头空白字符 | str.trimStart() |
String | ES2019 |
| trimEnd() | 移除结尾空白字符 | str.trimEnd() |
String | ES2019 |
| replace() | 替换子字符串 | str.replace(searchValue, replaceValue) |
String | ES3 |
| replaceAll() | 替换所有匹配的子字符串 | str.replaceAll(searchValue, replaceValue) |
String | ES2021 |
| split() | 将字符串分割为数组 | str.split(separator, limit) |
Array | ES1 |
| startsWith() | 检查是否以指定字符串开头 | str.startsWith(searchString, position) |
Boolean | ES6 |
| endsWith() | 检查是否以指定字符串结尾 | str.endsWith(searchString, length) |
Boolean | ES6 |
| includes() | 检查是否包含指定字符串 | str.includes(searchString, position) |
Boolean | ES6 |
| padStart() | 在开头填充字符串 | str.padStart(targetLength, padString) |
String | ES2017 |
| padEnd() | 在结尾填充字符串 | str.padEnd(targetLength, padString) |
String | ES2017 |
| repeat() | 重复字符串指定次数 | str.repeat(count) |
String | ES6 |
字符串方法示例
字符串操作示例
const text = ' Hello, JavaScript World! ';
const email = 'user@example.com';
const phone = '13800138000';
const multiline = `第一行
第二行
第三行`;
// 基本操作
console.log(text.length); // 28
console.log(text.trim()); // 'Hello, JavaScript World!'
console.log(text.trimStart()); // 'Hello, JavaScript World! '
console.log(text.trimEnd()); // ' Hello, JavaScript World!'
console.log(text.toUpperCase()); // ' HELLO, JAVASCRIPT WORLD! '
console.log(text.toLowerCase()); // ' hello, javascript world! '
// 搜索和提取
console.log(text.indexOf('JavaScript')); // 9
console.log(text.lastIndexOf(' ')); // 24
console.log(text.charAt(5)); // 'H'
console.log(text.charCodeAt(5)); // 72 (H的Unicode)
console.log(text.slice(2, 7)); // 'Hello'
console.log(text.substring(2, 7)); // 'Hello'
console.log(text.substr(2, 5)); // 'Hello'
// 替换和分割
console.log(text.replace('JavaScript', 'JS')); // ' Hello, JS World! '
console.log(text.replaceAll(' ', '-')); // '--Hello,-JavaScript-World!--'
console.log(text.split(' ')); // ['', '', 'Hello,', 'JavaScript', 'World!', '', '']
// 现代方法
console.log(text.includes('JavaScript')); // true
console.log(text.startsWith(' Hello')); // true
console.log(text.endsWith('World! ')); // true
// 填充和重复
console.log('5'.padStart(3, '0')); // '005'
console.log('5'.padEnd(3, '0')); // '500'
console.log('Hi'.repeat(3)); // 'HiHiHi'
// 模板字符串 (ES6)
const name = '张三';
const age = 25;
const message = `我叫${name},今年${age}岁。`;
console.log(message); // '我叫张三,今年25岁。'
// 多行字符串
console.log(multiline);
/*
第一行
第二行
第三行
*/
// 实际应用:验证邮箱
function isValidEmail(email) {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email.trim().toLowerCase());
}
console.log(isValidEmail('USER@EXAMPLE.COM')); // true
console.log(isValidEmail('invalid-email')); // false
// 实际应用:格式化手机号
function formatPhoneNumber(phone) {
const cleaned = phone.replace(/\D/g, '');
const match = cleaned.match(/^(\d{3})(\d{4})(\d{4})$/);
if (match) {
return `${match[1]} ${match[2]} ${match[3]}`;
}
return phone;
}
console.log(formatPhoneNumber('13800138000')); // '138 0013 8000'
// 实际应用:提取URL参数
function getUrlParams(url) {
const params = {};
const urlObj = new URL(url);
urlObj.searchParams.forEach((value, key) => {
params[key] = value;
});
return params;
}
const testUrl = 'https://example.com?name=张三&age=25&city=北京';
console.log(getUrlParams(testUrl)); // { name: '张三', age: '25', city: '北京' }
ES6+新特性参考
ECMAScript 2015 (ES6) 及后续版本引入了许多新特性,使JavaScript更现代化、更强大。这些特性提高了开发效率和代码质量。
ES6+主要特性
| 特性 | 描述 | 语法示例 | ES版本 |
|---|---|---|---|
| let/const | 块级作用域变量声明 | let x = 1; const y = 2; |
ES6 |
| 箭头函数 | 简化的函数语法 | const add = (a,b) => a+b; |
ES6 |
| 模板字符串 | 多行字符串和字符串插值 | `Hello ${name}` |
ES6 |
| 解构赋值 | 从数组或对象中提取值 | const {a,b} = obj; |
ES6 |
| 默认参数 | 函数参数的默认值 | function greet(name='游客'){} |
ES6 |
| 展开运算符 | 展开数组或对象 | [...arr1, ...arr2] |
ES6 |
| 剩余参数 | 将多个参数收集为数组 | function(...args){} |
ES6 |
| Promise | 异步编程解决方案 | new Promise() |
ES6 |
| 类 | 基于类的面向对象编程 | class MyClass {} |
ES6 |
| 模块 | ES6模块系统 | import/export |
ES6 |
| Symbol | 唯一的原始数据类型 | const sym = Symbol(); |
ES6 |
| Map/Set | 新的数据结构 | new Map(), new Set() |
ES6 |
| async/await | 异步编程语法糖 | async function f() { await p; } |
ES2017 |
| 可选链 | 安全访问嵌套属性 | obj?.prop?.subprop |
ES2020 |
| 空值合并 | 提供默认值的运算符 | value ?? defaultValue |
ES2020 |
| BigInt | 大整数类型 | 123n |
ES2020 |
| 全局This | 统一的全局对象 | globalThis |
ES2020 |
ES6+特性示例
ES6+特性综合示例
// 解构赋值
const person = { name: '张三', age: 25, city: '北京' };
const { name, age, country = '中国' } = person;
console.log(name, age, country); // 张三 25 中国
// 数组解构
const numbers = [1, 2, 3, 4, 5];
const [first, second, ...rest] = numbers;
console.log(first, second, rest); // 1 2 [3,4,5]
// 函数参数解构
function printPerson({ name, age = 18 }) {
console.log(`${name} 今年 ${age} 岁`);
}
printPerson({ name: '李四' }); // 李四 今年 18 岁
// 展开运算符
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const combined = [...arr1, ...arr2];
console.log(combined); // [1,2,3,4,5,6]
// 对象展开
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2, e: 5 };
console.log(merged); // {a:1,b:2,c:3,d:4,e:5}
// 箭头函数
const numbers = [1, 2, 3, 4, 5];
const doubled = numbers.map(n => n * 2);
const evens = numbers.filter(n => n % 2 === 0);
console.log(doubled, evens); // [2,4,6,8,10] [2,4]
// this绑定示例
const counter = {
count: 0,
increment: function() {
setInterval(() => {
// 箭头函数继承外层this
this.count++;
console.log(this.count);
}, 1000);
}
};
// counter.increment();
// 类
class Person {
// 类字段 (ES2022)
#privateField = '私有字段';
constructor(name, age) {
this.name = name;
this.age = age;
}
// 实例方法
greet() {
return `你好,我是${this.name},今年${this.age}岁`;
}
// 静态方法
static isAdult(age) {
return age >= 18;
}
// 私有方法 (ES2022)
#privateMethod() {
return '这是私有方法';
}
// Getter
get description() {
return `${this.name} (${this.age}岁)`;
}
// Setter
set updateAge(newAge) {
if (newAge > 0) {
this.age = newAge;
}
}
}
const john = new Person('约翰', 30);
console.log(john.greet()); // 你好,我是约翰,今年30岁
console.log(Person.isAdult(20)); // true
console.log(john.description); // 约翰 (30岁)
john.updateAge = 31;
console.log(john.age); // 31
// 继承
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
study() {
return `${this.name}正在学习`;
}
}
const student = new Student('小明', 20, 'A');
console.log(student.greet()); // 你好,我是小明,今年20岁
console.log(student.study()); // 小明正在学习
// Promise
const fetchData = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
Math.random() > 0.3 ?
resolve('数据获取成功') :
reject('数据获取失败');
}, 1000);
});
};
// async/await
async function getData() {
try {
const data = await fetchData();
console.log(data);
return data;
} catch (error) {
console.error('错误:', error);
throw error;
}
}
getData();
// 可选链和空值合并
const user = {
profile: {
name: '张三',
address: {
city: '北京'
}
}
};
console.log(user.profile?.name); // '张三'
console.log(user.profile?.age ?? '未知'); // '未知'
console.log(user.settings?.theme ?? 'default'); // 'default'
// BigInt
const bigNumber = 1234567890123456789012345678901234567890n;
console.log(bigNumber + 1n); // 1234567890123456789012345678901234567891n
// 全局This
console.log(globalThis === window); // 在浏览器中为true
console.log(globalThis === global); // 在Node.js中为true
// 动态导入
async function loadModule() {
const module = await import('./utils.js');
return module.default;
}
// 顶层await (ES2022)
// const data = await fetch('/api/data').then(r => r.json());
Promise与异步编程
Promise是JavaScript中处理异步操作的标准方式,async/await是基于Promise的语法糖,使异步代码更易读写。
Promise方法
| 方法 | 描述 | 语法 | 返回值 | ES版本 |
|---|---|---|---|---|
| Promise.resolve() | 创建已解决的Promise | Promise.resolve(value) |
Promise | ES6 |
| Promise.reject() | 创建已拒绝的Promise | Promise.reject(reason) |
Promise | ES6 |
| Promise.all() | 等待所有Promise完成 | Promise.all(iterable) |
Promise | ES6 |
| Promise.allSettled() | 等待所有Promise完成(无论成功失败) | Promise.allSettled(iterable) |
Promise | ES2020 |
| Promise.race() | 等待第一个完成的Promise | Promise.race(iterable) |
Promise | ES6 |
| Promise.any() | 等待第一个成功的Promise | Promise.any(iterable) |
Promise | ES2021 |
Promise与异步示例
Promise和async/await示例
// 创建Promise
const fetchUserData = (userId) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (userId > 0) {
resolve({ id: userId, name: '张三', age: 25 });
} else {
reject(new Error('用户ID无效'));
}
}, 1000);
});
};
// 使用Promise
fetchUserData(1)
.then(user => {
console.log('用户数据:', user);
return user.age;
})
.then(age => {
console.log('用户年龄:', age);
})
.catch(error => {
console.error('错误:', error.message);
})
.finally(() => {
console.log('请求完成');
});
// async/await
async function getUserInfo(userId) {
try {
console.log('开始获取用户信息...');
const user = await fetchUserData(userId);
console.log('用户信息:', user);
return user;
} catch (error) {
console.error('获取用户信息失败:', error.message);
throw error;
} finally {
console.log('用户信息获取过程结束');
}
}
getUserInfo(1);
// Promise.all - 并行执行多个异步操作
async function fetchMultipleUsers() {
try {
const [user1, user2, user3] = await Promise.all([
fetchUserData(1),
fetchUserData(2),
fetchUserData(3)
]);
console.log('所有用户数据:', user1, user2, user3);
return [user1, user2, user3];
} catch (error) {
console.error('获取用户数据失败:', error);
}
}
// Promise.allSettled - 等待所有Promise完成
async function fetchUsersSettled() {
const results = await Promise.allSettled([
fetchUserData(1),
fetchUserData(-1), // 这个会失败
fetchUserData(3)
]);
const successfulUsers = results
.filter(result => result.status === 'fulfilled')
.map(result => result.value);
const errors = results
.filter(result => result.status === 'rejected')
.map(result => result.reason);
console.log('成功获取的用户:', successfulUsers);
console.log('错误:', errors);
}
// Promise.race - 第一个完成的结果
async function fetchWithTimeout() {
const timeout = new Promise((_, reject) => {
setTimeout(() => reject(new Error('请求超时')), 500);
});
try {
const user = await Promise.race([
fetchUserData(1),
timeout
]);
console.log('获取的用户:', user);
} catch (error) {
console.error('错误:', error.message);
}
}
// Promise.any - 第一个成功的结果
async function fetchFirstSuccessful() {
const promises = [
fetchUserData(-1), // 失败
fetchUserData(2), // 成功
fetchUserData(3) // 成功
];
try {
const user = await Promise.any(promises);
console.log('第一个成功的用户:', user);
} catch (error) {
console.error('所有请求都失败了:', error);
}
}
// 实际应用:顺序执行异步操作
async function processUserData(userId) {
try {
// 1. 获取用户数据
const user = await fetchUserData(userId);
// 2. 获取用户订单
const orders = await fetchUserOrders(user.id);
// 3. 获取用户地址
const addresses = await fetchUserAddresses(user.id);
return {
...user,
orders,
addresses
};
} catch (error) {
console.error('处理用户数据失败:', error);
throw error;
}
}
// 模拟其他API函数
function fetchUserOrders(userId) {
return Promise.resolve([
{ id: 1, product: '手机', price: 2999 },
{ id: 2, product: '耳机', price: 299 }
]);
}
function fetchUserAddresses(userId) {
return Promise.resolve([
{ type: '家', address: '北京市朝阳区' },
{ type: '公司', address: '北京市海淀区' }
]);
}
// 使用示例
processUserData(1).then(userData => {
console.log('完整的用户数据:', userData);
});
// 错误处理最佳实践
async function robustAsyncFunction() {
try {
const result = await someAsyncOperation();
return result;
} catch (error) {
// 记录错误
console.error('异步操作失败:', error);
// 根据错误类型处理
if (error.name === 'NetworkError') {
// 重试逻辑
return retryOperation();
} else if (error.name === 'ValidationError') {
// 返回默认值
return getDefaultValue();
} else {
// 重新抛出未知错误
throw error;
}
}
}
浏览器兼容性参考
了解不同JavaScript特性在主流浏览器中的支持情况。
| 特性 | Chrome | Firefox | Safari | Edge | IE |
|---|---|---|---|---|---|
| ES6 (let/const) | 49+ | 44+ | 10+ | 12+ | 11 (部分) |
| 箭头函数 | 45+ | 22+ | 10+ | 12+ | - |
| Promise | 32+ | 29+ | 8+ | 12+ | - |
| async/await | 55+ | 52+ | 10.1+ | 15+ | - |
| 模块 (import/export) | 61+ | 60+ | 10.1+ | 16+ | - |
| 可选链 (?.) | 80+ | 74+ | 13.1+ | 80+ | - |
| 空值合并 (??) | 80+ | 72+ | 13.1+ | 80+ | - |
| Fetch API | 42+ | 39+ | 10.1+ | 14+ | - |
兼容性提示:
- 对于需要支持旧版浏览器的项目,建议使用Babel等转译工具将现代JavaScript代码转换为兼容性更好的ES5代码。
- 使用polyfill库(如core-js)为旧浏览器提供现代JavaScript特性的支持。
- 利用特性检测(Feature Detection)而不是浏览器检测来编写兼容性代码。
- 考虑使用TypeScript,它可以编译为兼容性更好的JavaScript版本。
JavaScript最佳实践
代码质量
- 使用严格模式 - 在文件或函数开头添加
'use strict' - 避免全局变量 - 使用模块化或IIFE封装代码
- 使用const和let - 优先使用const,需要重新赋值时使用let
- 使用===和!== - 避免类型转换带来的意外行为
- 使用模板字符串 - 替代字符串拼接,提高可读性
性能优化
- 减少DOM操作 - 批量更新DOM或使用文档片段
- 事件委托 - 利用事件冒泡减少事件监听器数量
- 防抖和节流 - 优化频繁触发的事件处理函数
- 避免内存泄漏 - 及时清理事件监听器和定时器
- 使用Web Workers - 将计算密集型任务移到后台线程
安全实践
- 验证用户输入 - 始终在服务器端和客户端验证数据
- 避免eval() - 使用JSON.parse()或其他安全替代方案
- 内容安全策略 - 使用CSP头防止XSS攻击
- HTTPS - 在生产环境中始终使用HTTPS
- 清理HTML - 使用textContent而不是innerHTML插入文本
更多资源
要进一步深入学习JavaScript,可以参考以下资源:
- MDN JavaScript文档 - 最全面的JavaScript参考
- 现代JavaScript教程 - 从基础到高级的完整教程
- ECMAScript 6 入门 - 阮一峰的ES6教程
- You Don't Know JS - 深入的JavaScript系列书籍
- ECMAScript规范 - 官方ECMAScript语言规范
- ECMA-262标准 - ECMAScript语言标准文档