JavaScript完全指南:从入门到精通
一、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
<buttononclick="alert('Hello!')">点击我</button>内部JavaScript
<script> console.log('Hello World!');</script>外部JavaScript
<scriptsrc="script.js"></script>注意:
- script标签通常放在body底部,避免阻塞页面渲染
- 可以使用
defer或async属性优化加载 defer:按顺序加载,在HTML解析完成后执行async:异步加载,加载完成后立即执行
<scriptdefersrc="script.js"></script><scriptasyncsrc="script.js"></script>2.2 注释
// 单行注释/* * 多行注释 * 可以写多行 *//** * 文档注释 * @param {string} name - 名字 * @returns {string} - 问候语 */functiongreet(name){return`Hello, ${name}!`;}2.3 语句和分号
// 使用分号(推荐)let a =1;let b =2;let c = a + b;// 不使用分号(自动插入分号)let a =1let b =2let c = a + b // 建议始终使用分号,避免潜在问题三、变量和数据类型
3.1 变量声明
// var - 函数作用域(不推荐)var name ='张三';// let - 块级作用域(推荐)let age =25;// const - 常量,块级作用域(推荐)constPI=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)
// 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;// 100000let hex =0xff;// 255let binary =0b1010;// 10let 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)
// Object - 对象let obj ={name:'张三',age:25,sayHello:function(){ console.log('Hello!');}};// Array - 数组let arr =[1,2,3,'four',{five:5}];// Function - 函数functionmyFunction(){ console.log('Function');}letarrowFunction=()=>{ console.log('Arrow Function');};// Date - 日期let date =newDate();let date2 =newDate('2026-01-01');// RegExp - 正则表达式let regex =/pattern/g;let regex2 =newRegExp('pattern','g');// Map - 映射(ES6)let map =newMap(); map.set('key','value');// Set - 集合(ES6)let set =newSet([1,2,3,3]);// {1, 2, 3}3.3 类型检测
// typeof - 检测基本类型 console.log(typeof42);// "number" console.log(typeof'hello');// "string" console.log(typeoftrue);// "boolean" console.log(typeofundefined);// "undefined" console.log(typeofnull);// "object"(历史原因) console.log(typeof{});// "object" console.log(typeof[]);// "object" console.log(typeoffunction(){});// "function"// instanceof - 检测对象类型 console.log([]instanceofArray);// true console.log({}instanceofObject);// true console.log(newDate()instanceofDate);// true// constructor - 构造函数 console.log([].constructor === Array);// true// Object.prototype.toString - 最精确的类型检测functiongetType(value){returnObject.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');// 123Number('123abc');// NaNNumber('');// 0Number(true);// 1Number(false);// 0Number(null);// 0Number(undefined);// NaNparseInt('123');// 123parseInt('123abc');// 123parseFloat('3.14');// 3.14// 转为布尔值Boolean(0);// falseBoolean('');// falseBoolean(null);// falseBoolean(undefined);// falseBoolean(NaN);// falseBoolean(false);// false// 其他都是trueBoolean(1);// trueBoolean('hello');// trueBoolean([]);// trueBoolean({});// true四、运算符
4.1 算术运算符
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 比较运算符
// 相等1==1;// true1=='1';// true(类型转换)1===1;// true(严格相等)1==='1';// false(类型不同)// 不等1!=2;// true1!='1';// false1!==2;// true1!=='1';// true// 大于5>3;// true5>=5;// true// 小于3<5;// true5<=5;// true// Object.is - 严格相等(处理特殊情况) Object.is(NaN,NaN);// true Object.is(+0,-0);// false4.3 逻辑运算符
// 逻辑与true&&true;// truetrue&&false;// falsefalse&&true;// falsefalse&&false;// false// 短路求值let a =1;let b = a >0&& a <10;// truelet c = a >10&& console.log('不会执行');// undefined// 逻辑或true||true;// truetrue||false;// truefalse||true;// truefalse||false;// false// 短路求值let d = a >0|| a <0;// truelet e = a >10|| console.log('会执行');// 会执行// 逻辑非!true;// false!false;// true// 空值合并运算符(ES2020)let f =null??'default';// 'default'let g =undefined??'default';// 'default'let h =0??'default';// 0let i =''??'default';// ''// 可选链运算符(ES2020)let user ={profile:{name:'张三'}}; user?.profile?.name;// '张三' user?.address?.city;// undefined4.4 赋值运算符
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, 2let{ name, age }={name:'张三',age:25}; console.log(name, age);// '张三', 254.5 位运算符
let a =5;// 二进制: 101let 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 条件运算符
// 三元运算符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 条件语句
// if-elselet score =85;if(score >=90){ console.log('优秀');}elseif(score >=80){ console.log('良好');}elseif(score >=60){ console.log('及格');}else{ console.log('不及格');}// switchlet 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){case10: console.log('数字10');break;case'10': console.log('字符串10');// 输出这个break;}5.2 循环语句
// 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和continuefor(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 异常处理
// try-catch-finallytry{// 可能出错的代码let result =10/0; console.log(result);}catch(error){// 捕获错误 console.error('发生错误:', error.message);}finally{// 无论是否出错都会执行 console.log('清理资源');}// 抛出错误functiondivide(a, b){if(b ===0){thrownewError('除数不能为0');}return a / b;}try{divide(10,0);}catch(error){ console.error(error.message);}// 错误类型newError('普通错误');newTypeError('类型错误');newReferenceError('引用错误');newSyntaxError('语法错误');newRangeError('范围错误');newURIError('URI错误');newEvalError('Eval错误');六、函数
6.1 函数定义
// 函数声明functiongreet(name){return`Hello, ${name}!`;}// 函数表达式constgreet2=function(name){return`Hello, ${name}!`;};// 箭头函数(ES6)constgreet3=(name)=>{return`Hello, ${name}!`;};// 箭头函数简写constgreet4=name=>`Hello, ${name}!`;// 箭头函数多个参数constadd=(a, b)=> a + b;// 箭头函数返回对象(需要括号)constcreateUser=(name, age)=>({ name, age });// 立即执行函数(function(){ console.log('立即执行');})();// 箭头函数版本的立即执行函数(()=>{ console.log('立即执行');})();// 函数构造器(不推荐)const greet5 =newFunction('name','return `Hello, ${name}!`');6.2 函数参数
// 默认参数functiongreet(name ='World'){return`Hello, ${name}!`;}greet();// 'Hello, World!'// 剩余参数functionsum(...numbers){return numbers.reduce((acc, num)=> acc + num,0);}sum(1,2,3,4,5);// 15// 参数解构functiongreetUser({ name, age }){ console.log(`${name}, ${age}岁`);}greetUser({name:'张三',age:25});// 结合默认参数和解构functioncreateUser({ name ='匿名', age =0}={}){return{ name, age };}createUser();// { name: '匿名', age: 0 }createUser({name:'李四'});// { name: '李四', age: 0 }6.3 作用域和闭包
// 函数作用域functionouter(){let outerVar ='outer';functioninner(){let innerVar ='inner'; console.log(outerVar);// 可以访问外部变量 console.log(innerVar);}inner();// console.log(innerVar); // 错误:无法访问内部变量}// 块级作用域{let blockVar ='block'; console.log(blockVar);}// console.log(blockVar); // 错误:无法访问// 闭包functioncreateCounter(){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// 闭包应用:模拟私有变量functioncreatePerson(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关键字
// 方法中的thisconst 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、bindfunctiongreet(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 高阶函数
// 函数作为参数functionexecute(fn){fn();}execute(function(){ console.log('执行函数');});// 函数作为返回值functioncreateMultiplier(factor){returnfunction(number){return number * factor;};}const double =createMultiplier(2);const triple =createMultiplier(3); console.log(double(5));// 10 console.log(triple(5));// 15// 回调函数functionfetchData(callback){setTimeout(()=>{const data ={name:'张三',age:25};callback(data);},1000);}fetchData(function(data){ console.log(data);});// 数组高阶函数const numbers =[1,2,3,4,5];// mapconst doubled = numbers.map(n=> n *2); console.log(doubled);// [2, 4, 6, 8, 10]// filterconst evens = numbers.filter(n=> n %2===0); console.log(evens);// [2, 4]// reduceconst sum = numbers.reduce((acc, n)=> acc + n,0); console.log(sum);// 15// findconst found = numbers.find(n=> n >3); console.log(found);// 4// someconst hasEven = numbers.some(n=> n %2===0); console.log(hasEven);// true// everyconst allPositive = numbers.every(n=> n >0); console.log(allPositive);// true// forEach numbers.forEach(n=> console.log(n));七、对象和数组
7.1 对象
// 对象字面量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和setterconst user ={_name:'张三',getname(){returnthis._name;},setname(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 数组
// 数组创建const arr1 =[1,2,3];const arr2 =newArray(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];[...newSet(unique)];// [1, 2, 3, 4]八、ES6+新特性
8.1 let和const
// let - 块级作用域for(let i =0; i <3; i++){ console.log(i);// 0, 1, 2}// console.log(i); // 错误:i不存在// const - 常量constPI=3.14159;// PI = 3.14; // 错误:不能重新赋值// const 对象const person ={name:'张三'}; person.name ='李四';// 正确// person = {}; // 错误:不能重新赋值8.2 箭头函数
// 基本语法constadd=(a, b)=> a + b;// 单参数constsquare=x=> x * x;// 多行代码constgreet=name=>{const greeting =`Hello, ${name}!`;return greeting;};// 返回对象(需要括号)constcreatePerson=(name, age)=>({ name, age });// 箭头函数不绑定thisconst obj ={name:'张三',greet:function(){setTimeout(()=>{ console.log(this.name);// '张三'},1000);}};8.3 模板字符串
const name ='张三';const age =25;// 基本用法const greeting =`Hello, ${name}!`; console.log(greeting);// 'Hello, 张三!'// 多行字符串const message =` 你好,${name} 今年${age}岁 `;// 表达式const result =`${name}${age >18?'成年':'未成年'}`;// 标签模板functionhighlight(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 解构赋值
// 数组解构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:'张三'};// 函数参数解构functiongreet({ 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 展开运算符
// 数组展开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 }// 函数参数展开functionsum(...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
// Promise基础const promise =newPromise((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.allconst 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/awaitasyncfunctionfetchData(){try{const result =await promise; console.log(result);// '成功'}catch(error){ console.error(error);}}fetchData();// async函数返回PromiseasyncfunctionasyncFunction(){return'返回值';}asyncFunction().then(result=> console.log(result));// '返回值'// 并行执行asyncfunctionparallel(){const[result1, result2]=await Promise.all([ promise1, promise2 ]); console.log(result1, result2);// 1, 2}parallel();8.7 Class类
// 基本类classPerson{constructor(name, age){this.name = name;this.age = age;}greet(){ console.log(`Hello, ${this.name}!`);}staticcreateAnonymous(){returnnewPerson('匿名',0);}}const person =newPerson('张三',25); person.greet();// 'Hello, 张三!'const anonymous = Person.createAnonymous();// 继承classStudentextendsPerson{constructor(name, age, grade){super(name, age);this.grade = grade;}study(){ console.log(`${this.name}正在学习`);}greet(){super.greet(); console.log(`我是${this.grade}年级学生`);}}const student =newStudent('李四',20,3); student.greet();// 'Hello, 李四!' '我是3年级学生' student.study();// '李四正在学习'// Getter和SetterclassUser{constructor(name){this._name = name;}getname(){returnthis._name;}setname(value){this._name = value;}}const user =newUser('张三'); console.log(user.name);// '张三' user.name ='李四'; console.log(user.name);// '李四'8.8 模块化
// 导出// math.jsexportconstPI=3.14159;exportfunctionadd(a, b){return a + b;}exportfunctionsubtract(a, b){return a - b;}// 默认导出exportdefaultfunctionmultiply(a, b){return a * b;}// 导入// main.jsimport 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));// 28.9 其他新特性
// Symbolconst sym =Symbol('description');const obj ={[sym]:'value'};// Proxyconst 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 =newProxy({}, handler); proxy.name ='张三';// 'Setting name to 张三' console.log(proxy.name);// 'Getting name' '张三'// Reflectconst obj ={name:'张三'}; Reflect.get(obj,'name');// '张三' Reflect.set(obj,'age',25);// true// Mapconst map =newMap(); map.set('key','value'); map.get('key');// 'value' map.has('key');// true map.delete('key');// true// Setconst set =newSet([1,2,3,3]); set.add(4); set.has(3);// true set.delete(3);// true// WeakMapconst weakMap =newWeakMap();const key ={}; weakMap.set(key,'value'); weakMap.get(key);// 'value'// WeakSetconst weakSet =newWeakSet();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.assignconst 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]// 数组填充newArray(5).fill(0);// [0, 0, 0, 0, 0]// 指数运算符2**3;// 8 Math.pow(2,3);// 8九、DOM操作
9.1 选择元素
// 选择单个元素 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 修改元素
// 获取和设置属性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 创建和删除元素
// 创建元素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 事件处理
// 添加事件监听const button = document.getElementById('myButton'); button.addEventListener('click',function(event){ console.log('按钮被点击'); console.log(event);});// 移除事件监听functionhandleClick(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遍历
// 父子关系 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 回调函数
// 基本回调functionfetchData(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
// 创建Promiseconst promise =newPromise((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链functionfetchUser(id){returnnewPromise(resolve=>{setTimeout(()=>{resolve({ id,name:'张三'});},1000);});}functionfetchPosts(userId){returnnewPromise(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.allconst 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
// 基本用法asyncfunctionfetchData(){try{const response =awaitfetch('https://api.example.com/data');const data =await response.json(); console.log(data);}catch(error){ console.error(error);}}fetchData();// async函数返回PromiseasyncfunctionasyncFunction(){return'返回值';}asyncFunction().then(result=> console.log(result));// '返回值'// 并行执行asyncfunctionparallel(){const[result1, result2]=await Promise.all([fetchUser(1),fetchUser(2)]); console.log(result1, result2);}// 顺序执行asyncfunctionsequential(){const user1 =awaitfetchUser(1);const user2 =awaitfetchUser(2); console.log(user1, user2);}// 错误处理asyncfunctionwithErrorHandling(){try{const data =awaitfetchData();return data;}catch(error){ console.error('发生错误:', error);returnnull;}finally{ console.log('清理资源');}}10.4 Generator函数
// 基本用法function*generator(){yield1;yield2;yield3;}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 offibonacci()){if(num >100)break; console.log(num);}十一、错误处理
11.1 try-catch-finally
try{// 可能出错的代码const result =10/0; console.log(result);}catch(error){// 捕获错误 console.error('发生错误:', error.message);}finally{// 无论是否出错都会执行 console.log('清理资源');}11.2 错误类型
// Error - 基础错误thrownewError('普通错误');// TypeError - 类型错误thrownewTypeError('类型错误');// ReferenceError - 引用错误thrownewReferenceError('引用错误');// SyntaxError - 语法错误thrownewSyntaxError('语法错误');// RangeError - 范围错误thrownewRangeError('范围错误');// URIError - URI错误thrownewURIError('URI错误');// EvalError - Eval错误thrownewEvalError('Eval错误');11.3 自定义错误
classCustomErrorextendsError{constructor(message){super(message);this.name ='CustomError';}}thrownewCustomError('自定义错误');11.4 全局错误处理
// 捕获未处理的Promise错误 window.addEventListener('unhandledrejection',event=>{ console.error('未处理的Promise错误:', event.reason);});// 捕获全局错误 window.addEventListener('error',event=>{ console.error('全局错误:', event.error);});十二、JavaScript最佳实践
12.1 代码规范
// 使用const和let,避免varconstPI=3.14159;let count =0;// 使用语义化的变量名const userName ='张三';const userAge =25;// 使用一致的命名风格const firstName ='张';const lastName ='三';const fullName =`${firstName}${lastName}`;// 函数名使用动词开头functiongetUserData(){}functionvalidateInput(){}functionhandleSubmit(){}// 避免全局变量// ❌ 不好 globalVar ='value';// ✅ 好const myModule ={localVar:'value'};// 使用严格模式'use strict';// 避免使用eval和with// ❌ 不好eval('console.log("hello")');// ✅ 好 console.log('hello');12.2 性能优化
// 避免在循环中创建函数// ❌ 不好for(let i =0; i <1000; i++){ document.getElementById('item'+ i).addEventListener('click',function(){ console.log(i);});}// ✅ 好functionhandleClick(i){returnfunction(){ 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);// 防抖和节流// 防抖functiondebounce(func, wait){let timeout;returnfunction(...args){clearTimeout(timeout); timeout =setTimeout(()=>func.apply(this, args), wait);};} window.addEventListener('resize',debounce(function(){ console.log('窗口大小改变');},300));// 节流functionthrottle(func, limit){let inThrottle;returnfunction(...args){if(!inThrottle){func.apply(this, args); inThrottle =true;setTimeout(()=> inThrottle =false, limit);}};} window.addEventListener('scroll',throttle(function(){ console.log('滚动');},300));12.3 安全性
// 避免innerHTML,使用textContent// ❌ 不好 element.innerHTML = userInput;// ✅ 好 element.textContent = userInput;// 输入验证functionvalidateInput(input){// 去除HTML标签const sanitized = input.replace(/<[^>]*>/g,'');// 限制长度return sanitized.substring(0,100);}// 防止XSSfunctionescapeHtml(unsafe){return unsafe .replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'");}// 使用HTTPS// API请求使用HTTPSfetch('https://api.example.com/data');// 验证API响应asyncfunctionfetchData(){try{const response =awaitfetch('https://api.example.com/data');if(!response.ok){thrownewError('网络响应不正常');}const data =await response.json();// 验证数据结构if(!data ||typeof data !=='object'){thrownewError('无效的数据格式');}return data;}catch(error){ console.error('获取数据失败:', error);throw error;}}12.4 可维护性
// 模块化// utils.jsexportfunctionformatDate(date){return date.toISOString();}exportfunctionvalidateEmail(email){const regex =/^[^\s@]+@[^\s@]+\.[^\s@]+$/;return regex.test(email);}// api.jsimport{ formatDate }from'./utils.js';exportasyncfunctionfetchUserData(userId){const response =awaitfetch(`/api/users/${userId}`);const data =await response.json();return{...data,formattedDate:formatDate(newDate(data.createdAt))};}// 使用注释/** * 计算两个数字的和 * @param {number} a - 第一个数字 * @param {number} b - 第二个数字 * @returns {number} 两个数字的和 */functionadd(a, b){return a + b;}// 使用常量constAPI_URL='https://api.example.com';constMAX_RETRY_COUNT=3;constTIMEOUT_MS=5000;// 错误处理asyncfunctionfetchData(){try{const response =awaitfetch(API_URL);if(!response.ok){thrownewError(`HTTP error! status: ${response.status}`);}returnawait response.json();}catch(error){ console.error('获取数据失败:', error);throw error;}}十三、实战示例
13.1 待办事项应用
classTodoApp{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:newDate().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>删除</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 =newTodoApp();13.2 API请求封装
classApiClient{constructor(baseURL){this.baseURL = baseURL;this.defaultHeaders ={'Content-Type':'application/json'};}asyncrequest(endpoint, options ={}){const url =`${this.baseURL}${endpoint}`;const config ={...options,headers:{...this.defaultHeaders,...options.headers }};try{const response =awaitfetch(url, config);if(!response.ok){thrownewError(`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 =newURLSearchParams(params).toString();const url = queryString ?`${endpoint}?${queryString}`: endpoint;returnthis.request(url,{method:'GET'});}post(endpoint, data){returnthis.request(endpoint,{method:'POST',body:JSON.stringify(data)});}put(endpoint, data){returnthis.request(endpoint,{method:'PUT',body:JSON.stringify(data)});}delete(endpoint){returnthis.request(endpoint,{method:'DELETE'});}}// 使用示例const api =newApiClient('https://api.example.com');asyncfunctionloadData(){try{const users =await api.get('/users'); console.log(users);}catch(error){ console.error('加载用户失败');}}asyncfunctioncreateUser(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开发的道路上越走越远!