一、JavaScript基础概念
1.1 什么是JavaScript?
JavaScript(简称JS)是一种轻量级的解释型编程语言,主要用于为网页添加交互性。它是Web开发的三大核心技术之一(HTML、CSS、JavaScript)。
1.2 JavaScript的历史
- 1995年:Brendan Eich在10天内创造了JavaScript,最初名为Mocha
- 1996年:改名为LiveScript,最后定名为JavaScript
- 1997年:ECMAScript标准建立
- 2009年:Node.js诞生,JS可在服务器端运行
- 2015年:ES6(ECMAScript 2015)发布,引入大量新特性
- 至今:持续发展和完善,每年都有新版本
1.3 JavaScript的特点
- 解释型语言:无需编译,直接在浏览器中执行
- 动态类型:变量类型在运行时确定
- 函数式编程:支持高阶函数、闭包等特性
- 面向对象:基于原型的面向对象编程
- 跨平台:可在浏览器、Node.js等环境中运行
- 事件驱动:适合处理用户交互和异步操作
1.4 JavaScript的应用场景
- 前端开发:网页交互、动画、表单验证
- 后端开发:Node.js服务器、API开发
- 移动开发:React Native、Ionic
- 桌面应用:Electron
- 小程序开发:微信小程序、支付宝小程序
- 游戏开发:Canvas游戏、WebGL
二、JavaScript基础语法
2.1 JavaScript的引入方式
行内JavaScript
html
<button onclick="alert('Hello!')">点击我</button>
内部JavaScript
html
<script>
console.log('Hello World!');
</script>
外部JavaScript
html
<script src="script.js"></script>
注意:
- script标签通常放在body底部,避免阻塞页面渲染
- 可以使用
defer或async属性优化加载 defer:按顺序加载,在HTML解析完成后执行async:异步加载,加载完成后立即执行
html
<script defer src="script.js"></script>
<script async src="script.js"></script>
2.2 注释
javascript
// 单行注释
/*
* 多行注释
* 可以写多行
*/
/**
* 文档注释
* @param {string} name - 名字
* @returns {string} - 问候语
*/
function greet(name) {
return `Hello, ${name}!`;
}
2.3 语句和分号
javascript
// 使用分号(推荐)
let a = 1;
let b = 2;
let c = a + b;
// 不使用分号(自动插入分号)
let a = 1
let b = 2
let c = a + b
// 建议始终使用分号,避免潜在问题
三、变量和数据类型
3.1 变量声明
javascript
// var - 函数作用域(不推荐)
var name = '张三';
// let - 块级作用域(推荐)
let age = 25;
// const - 常量,块级作用域(推荐)
const PI = 3.14159;
// 不重复声明
let x = 1;
// let x = 2; // 错误:不能重复声明
// 可以重新赋值
x = 3;
// const 声明后不能重新赋值
const y = 1;
// y = 2; // 错误:不能重新赋值
// const 对象可以修改属性
const person = { name: '李四' };
person.name = '王五'; // 正确
// person = {}; // 错误:不能重新赋值
3.2 数据类型
原始类型(Primitive Types)
javascript
// 1. Undefined - 未定义
let undefinedVar;
console.log(undefinedVar); // undefined
// 2. Null - 空值
let nullVar = null;
console.log(nullVar); // null
// 3. Boolean - 布尔值
let isTrue = true;
let isFalse = false;
// 4. Number - 数字
let integer = 42;
let float = 3.14;
let scientific = 1e5; // 100000
let hex = 0xff; // 255
let binary = 0b1010; // 10
let octal = 0o755; // 493
// 特殊数值
let infinity = Infinity;
let negInfinity = -Infinity;
let notANumber = NaN;
// 5. String - 字符串
let str1 = '单引号字符串';
let str2 = "双引号字符串";
let str3 = `模板字符串 ${age}`;
let multiLine = `
多行
字符串
`;
// 6. Symbol - 符号(ES6)
let sym = Symbol('description');
let sym2 = Symbol('description');
console.log(sym === sym2); // false
// 7. BigInt - 大整数(ES2020)
let bigInt = 9007199254740991n;
let bigInt2 = BigInt('9007199254740992');
引用类型(Reference Types)
javascript
// Object - 对象
let obj = {
name: '张三',
age: 25,
sayHello: function() {
console.log('Hello!');
}
};
// Array - 数组
let arr = [1, 2, 3, 'four', { five: 5 }];
// Function - 函数
function myFunction() {
console.log('Function');
}
let arrowFunction = () => {
console.log('Arrow Function');
};
// Date - 日期
let date = new Date();
let date2 = new Date('2026-01-01');
// RegExp - 正则表达式
let regex = /pattern/g;
let regex2 = new RegExp('pattern', 'g');
// Map - 映射(ES6)
let map = new Map();
map.set('key', 'value');
// Set - 集合(ES6)
let set = new Set([1, 2, 3, 3]); // {1, 2, 3}
3.3 类型检测
javascript
// typeof - 检测基本类型
console.log(typeof 42); // "number"
console.log(typeof 'hello'); // "string"
console.log(typeof true); // "boolean"
console.log(typeof undefined); // "undefined"
console.log(typeof null); // "object"(历史原因)
console.log(typeof {}); // "object"
console.log(typeof []); // "object"
console.log(typeof function() {}); // "function"
// instanceof - 检测对象类型
console.log([] instanceof Array); // true
console.log({} instanceof Object); // true
console.log(new Date() instanceof Date); // true
// constructor - 构造函数
console.log([].constructor === Array); // true
// Object.prototype.toString - 最精确的类型检测
function getType(value) {
return Object.prototype.toString.call(value).slice(8, -1);
}
console.log(getType(42)); // "Number"
console.log(getType([])); // "Array"
console.log(getType(null)); // "Null"
console.log(getType(undefined)); // "Undefined"
// 类型转换
// 转为字符串
String(123); // "123"
String(true); // "true"
String(null); // "null"
String(undefined); // "undefined"
123.toString(); // "123"
''.toString(); // ""
// 转为数字
Number('123'); // 123
Number('123abc'); // NaN
Number(''); // 0
Number(true); // 1
Number(false); // 0
Number(null); // 0
Number(undefined); // NaN
parseInt('123'); // 123
parseInt('123abc'); // 123
parseFloat('3.14'); // 3.14
// 转为布尔值
Boolean(0); // false
Boolean(''); // false
Boolean(null); // false
Boolean(undefined); // false
Boolean(NaN); // false
Boolean(false); // false
// 其他都是true
Boolean(1); // true
Boolean('hello'); // true
Boolean([]); // true
Boolean({}); // true
四、运算符
4.1 算术运算符
javascript
let a = 10;
let b = 3;
a + b; // 13 - 加法
a - b; // 7 - 减法
a * b; // 30 - 乘法
a / b; // 3.333... - 除法
a % b; // 1 - 取余
a ** b; // 1000 - 幂运算(ES6)
// 自增自减
let x = 5;
x++; // 6 - 后置自增(先返回后自增)
++x; // 7 - 前置自增(先自增后返回)
x--; // 6 - 后置自减
--x; // 5 - 前置自减
// 字符串拼接
'Hello' + ' ' + 'World'; // "Hello World"
4.2 比较运算符
javascript
// 相等
1 == 1; // true
1 == '1'; // true(类型转换)
1 === 1; // true(严格相等)
1 === '1'; // false(类型不同)
// 不等
1 != 2; // true
1 != '1'; // false
1 !== 2; // true
1 !== '1'; // true
// 大于
5 > 3; // true
5 >= 5; // true
// 小于
3 < 5; // true
5 <= 5; // true
// Object.is - 严格相等(处理特殊情况)
Object.is(NaN, NaN); // true
Object.is(+0, -0); // false
4.3 逻辑运算符
javascript
// 逻辑与
true && true; // true
true && false; // false
false && true; // false
false && false; // false
// 短路求值
let a = 1;
let b = a > 0 && a < 10; // true
let c = a > 10 && console.log('不会执行'); // undefined
// 逻辑或
true || true; // true
true || false; // true
false || true; // true
false || false; // false
// 短路求值
let d = a > 0 || a < 0; // true
let e = a > 10 || console.log('会执行'); // 会执行
// 逻辑非
!true; // false
!false; // true
// 空值合并运算符(ES2020)
let f = null ?? 'default'; // 'default'
let g = undefined ?? 'default'; // 'default'
let h = 0 ?? 'default'; // 0
let i = '' ?? 'default'; // ''
// 可选链运算符(ES2020)
let user = { profile: { name: '张三' } };
user?.profile?.name; // '张三'
user?.address?.city; // undefined
4.4 赋值运算符
javascript
let a = 10;
a += 5; // a = a + 5; 15
a -= 3; // a = a - 3; 12
a *= 2; // a = a * 2; 24
a /= 4; // a = a / 4; 6
a %= 4; // a = a % 4; 2
a **= 3; // a = a ** 3; 8
// 解构赋值
let [x, y] = [1, 2];
console.log(x, y); // 1, 2
let { name, age } = { name: '张三', age: 25 };
console.log(name, age); // '张三', 25
4.5 位运算符
javascript
let a = 5; // 二进制: 101
let b = 3; // 二进制: 011
// 按位与
a & b; // 1 (001)
// 按位或
a | b; // 7 (111)
// 按位异或
a ^ b; // 6 (110)
// 按位非
~a; // -6
// 左移
a << 1; // 10 (1010)
// 右移
a >> 1; // 2 (10)
// 无符号右移
a >>> 1; // 2 (10)
4.6 条件运算符
javascript
// 三元运算符
let age = 18;
let canVote = age >= 18 ? '可以投票' : '不能投票';
console.log(canVote); // '可以投票'
// 链式三元运算符
let score = 85;
let grade = score >= 90 ? 'A' :
score >= 80 ? 'B' :
score >= 70 ? 'C' :
score >= 60 ? 'D' : 'F';
console.log(grade); // 'B'
五、控制流程
5.1 条件语句
javascript
// if-else
let score = 85;
if (score >= 90) {
console.log('优秀');
} else if (score >= 80) {
console.log('良好');
} else if (score >= 60) {
console.log('及格');
} else {
console.log('不及格');
}
// switch
let day = '星期一';
switch (day) {
case '星期一':
console.log('工作日');
break;
case '星期二':
console.log('工作日');
break;
case '星期六':
case '星期日':
console.log('周末');
break;
default:
console.log('未知');
}
// switch 的严格相等
let x = '10';
switch (x) {
case 10:
console.log('数字10');
break;
case '10':
console.log('字符串10'); // 输出这个
break;
}
5.2 循环语句
javascript
// for循环
for (let i = 0; i < 5; i++) {
console.log(i);
}
// for-in循环(遍历对象属性)
let obj = { a: 1, b: 2, c: 3 };
for (let key in obj) {
console.log(key, obj[key]);
}
// for-of循环(遍历可迭代对象)
let arr = [1, 2, 3, 4, 5];
for (let value of arr) {
console.log(value);
}
// while循环
let i = 0;
while (i < 5) {
console.log(i);
i++;
}
// do-while循环
let j = 0;
do {
console.log(j);
j++;
} while (j < 5);
// break和continue
for (let i = 0; i < 10; i++) {
if (i === 3) {
continue; // 跳过3
}
if (i === 7) {
break; // 退出循环
}
console.log(i);
}
// 标签循环
outer: for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
if (i === 1 && j === 1) {
break outer; // 退出外层循环
}
console.log(i, j);
}
}
5.3 异常处理
javascript
// try-catch-finally
try {
// 可能出错的代码
let result = 10 / 0;
console.log(result);
} catch (error) {
// 捕获错误
console.error('发生错误:', error.message);
} finally {
// 无论是否出错都会执行
console.log('清理资源');
}
// 抛出错误
function divide(a, b) {
if (b === 0) {
throw new Error('除数不能为0');
}
return a / b;
}
try {
divide(10, 0);
} catch (error) {
console.error(error.message);
}
// 错误类型
new Error('普通错误');
new TypeError('类型错误');
new ReferenceError('引用错误');
new SyntaxError('语法错误');
new RangeError('范围错误');
new URIError('URI错误');
new EvalError('Eval错误');
六、函数
6.1 函数定义
javascript
// 函数声明
function greet(name) {
return `Hello, ${name}!`;
}
// 函数表达式
const greet2 = function(name) {
return `Hello, ${name}!`;
};
// 箭头函数(ES6)
const greet3 = (name) => {
return `Hello, ${name}!`;
};
// 箭头函数简写
const greet4 = name => `Hello, ${name}!`;
// 箭头函数多个参数
const add = (a, b) => a + b;
// 箭头函数返回对象(需要括号)
const createUser = (name, age) => ({ name, age });
// 立即执行函数
(function() {
console.log('立即执行');
})();
// 箭头函数版本的立即执行函数
(() => {
console.log('立即执行');
})();
// 函数构造器(不推荐)
const greet5 = new Function('name', 'return `Hello, ${name}!`');
6.2 函数参数
javascript
// 默认参数
function greet(name = 'World') {
return `Hello, ${name}!`;
}
greet(); // 'Hello, World!'
// 剩余参数
function sum(...numbers) {
return numbers.reduce((acc, num) => acc + num, 0);
}
sum(1, 2, 3, 4, 5); // 15
// 参数解构
function greetUser({ name, age }) {
console.log(`${name}, ${age}岁`);
}
greetUser({ name: '张三', age: 25 });
// 结合默认参数和解构
function createUser({ name = '匿名', age = 0 } = {}) {
return { name, age };
}
createUser(); // { name: '匿名', age: 0 }
createUser({ name: '李四' }); // { name: '李四', age: 0 }
6.3 作用域和闭包
javascript
// 函数作用域
function outer() {
let outerVar = 'outer';
function inner() {
let innerVar = 'inner';
console.log(outerVar); // 可以访问外部变量
console.log(innerVar);
}
inner();
// console.log(innerVar); // 错误:无法访问内部变量
}
// 块级作用域
{
let blockVar = 'block';
console.log(blockVar);
}
// console.log(blockVar); // 错误:无法访问
// 闭包
function createCounter() {
let count = 0;
return {
increment: function() {
count++;
return count;
},
decrement: function() {
count--;
return count;
},
getCount: function() {
return count;
}
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
console.log(counter.decrement()); // 1
console.log(counter.getCount()); // 1
// 闭包应用:模拟私有变量
function createPerson(name) {
let _name = name;
return {
getName: function() {
return _name;
},
setName: function(newName) {
_name = newName;
}
};
}
const person = createPerson('张三');
console.log(person.getName()); // '张三'
person.setName('李四');
console.log(person.getName()); // '李四'
// console.log(_name); // 错误:无法直接访问
6.4 this关键字
javascript
// 方法中的this
const person = {
name: '张三',
greet: function() {
console.log(`Hello, ${this.name}`);
}
};
person.greet(); // 'Hello, 张三'
// 箭头函数中的this(继承外层作用域)
const person2 = {
name: '李四',
greet: () => {
console.log(`Hello, ${this.name}`);
}
};
person2.greet(); // 'Hello, undefined'
// 箭头函数在对象方法中的正确用法
const person3 = {
name: '王五',
greet: function() {
setTimeout(() => {
console.log(`Hello, ${this.name}`);
}, 1000);
}
};
person3.greet(); // 'Hello, 王五'
// call、apply、bind
function greet(greeting, punctuation) {
console.log(`${greeting}, ${this.name}${punctuation}`);
}
const person4 = { name: '赵六' };
greet.call(person4, 'Hello', '!'); // 'Hello, 赵六!'
greet.apply(person4, ['Hi', '.']); // 'Hi, 赵六.'
const greetBound = greet.bind(person4, 'Hey');
greetBound('~'); // 'Hey, 赵六~'
6.5 高阶函数
javascript
// 函数作为参数
function execute(fn) {
fn();
}
execute(function() {
console.log('执行函数');
});
// 函数作为返回值
function createMultiplier(factor) {
return function(number) {
return number * factor;
};
}
const double = createMultiplier(2);
const triple = createMultiplier(3);
console.log(double(5)); // 10
console.log(triple(5)); // 15
// 回调函数
function fetchData(callback) {
setTimeout(() => {
const data = { name: '张三', age: 25 };
callback(data);
}, 1000);
}
fetchData(function(data) {
console.log(data);
});
// 数组高阶函数
const numbers = [1, 2, 3, 4, 5];
// map
const doubled = numbers.map(n => n * 2);
console.log(doubled); // [2, 4, 6, 8, 10]
// filter
const evens = numbers.filter(n => n % 2 === 0);
console.log(evens); // [2, 4]
// reduce
const sum = numbers.reduce((acc, n) => acc + n, 0);
console.log(sum); // 15
// find
const found = numbers.find(n => n > 3);
console.log(found); // 4
// 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
// forEach
numbers.forEach(n => console.log(n));
七、对象和数组
7.1 对象
javascript
// 对象字面量
const person = {
name: '张三',
age: 25,
greet: function() {
console.log(`Hello, ${this.name}`);
}
};
// 访问属性
person.name; // '张三'
person['age']; // 25
// 添加属性
person.city = '北京';
person['country'] = '中国';
// 删除属性
delete person.city;
// 检查属性
'name' in person; // true
person.hasOwnProperty('name'); // true
// 对象方法
Object.keys(person); // ['name', 'age', 'greet']
Object.values(person); // ['张三', 25, function]
Object.entries(person); // [['name', '张三'], ['age', 25], ['greet', function]]
// 对象解构
const { name, age } = person;
const { name: personName, age: personAge } = person;
// 对象展开运算符
const newPerson = { ...person, city: '上海' };
// 对象合并
const obj1 = { a: 1, b: 2 };
const obj2 = { c: 3, d: 4 };
const merged = { ...obj1, ...obj2 };
// 计算属性名
const key = 'dynamic';
const obj = {
[key]: 'value',
[`prop_${Date.now()}`]: 'timestamp'
};
// getter和setter
const user = {
_name: '张三',
get name() {
return this._name;
},
set name(value) {
this._name = value;
}
};
user.name; // '张三'
user.name = '李四';
user.name; // '李四'
// 对象冻结(不可修改)
const frozen = Object.freeze({ a: 1 });
// frozen.a = 2; // 错误(严格模式下)
// 对象密封(不能添加或删除属性)
const sealed = Object.seal({ a: 1 });
sealed.b = 2; // 错误
delete sealed.a; // 错误
sealed.a = 2; // 正确
7.2 数组
javascript
// 数组创建
const arr1 = [1, 2, 3];
const arr2 = new Array(1, 2, 3);
const arr3 = Array.of(1, 2, 3);
const arr4 = Array(3); // [empty × 3]
// 数组访问
arr1[0]; // 1
arr1[arr1.length - 1]; // 3
// 数组长度
arr1.length; // 3
// 添加元素
arr1.push(4); // 尾部添加
arr1.unshift(0); // 头部添加
// 删除元素
arr1.pop(); // 尾部删除
arr1.shift(); // 头部删除
// 数组方法
// splice - 删除/插入/替换
const arr = [1, 2, 3, 4, 5];
arr.splice(2, 1); // 删除索引2的元素 -> [1, 2, 4, 5]
arr.splice(2, 0, 3); // 在索引2处插入3 -> [1, 2, 3, 4, 5]
arr.splice(2, 1, 99); // 替换索引2的元素 -> [1, 2, 99, 4, 5]
// slice - 切片
const sliced = arr.slice(1, 3); // [2, 99]
// concat - 连接
const arrA = [1, 2];
const arrB = [3, 4];
const arrC = arrA.concat(arrB); // [1, 2, 3, 4]
// join - 连接成字符串
const str = [1, 2, 3].join('-'); // '1-2-3'
// reverse - 反转
const reversed = [1, 2, 3].reverse(); // [3, 2, 1]
// sort - 排序
const nums = [3, 1, 4, 1, 5, 9, 2, 6];
nums.sort(); // [1, 1, 2, 3, 4, 5, 6, 9](按字符串排序)
nums.sort((a, b) => a - b); // [1, 1, 2, 3, 4, 5, 6, 9](按数字排序)
// indexOf / lastIndexOf - 查找索引
const fruits = ['苹果', '香蕉', '橙子'];
fruits.indexOf('香蕉'); // 1
fruits.indexOf('葡萄'); // -1
fruits.lastIndexOf('苹果'); // 0
// includes - 检查是否包含
fruits.includes('香蕉'); // true
fruits.includes('葡萄'); // false
// find - 查找元素
const users = [
{ id: 1, name: '张三' },
{ id: 2, name: '李四' }
];
const user = users.find(u => u.id === 2); // { id: 2, name: '李四' }
// findIndex - 查找索引
const index = users.findIndex(u => u.id === 2); // 1
// forEach - 遍历
[1, 2, 3].forEach((item, index) => {
console.log(index, item);
});
// map - 映射
const doubled = [1, 2, 3].map(n => n * 2); // [2, 4, 6]
// filter - 过滤
const evens = [1, 2, 3, 4, 5].filter(n => n % 2 === 0); // [2, 4]
// reduce - 归约
const sum = [1, 2, 3, 4, 5].reduce((acc, n) => acc + n, 0); // 15
// some - 是否有满足条件的
const hasEven = [1, 3, 5, 7, 8].some(n => n % 2 === 0); // true
// every - 是否都满足条件
const allPositive = [1, 2, 3, 4, 5].every(n => n > 0); // true
// 数组解构
const [first, second, ...rest] = [1, 2, 3, 4, 5];
console.log(first, second, rest); // 1, 2, [3, 4, 5]
// 数组展开运算符
const arrA = [1, 2];
const arrB = [...arrA, 3, 4]; // [1, 2, 3, 4]
// Array.from - 从类数组创建数组
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
Array.from(arrayLike); // ['a', 'b']
// Array.isArray - 检查是否为数组
Array.isArray([1, 2, 3]); // true
Array.isArray({}); // false
// 数组扁平化
const nested = [1, [2, [3, [4]]]];
nested.flat(Infinity); // [1, 2, 3, 4]
// 数组去重
const unique = [1, 2, 2, 3, 3, 4];
[...new Set(unique)]; // [1, 2, 3, 4]
八、ES6+新特性
8.1 let和const
javascript
// let - 块级作用域
for (let i = 0; i < 3; i++) {
console.log(i); // 0, 1, 2
}
// console.log(i); // 错误:i不存在
// const - 常量
const PI = 3.14159;
// PI = 3.14; // 错误:不能重新赋值
// const 对象
const person = { name: '张三' };
person.name = '李四'; // 正确
// person = {}; // 错误:不能重新赋值
8.2 箭头函数
javascript
// 基本语法
const add = (a, b) => a + b;
// 单参数
const square = x => x * x;
// 多行代码
const greet = name => {
const greeting = `Hello, ${name}!`;
return greeting;
};
// 返回对象(需要括号)
const createPerson = (name, age) => ({ name, age });
// 箭头函数不绑定this
const obj = {
name: '张三',
greet: function() {
setTimeout(() => {
console.log(this.name); // '张三'
}, 1000);
}
};
8.3 模板字符串
javascript
const name = '张三';
const age = 25;
// 基本用法
const greeting = `Hello, ${name}!`;
console.log(greeting); // 'Hello, 张三!'
// 多行字符串
const message = `
你好,${name}
今年${age}岁
`;
// 表达式
const result = `${name} ${age > 18 ? '成年' : '未成年'}`;
// 标签模板
function highlight(strings, ...values) {
return strings.reduce((result, str, i) => {
return result + str + (values[i] ? `<strong>${values[i]}</strong>` : '');
}, '');
}
const highlighted = highlight`Hello, ${name}!`;
// 'Hello, <strong>张三</strong>!'
8.4 解构赋值
javascript
// 数组解构
const [a, b, c] = [1, 2, 3];
const [first, , third] = [1, 2, 3];
const [x, y, ...rest] = [1, 2, 3, 4, 5];
// 对象解构
const { name, age } = { name: '张三', age: 25 };
const { name: personName, age: personAge } = { name: '张三', age: 25 };
// 默认值
const { city = '北京' } = { name: '张三' };
// 函数参数解构
function greet({ name, age }) {
console.log(`${name}, ${age}岁`);
}
greet({ name: '张三', age: 25 });
// 嵌套解构
const user = {
profile: {
name: '张三',
age: 25
},
address: {
city: '北京'
}
};
const { profile: { name, age }, address: { city } } = user;
8.5 展开运算符
javascript
// 数组展开
const arr1 = [1, 2, 3];
const arr2 = [...arr1, 4, 5]; // [1, 2, 3, 4, 5]
// 对象展开
const obj1 = { a: 1, b: 2 };
const obj2 = { ...obj1, c: 3 }; // { a: 1, b: 2, c: 3 }
// 函数参数展开
function sum(...numbers) {
return numbers.reduce((acc, n) => acc + n, 0);
}
sum(1, 2, 3, 4, 5); // 15
// 数组合并
const merged = [...arr1, ...[4, 5]]; // [1, 2, 3, 4, 5]
// 对象合并
const mergedObj = { ...obj1, ...{ c: 3, d: 4 } };
8.6 Promise和async/await
javascript
// Promise基础
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
resolve('成功');
}, 1000);
});
promise.then(result => {
console.log(result); // '成功'
}).catch(error => {
console.error(error);
});
// Promise链
promise
.then(result => result + '!')
.then(result => result + '!!')
.then(result => console.log(result)); // '成功!!'
// Promise.all
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
Promise.all([promise1, promise2, promise3])
.then(results => console.log(results)); // [1, 2, 3]
// Promise.race
Promise.race([promise1, promise2, promise3])
.then(result => console.log(result)); // 1(最先完成的)
// async/await
async function fetchData() {
try {
const result = await promise;
console.log(result); // '成功'
} catch (error) {
console.error(error);
}
}
fetchData();
// async函数返回Promise
async function asyncFunction() {
return '返回值';
}
asyncFunction().then(result => console.log(result)); // '返回值'
// 并行执行
async function parallel() {
const [result1, result2] = await Promise.all([
promise1,
promise2
]);
console.log(result1, result2); // 1, 2
}
parallel();
8.7 Class类
javascript
// 基本类
class Person {
constructor(name, age) {
this.name = name;
this.age = age;
}
greet() {
console.log(`Hello, ${this.name}!`);
}
static createAnonymous() {
return new Person('匿名', 0);
}
}
const person = new Person('张三', 25);
person.greet(); // 'Hello, 张三!'
const anonymous = Person.createAnonymous();
// 继承
class Student extends Person {
constructor(name, age, grade) {
super(name, age);
this.grade = grade;
}
study() {
console.log(`${this.name}正在学习`);
}
greet() {
super.greet();
console.log(`我是${this.grade}年级学生`);
}
}
const student = new Student('李四', 20, 3);
student.greet(); // 'Hello, 李四!' '我是3年级学生'
student.study(); // '李四正在学习'
// Getter和Setter
class User {
constructor(name) {
this._name = name;
}
get name() {
return this._name;
}
set name(value) {
this._name = value;
}
}
const user = new User('张三');
console.log(user.name); // '张三'
user.name = '李四';
console.log(user.name); // '李四'
8.8 模块化
javascript
// 导出
// math.js
export const PI = 3.14159;
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// 默认导出
export default function multiply(a, b) {
return a * b;
}
// 导入
// main.js
import multiply, { PI, add, subtract } from './math.js';
import * as math from './math.js';
console.log(PI); // 3.14159
console.log(add(1, 2)); // 3
console.log(multiply(3, 4)); // 12
console.log(math.subtract(5, 3)); // 2
8.9 其他新特性
javascript
// Symbol
const sym = Symbol('description');
const obj = { [sym]: 'value' };
// Proxy
const handler = {
get: function(target, property) {
console.log(`Getting ${property}`);
return target[property];
},
set: function(target, property, value) {
console.log(`Setting ${property} to ${value}`);
target[property] = value;
}
};
const proxy = new Proxy({}, handler);
proxy.name = '张三'; // 'Setting name to 张三'
console.log(proxy.name); // 'Getting name' '张三'
// Reflect
const obj = { name: '张三' };
Reflect.get(obj, 'name'); // '张三'
Reflect.set(obj, 'age', 25); // true
// Map
const map = new Map();
map.set('key', 'value');
map.get('key'); // 'value'
map.has('key'); // true
map.delete('key'); // true
// Set
const set = new Set([1, 2, 3, 3]);
set.add(4);
set.has(3); // true
set.delete(3); // true
// WeakMap
const weakMap = new WeakMap();
const key = {};
weakMap.set(key, 'value');
weakMap.get(key); // 'value'
// WeakSet
const weakSet = new WeakSet();
const obj = {};
weakSet.add(obj);
weakSet.has(obj); // true
// Array.from
Array.from([1, 2, 3]); // [1, 2, 3]
Array.from('hello'); // ['h', 'e', 'l', 'l', 'o']
// Array.of
Array.of(1, 2, 3); // [1, 2, 3]
// Object.assign
const target = { a: 1 };
const source = { b: 2 };
Object.assign(target, source); // { a: 1, b: 2 }
// Object.is
Object.is(NaN, NaN); // true
Object.is(+0, -0); // false
// 字符串方法
'hello'.includes('ell'); // true
'hello'.startsWith('he'); // true
'hello'.endsWith('lo'); // true
'hello'.repeat(3); // 'hellohellohello'
'hello'.padStart(10, '='); // '=====hello'
'hello'.padEnd(10, '='); // 'hello====='
// 数组方法
[1, 2, 3].includes(2); // true
[1, 2, 3].findIndex(x => x > 1); // 1
[1, 2, 3].copyWithin(0, 2); // [3, 2, 3]
// 数组填充
new Array(5).fill(0); // [0, 0, 0, 0, 0]
// 指数运算符
2 ** 3; // 8
Math.pow(2, 3); // 8
九、DOM操作
9.1 选择元素
javascript
// 选择单个元素
document.getElementById('myId');
document.querySelector('.myClass');
document.querySelector('div > p');
// 选择多个元素
document.getElementsByClassName('myClass'); // HTMLCollection
document.getElementsByTagName('div'); // HTMLCollection
document.querySelectorAll('.myClass'); // NodeList
// 遍历NodeList
document.querySelectorAll('.item').forEach(item => {
console.log(item);
});
9.2 修改元素
javascript
// 获取和设置属性
const element = document.getElementById('myId');
element.getAttribute('class');
element.setAttribute('class', 'newClass');
element.removeAttribute('class');
// 获取和设置样式
element.style.color = 'red';
element.style.backgroundColor = 'blue';
element.style.fontSize = '16px';
// class操作
element.classList.add('active');
element.classList.remove('inactive');
element.classList.toggle('active');
element.classList.contains('active');
// 修改内容
element.textContent = '文本内容';
element.innerHTML = '<strong>HTML内容</strong>';
element.innerText = '文本内容';
// 修改value(表单元素)
const input = document.getElementById('myInput');
input.value = '新值';
9.3 创建和删除元素
javascript
// 创建元素
const newElement = document.createElement('div');
newElement.textContent = '新元素';
newElement.classList.add('new-item');
// 添加元素
document.body.appendChild(newElement);
document.body.insertBefore(newElement, document.body.firstChild);
// 删除元素
const oldElement = document.getElementById('oldId');
oldElement.remove();
// 或
oldElement.parentNode.removeChild(oldElement);
// 替换元素
const parent = document.getElementById('parent');
const newElement = document.createElement('div');
const oldElement = document.getElementById('oldId');
parent.replaceChild(newElement, oldElement);
// 克隆元素
const cloned = element.cloneNode(true); // true表示克隆子节点
9.4 事件处理
javascript
// 添加事件监听
const button = document.getElementById('myButton');
button.addEventListener('click', function(event) {
console.log('按钮被点击');
console.log(event);
});
// 移除事件监听
function handleClick(event) {
console.log('按钮被点击');
}
button.addEventListener('click', handleClick);
button.removeEventListener('click', handleClick);
// 事件对象
button.addEventListener('click', function(event) {
event.preventDefault(); // 阻止默认行为
event.stopPropagation(); // 阻止事件冒泡
console.log(event.target); // 触发事件的元素
console.log(event.currentTarget); // 绑定事件的元素
});
// 常用事件类型
button.addEventListener('click', handler); // 点击
input.addEventListener('input', handler); // 输入
input.addEventListener('change', handler); // 改变
form.addEventListener('submit', handler); // 提交
window.addEventListener('load', handler); // 加载完成
window.addEventListener('resize', handler); // 窗口大小改变
window.addEventListener('scroll', handler); // 滚动
// 事件委托
document.getElementById('list').addEventListener('click', function(event) {
if (event.target.classList.contains('item')) {
console.log('列表项被点击');
}
});
9.5 DOM遍历
javascript
// 父子关系
element.parentNode; // 父节点
element.parentElement; // 父元素
element.childNodes; // 所有子节点
element.children; // 所有子元素
element.firstChild; // 第一个子节点
element.firstElementChild; // 第一个子元素
element.lastChild; // 最后一个子节点
element.lastElementChild; // 最后一个子元素
// 兄弟关系
element.previousSibling; // 前一个兄弟节点
element.previousElementSibling; // 前一个兄弟元素
element.nextSibling; // 后一个兄弟节点
element.nextElementSibling; // 后一个兄弟元素
// 查找元素
element.querySelector('.class');
element.querySelectorAll('.class');
element.closest('.parent'); // 查找最近的祖先元素
十、异步编程
10.1 回调函数
javascript
// 基本回调
function fetchData(callback) {
setTimeout(() => {
const data = { name: '张三', age: 25 };
callback(data);
}, 1000);
}
fetchData(function(data) {
console.log(data);
});
// 回调地狱(不推荐)
fetchData(function(data1) {
fetchData(function(data2) {
fetchData(function(data3) {
console.log(data1, data2, data3);
});
});
});
10.2 Promise
javascript
// 创建Promise
const promise = new Promise((resolve, reject) => {
setTimeout(() => {
const success = true;
if (success) {
resolve('成功');
} else {
reject('失败');
}
}, 1000);
});
// 使用Promise
promise
.then(result => {
console.log(result);
return result + '!';
})
.then(result => {
console.log(result);
})
.catch(error => {
console.error(error);
})
.finally(() => {
console.log('完成');
});
// Promise链
function fetchUser(id) {
return new Promise(resolve => {
setTimeout(() => {
resolve({ id, name: '张三' });
}, 1000);
});
}
function fetchPosts(userId) {
return new Promise(resolve => {
setTimeout(() => {
resolve([
{ id: 1, userId, title: '文章1' },
{ id: 2, userId, title: '文章2' }
]);
}, 1000);
});
}
fetchUser(1)
.then(user => fetchPosts(user.id))
.then(posts => console.log(posts))
.catch(error => console.error(error));
// Promise.all
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
Promise.all([promise1, promise2, promise3])
.then(results => console.log(results)); // [1, 2, 3]
// Promise.race
Promise.race([promise1, promise2, promise3])
.then(result => console.log(result)); // 1
// Promise.allSettled
Promise.allSettled([
Promise.resolve(1),
Promise.reject(2),
Promise.resolve(3)
]).then(results => {
console.log(results);
// [
// { status: 'fulfilled', value: 1 },
// { status: 'rejected', reason: 2 },
// { status: 'fulfilled', value: 3 }
// ]
});
10.3 async/await
javascript
// 基本用法
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchData();
// async函数返回Promise
async function asyncFunction() {
return '返回值';
}
asyncFunction().then(result => console.log(result)); // '返回值'
// 并行执行
async function parallel() {
const [result1, result2] = await Promise.all([
fetchUser(1),
fetchUser(2)
]);
console.log(result1, result2);
}
// 顺序执行
async function sequential() {
const user1 = await fetchUser(1);
const user2 = await fetchUser(2);
console.log(user1, user2);
}
// 错误处理
async function withErrorHandling() {
try {
const data = await fetchData();
return data;
} catch (error) {
console.error('发生错误:', error);
return null;
} finally {
console.log('清理资源');
}
}
10.4 Generator函数
javascript
// 基本用法
function* generator() {
yield 1;
yield 2;
yield 3;
}
const gen = generator();
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
// 生成器函数
function* fibonacci() {
let [a, b] = [0, 1];
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
const fib = fibonacci();
console.log(fib.next().value); // 0
console.log(fib.next().value); // 1
console.log(fib.next().value); // 1
console.log(fib.next().value); // 2
// for...of遍历
for (const num of fibonacci()) {
if (num > 100) break;
console.log(num);
}
十一、错误处理
11.1 try-catch-finally
javascript
try {
// 可能出错的代码
const result = 10 / 0;
console.log(result);
} catch (error) {
// 捕获错误
console.error('发生错误:', error.message);
} finally {
// 无论是否出错都会执行
console.log('清理资源');
}
11.2 错误类型
javascript
// Error - 基础错误
throw new Error('普通错误');
// TypeError - 类型错误
throw new TypeError('类型错误');
// ReferenceError - 引用错误
throw new ReferenceError('引用错误');
// SyntaxError - 语法错误
throw new SyntaxError('语法错误');
// RangeError - 范围错误
throw new RangeError('范围错误');
// URIError - URI错误
throw new URIError('URI错误');
// EvalError - Eval错误
throw new EvalError('Eval错误');
11.3 自定义错误
javascript
class CustomError extends Error {
constructor(message) {
super(message);
this.name = 'CustomError';
}
}
throw new CustomError('自定义错误');
11.4 全局错误处理
javascript
// 捕获未处理的Promise错误
window.addEventListener('unhandledrejection', event => {
console.error('未处理的Promise错误:', event.reason);
});
// 捕获全局错误
window.addEventListener('error', event => {
console.error('全局错误:', event.error);
});
十二、JavaScript最佳实践
12.1 代码规范
javascript
// 使用const和let,避免var
const PI = 3.14159;
let count = 0;
// 使用语义化的变量名
const userName = '张三';
const userAge = 25;
// 使用一致的命名风格
const firstName = '张';
const lastName = '三';
const fullName = `${firstName}${lastName}`;
// 函数名使用动词开头
function getUserData() { }
function validateInput() { }
function handleSubmit() { }
// 避免全局变量
// ❌ 不好
globalVar = 'value';
// ✅ 好
const myModule = {
localVar: 'value'
};
// 使用严格模式
'use strict';
// 避免使用eval和with
// ❌ 不好
eval('console.log("hello")');
// ✅ 好
console.log('hello');
12.2 性能优化
javascript
// 避免在循环中创建函数
// ❌ 不好
for (let i = 0; i < 1000; i++) {
document.getElementById('item' + i).addEventListener('click', function() {
console.log(i);
});
}
// ✅ 好
function handleClick(i) {
return function() {
console.log(i);
};
}
for (let i = 0; i < 1000; i++) {
document.getElementById('item' + i).addEventListener('click', handleClick(i));
}
// 使用事件委托
document.getElementById('list').addEventListener('click', function(event) {
if (event.target.classList.contains('item')) {
console.log('列表项被点击');
}
});
// 避免频繁的DOM操作
// ❌ 不好
for (let i = 0; i < 1000; i++) {
document.body.innerHTML += '<div>Item ' + i + '</div>';
}
// ✅ 好
let html = '';
for (let i = 0; i < 1000; i++) {
html += '<div>Item ' + i + '</div>';
}
document.body.innerHTML = html;
// 使用文档片段
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = 'Item ' + i;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
// 防抖和节流
// 防抖
function debounce(func, wait) {
let timeout;
return function(...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), wait);
};
}
window.addEventListener('resize', debounce(function() {
console.log('窗口大小改变');
}, 300));
// 节流
function throttle(func, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
func.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
window.addEventListener('scroll', throttle(function() {
console.log('滚动');
}, 300));
12.3 安全性
javascript
// 避免innerHTML,使用textContent
// ❌ 不好
element.innerHTML = userInput;
// ✅ 好
element.textContent = userInput;
// 输入验证
function validateInput(input) {
// 去除HTML标签
const sanitized = input.replace(/<[^>]*>/g, '');
// 限制长度
return sanitized.substring(0, 100);
}
// 防止XSS
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&")
.replace(/</g, "<")
.replace(/>/g, ">")
.replace(/"/g, """)
.replace(/'/g, "'");
}
// 使用HTTPS
// API请求使用HTTPS
fetch('https://api.example.com/data');
// 验证API响应
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('网络响应不正常');
}
const data = await response.json();
// 验证数据结构
if (!data || typeof data !== 'object') {
throw new Error('无效的数据格式');
}
return data;
} catch (error) {
console.error('获取数据失败:', error);
throw error;
}
}
12.4 可维护性
javascript
// 模块化
// utils.js
export function formatDate(date) {
return date.toISOString();
}
export function validateEmail(email) {
const regex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return regex.test(email);
}
// api.js
import { formatDate } from './utils.js';
export async function fetchUserData(userId) {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
return {
...data,
formattedDate: formatDate(new Date(data.createdAt))
};
}
// 使用注释
/**
* 计算两个数字的和
* @param {number} a - 第一个数字
* @param {number} b - 第二个数字
* @returns {number} 两个数字的和
*/
function add(a, b) {
return a + b;
}
// 使用常量
const API_URL = 'https://api.example.com';
const MAX_RETRY_COUNT = 3;
const TIMEOUT_MS = 5000;
// 错误处理
async function fetchData() {
try {
const response = await fetch(API_URL);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
} catch (error) {
console.error('获取数据失败:', error);
throw error;
}
}
十三、实战示例
13.1 待办事项应用
javascript
class TodoApp {
constructor() {
this.todos = [];
this.init();
}
init() {
this.loadTodos();
this.render();
this.bindEvents();
}
loadTodos() {
const stored = localStorage.getItem('todos');
if (stored) {
this.todos = JSON.parse(stored);
}
}
saveTodos() {
localStorage.setItem('todos', JSON.stringify(this.todos));
}
addTodo(text) {
const todo = {
id: Date.now(),
text,
completed: false,
createdAt: new Date().toISOString()
};
this.todos.push(todo);
this.saveTodos();
this.render();
}
toggleTodo(id) {
const todo = this.todos.find(t => t.id === id);
if (todo) {
todo.completed = !todo.completed;
this.saveTodos();
this.render();
}
}
deleteTodo(id) {
this.todos = this.todos.filter(t => t.id !== id);
this.saveTodos();
this.render();
}
render() {
const todoList = document.getElementById('todoList');
todoList.innerHTML = '';
this.todos.forEach(todo => {
const li = document.createElement('li');
li.className = `todo-item ${todo.completed ? 'completed' : ''}`;
li.innerHTML = `
<input type="checkbox" ${todo.completed ? 'checked' : ''}>
<span>${todo.text}</span>
<button class="delete-btn">删除</button>
`;
li.querySelector('input').addEventListener('change', () => {
this.toggleTodo(todo.id);
});
li.querySelector('.delete-btn').addEventListener('click', () => {
this.deleteTodo(todo.id);
});
todoList.appendChild(li);
});
}
bindEvents() {
const form = document.getElementById('todoForm');
form.addEventListener('submit', (e) => {
e.preventDefault();
const input = document.getElementById('todoInput');
const text = input.value.trim();
if (text) {
this.addTodo(text);
input.value = '';
}
});
}
}
// 初始化应用
const app = new TodoApp();
13.2 API请求封装
javascript
class ApiClient {
constructor(baseURL) {
this.baseURL = baseURL;
this.defaultHeaders = {
'Content-Type': 'application/json'
};
}
async request(endpoint, options = {}) {
const url = `${this.baseURL}${endpoint}`;
const config = {
...options,
headers: {
...this.defaultHeaders,
...options.headers
}
};
try {
const response = await fetch(url, config);
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error('API请求失败:', error);
throw error;
}
}
get(endpoint, params = {}) {
const queryString = new URLSearchParams(params).toString();
const url = queryString ? `${endpoint}?${queryString}` : endpoint;
return this.request(url, { method: 'GET' });
}
post(endpoint, data) {
return this.request(endpoint, {
method: 'POST',
body: JSON.stringify(data)
});
}
put(endpoint, data) {
return this.request(endpoint, {
method: 'PUT',
body: JSON.stringify(data)
});
}
delete(endpoint) {
return this.request(endpoint, {
method: 'DELETE'
});
}
}
// 使用示例
const api = new ApiClient('https://api.example.com');
async function loadData() {
try {
const users = await api.get('/users');
console.log(users);
} catch (error) {
console.error('加载用户失败');
}
}
async function createUser(userData) {
try {
const user = await api.post('/users', userData);
console.log('用户创建成功:', user);
} catch (error) {
console.error('创建用户失败');
}
}
十四、总结
JavaScript是一门功能强大、应用广泛的编程语言。通过本文的学习,你应该掌握了:
- JavaScript基础概念和语法
- 变量、数据类型和运算符
- 控制流程和异常处理
- 函数和高阶函数
- 对象和数组的详细使用
- ES6+新特性
- DOM操作和事件处理
- 异步编程(Promise、async/await)
- 错误处理和最佳实践
- 完整的实战示例
学习建议:
- 多动手实践,创建自己的项目
- 参考优秀的开源项目代码
- 关注JavaScript的最新发展和特性
- 深入理解JavaScript的核心概念(闭包、原型链、异步)
- 养成良好的编码习惯和代码规范
- 学习TypeScript提高代码质量
JavaScript的学习是一个持续的过程,随着技术的发展,JavaScript也在不断进化。保持学习的热情,不断提升自己的技能,你一定能成为一名优秀的前端开发者!
希望这篇JavaScript详解教程对你有所帮助!如果你有任何问题或建议,欢迎留言讨论。持续学习,不断进步,让我们一起在Web开发的道路上越走越远!