JavaScript学习笔记
- JS简介
- 书写语法
- 一、基础语法规则(必遵守)
- 二、变量声明
- 数据类型
- 运算符
- 循环控制语句
- 一、条件语句
- 二、循环语句
- 数组操作
- 1. 新增元素(末尾 / 开头 / 指定位置)
- 2. 删除元素(末尾 / 开头 / 指定位置)
- 3. 修改元素(直接赋值 / 批量修改)
- 4. 查找元素(索引 / 值)
- 函数
- 一、函数的核心概念
- 二、函数的声明方式
- 三、函数参数处理
- 四、函数的返回值
- 对象操作
- 一、对象的基础概念
- 二、对象的创建方式
- 三、对象属性的增删改查
- 四、对象的遍历
- 总结
JS简介
JavaScript(简称 JS)是一种轻量级、解释型或即时编译的编程语言,主要用于网页开发,实现动态交互效果。作为 Web 三大核心技术之一(HTML、CSS、JavaScript),它可直接嵌入 HTML 页面,由浏览器执行。
书写语法
一、基础语法规则(必遵守)
大小写敏感
JS 严格区分大小写,let num = 1和let Num = 1是两个不同变量。语句结束符
- 分号 ; 是语句结束符,建议显式添加(避免自动分号插入 ASI 的坑);
- 换行也可作为语句分隔,但易出错(如 return 后换行)。
- 注释
- 单行注释:
// 注释内容 - 多行注释:
/* 多行注释 换行也可以 */
空白符
空格、制表符、换行符等空白符会被忽略,合理使用可提升可读性标识符命名规则
标识符(变量 / 函数 / 对象属性名等)需遵守:
- 首字符:字母(a-z/A-Z)、下划线_、美元符$;
- 后续字符:可加数字;
- 不能是 JS 关键字 / 保留字(如let、if、function、class等)。
letuserName="张三";// 小驼峰(变量/函数)let_age=20;// 下划线开头let$price=99;// 美元符开头// let 123num = 1; // 错误:数字开头// let if = 5; // 错误:关键字二、变量声明
JS 有 3 种声明方式,ES6 + 新增let/const,替代老旧的var:
| 声明方式 | 作用域 | 提升特性 | 重复声明 | 重新赋值 |
|---|---|---|---|---|
var | 函数级 / 全局 | 变量提升(初始化 undefined) | 允许 | 允许 |
let | 块级({}) | 暂时性死区(无提升) | 禁止 | 允许 |
const | 块级({}) | 暂时性死区(无提升) | 禁止 | 禁止 |
// var(不推荐)vara=1;vara=2;// 允许重复声明// let(推荐:可变变量)letb=10;b=20;// 允许重新赋值// let b = 30; // 错误:重复声明// const(推荐:不可变常量,声明时必须赋值)constPI=3.14159;// PI = 3.14; // 错误:禁止重新赋值constobj={name:"李四"};obj.name="王五";// 允许修改对象属性(const仅保证引用不变)数据类型
- 基本类型(值类型)
- 字符串(String):“abc”、‘123’、模板字符串 `(支持换行 / 插值);
- 数字(Number):123、3.14、NaN、Infinity;
- 布尔(Boolean):true、false;
- 空(Null):null(表示空值);
- 未定义(Undefined):undefined(声明未赋值)
- 引用类型
- 对象(Object):{ key: value };
- 数组(Array):[1, 2, 3];
- 函数(Function):function() {};
- 正则(RegExp):/^abc$/;
- 日期(Date):new Date()。
// 字符串letstr1="hello";letstr2=`name:${userName}, age:${_age}`;// 插值// 数字letnum1=100;letnum2=0.1+0.2;// 0.30000000000000004(浮点精度问题)// 数组letarr=[1,"2",true,{a:1}];console.log(arr[0]);// 1// 对象letuser={name:"张三",age:20,sayHi:function(){// 对象方法console.log("Hi");}};user.sayHi();// 调用方法运算符
- 算术运算符:+、-、*、/、%(取模)。
- 比较运算符:= =(宽松相等)、 = = =(严格相等)、>、<。
- 逻辑运算符:&&(与)、||(或)、!(非)。
- 三元运算符:
条件 ? 表达式1 : 表达式2
5+"5";// "55"(字符串拼接)5==="5";// false(类型不同)true&&false// false//三元算符letscore=85;letresult=score>=60?"及格":"不及格";console.log(result);// 及格循环控制语句
一、条件语句
- if-else:
if(score>=90){console.log("优秀");}elseif(score>=70){console.log("良好");}else{console.log("加油");}- switch:
letday=1;switch(day){case1:console.log("周一");break;// 必须break,否则穿透case2:console.log("周二");break;default:console.log("其他");}二、循环语句
- for:
for(leti=0;i<5;i++){console.log(i);// 0-4}- while:
letj=0;while(j<5){console.log(j);j++;}- for…in(遍历对象属性 / 数组索引):
letobj={a:1,b:2};for(letkeyinobj){console.log(key,obj[key]);// a 1, b 2}- for…of(遍历可迭代对象值,如数组 / 字符串):
letarr=[1,2,3];for(letvalofarr){console.log(val);// 1,2,3}数组操作
1. 新增元素(末尾 / 开头 / 指定位置)
| 方法 | 作用 | 示例 | 返回值 |
|---|---|---|---|
push() | 末尾添加 1 + 元素 | arr.push(4, 5) | 新数组长度 |
unshift() | 开头添加 1 + 元素 | arr.unshift(0) | 新数组长度 |
splice() | 指定位置插入元素 | arr.splice(2, 0, 'a') | 空数组(无删除) |
letarr=[1,2,3];// 末尾新增arr.push(4);// arr → [1,2,3,4]// 开头新增arr.unshift(0);// arr → [0,1,2,3,4]// 索引2的位置插入'a'(参数:起始索引,删除数量,插入元素)arr.splice(2,0,'a');// arr → [0,1,'a',2,3,4]2. 删除元素(末尾 / 开头 / 指定位置)
| 方法 | 作用 | 示例 | 返回值 |
|---|---|---|---|
pop() | 删除末尾元素 | arr.pop() | 被删除的元素 |
shift() | 删除开头元素 | arr.shift() | 被删除的元素 |
splice() | 指定位置删除元素 | arr.splice(2, 1) | 被删除元素组成的数组 |
slice() | 截取部分元素(不修改原数组) | arr.slice(1, 3) | 截取的新数组 |
letarr=[0,1,'a',2,3,4];// 删除末尾letlast=arr.pop();// last=4,arr → [0,1,'a',2,3]// 删除开头letfirst=arr.shift();// first=0,arr → [1,'a',2,3]// 删除索引2的1个元素letdel=arr.splice(2,1);// del=[2],arr → [1,'a',3]// 截取(索引1到3,左闭右开)letnewArr=arr.slice(1,3);// newArr=['a',3],原arr不变3. 修改元素(直接赋值 / 批量修改)
- 直接通过索引赋值:arr[索引] = 新值;
- fill():批量填充 / 修改元素(修改原数组)。
letarr=[1,2,3];// 单个修改arr[1]='b';// arr → [1,'b',3]// 批量填充(参数:填充值,起始索引,结束索引)arr.fill(0,1,3);// arr → [1,0,0]4. 查找元素(索引 / 值)
| 方法 | 作用 | 示例 | 返回值 |
|---|---|---|---|
indexOf() | 查找值的第一个索引 | arr.indexOf(2) | 索引 /-1 |
lastIndexOf() | 查找值的最后一个索引 | arr.lastIndexOf(2) | 索引 /-1 |
find() | 查找满足条件的第一个元素 | arr.find(item => item > 3) | 元素 /undefined |
findIndex() | 查找满足条件的第一个索引 | arr.findIndex(item => item > 3) | 索引 /-1 |
includes() | 判断是否包含某个值 | arr.includes(2) | true/false |
letarr=[1,2,3,2,4];// 查找值的索引console.log(arr.indexOf(2));// 1console.log(arr.lastIndexOf(2));// 3// 条件查找元素console.log(arr.find(item=>item>3));// 4// 条件查找索引console.log(arr.findIndex(item=>item>3));// 4// 判断是否包含console.log(arr.includes(5));// false函数
一、函数的核心概念
函数本质是【可调用的对象】,具有以下特性:
- 可接收参数、执行逻辑、返回值;
- 可赋值给变量、作为参数传递、作为返回值(一等公民);
- 有自己的作用域,隔离内部变量。
二、函数的声明方式
JS 有 4 种主流函数声明方式,适用场景不同:
| 声明方式 | 语法示例 | 提升特性 | 适用场景 |
|---|---|---|---|
| 函数声明 | function add(a, b) { return a + b; } | 函数提升(可先调用后声明) | 全局 / 函数内通用函数 |
| 函数表达式 | const add = function(a, b) { return a + b; }; | 无提升(先声明后调用) | 赋值给变量、作为回调 |
| 箭头函数(ES6) | const add = (a, b) => a + b; | 无提升 | 简洁回调、无 this 绑定场景 |
| 构造函数(极少用) | const add = new Function('a', 'b', 'return a + b'); | 无提升 | 动态生成函数(性能差,不推荐) |
示例:不同声明方式的调用
// 1. 函数声明(提升)console.log(sum(1,2));// 3(先调用后声明)functionsum(a,b){returna+b;}// 2. 函数表达式(无提升)// console.log(sub(5, 3)); // 报错:sub is not a functionconstsub=function(a,b){returna-b;};console.log(sub(5,3));// 2// 3. 箭头函数constmul=(a,b)=>a*b;// 单行返回可省略{}和returnconstdiv=(a,b)=>{// 多行需加{}和returnif(b===0)returnNaN;returna/b;};console.log(mul(2,4));// 8console.log(div(8,2));// 4三、函数参数处理
JS 函数参数灵活,支持默认参数、剩余参数、解构参数、参数传递方式等特性:
- 默认参数(ES6)
声明时指定参数默认值,调用时未传参则使用默认值:
functiongreet(name="访客",age=18){console.log(`你好,${name},年龄${age}`);}greet();// 你好,访客,年龄18greet("张三");// 你好,张三,年龄18greet("李四",20);// 你好,李四,年龄20- 剩余参数(…rest,ES6)
接收【多余的参数】为数组,替代 arguments(类数组),更灵活:
// 求和任意个数的参数functionsum(...nums){returnnums.reduce((total,num)=>total+num,0);}console.log(sum(1,2));// 3console.log(sum(1,2,3,4));// 10// 剩余参数需放在参数列表最后functionfn(a,b,...rest){console.log(a,b,rest);// 1 2 [3,4,5]}fn(1,2,3,4,5);- 解构参数(ES6)
直接解构对象 / 数组作为参数,简化参数提取:
// 解构对象参数functionprintUser({name,age,gender="男"}){console.log(`姓名:${name},年龄:${age},性别:${gender}`);}printUser({name:"张三",age:20});// 姓名:张三,年龄:20,性别:男// 解构数组参数functionprintArr([a,b,c]){console.log(a,b,c);// 1 2 3}printArr([1,2,3]);- 参数传递方式
- 基本类型(值传递):传递值的副本,函数内修改不影响外部;
- 引用类型(引用传递):传递内存地址,函数内修改会影响外部;
// 基本类型letnum=10;functionchangeNum(n){n=20;}changeNum(num);console.log(num);// 10(无变化)// 引用类型letobj={name:"张三"};functionchangeObj(o){o.name="李四";}changeObj(obj);console.log(obj.name);// 李四(被修改)- arguments 对象(类数组)
非严格模式下,函数内可通过 arguments 获取所有传入的参数(类数组,无数组方法):
functionfn(){console.log(arguments[0]);// 1console.log(arguments.length);// 3// 转为数组:[...arguments] 或 Array.from(arguments)}fn(1,2,3);注意:箭头函数无
arguments对象,优先用剩余参数替代。
四、函数的返回值
- 无 return 语句:默认返回 undefined;
- return 后无值:返回 undefined;
- return 可返回任意类型(基本类型、对象、函数);
functionfn1(){}console.log(fn1());// undefinedfunctionfn2(){return;// 等同于 return undefined}console.log(fn2());// undefined// 返回函数(高阶函数)functioncreateAdd(n){return(x)=>x+n;}constadd5=createAdd(5);console.log(add5(3));// 8对象操作
一、对象的基础概念
- 对象的「键」(属性名):字符串 / Symbol 类型(数字会自动转为字符串);
- 对象的「值」(属性值):任意类型(基本类型、对象、函数);
- 函数类型的属性称为「方法」。
二、对象的创建方式
| 创建方式 | 语法示例 | 适用场景 |
|---|---|---|
| 对象字面量(推荐) | const obj = { name: "张三", age: 20 }; | 简单对象,直接声明 |
| 构造函数 | const obj = new Object({ name: "张三" }); | 动态创建(极少用) |
| object.create() | const obj = Object.create(prototypeObj); | 基于原型创建对象 |
| 类(ES6) | class User { constructor(name) { this.name = name; } } const obj = new User("张三"); | 复杂对象 / 面向对象编程 |
// 1. 对象字面量(最常用)constuser={name:"张三",age:20,sayHi(){// 方法简写(替代 sayHi: function() {})console.log(`你好,我是${this.name}`);}};user.sayHi();// 你好,我是张三// 2. Object.create(指定原型)constproto={gender:"男"};constuser2=Object.create(proto);user2.name="李四";console.log(user2.gender);// 男(继承原型属性)// 3. 类创建(ES6)classUser{constructor(name,age){this.name=name;this.age=age;}// 类方法getInfo(){return`${this.name},${this.age}岁`;}}constuser3=newUser("王五",25);console.log(user3.getInfo());// 王五,25岁三、对象属性的增删改查
- 访问属性(两种方式)
- 点语法:
obj.key(键为合法标识符,推荐); - 方括号语法:
obj["key"](键含特殊字符 / 变量,必用)。
constobj={"user-name":"张三",// 含特殊字符的键age:20};// 点语法console.log(obj.age);// 20// 方括号语法(特殊字符键)console.log(obj["user-name"]);// 张三// 变量作为键constkey="age";console.log(obj[key]);// 20- 添加 / 修改属性
- 直接赋值:
obj.key = value(存在则修改,不存在则添加); - Object.defineProperty ():精细配置属性(可枚举、可修改、可删除)。
constobj={name:"张三"};// 添加属性obj.age=20;obj["gender"]="男";console.log(obj);// { name: '张三', age: 20, gender: '男' }// 修改属性obj.name="李四";console.log(obj.name);// 李四// 精细配置属性(不可修改、不可枚举)Object.defineProperty(obj,"id",{value:1001,writable:false,// 不可修改enumerable:false,// 不可枚举(遍历不到)configurable:false// 不可删除/重新配置});obj.id=1002;// 无效果(严格模式报错)console.log(obj.id);// 1001- 删除属性
delete obj.key:删除对象自身属性(原型属性无法删除);- 返回值:成功删除 / 属性不存在返回 true,不可配置属性返回 false(严格模式报错)。
constobj={name:"张三",age:20};deleteobj.age;console.log(obj);// { name: '张三' }// 不可配置属性无法删除Object.defineProperty(obj,"id",{value:1,configurable:false});console.log(deleteobj.id);// false- 检查属性是否存在
| 方法 | 作用 | 示例 |
|---|---|---|
| in 运算符 | 检查自身 + 原型属性 | 'age' in obj |
| hasOwnProperty() | 仅检查自身属性(推荐) | obj.hasOwnProperty('age') |
| obj.key !== undefined | 检查属性值是否为 undefined(不严谨,属性值可能为 undefined) | obj.age !== undefined |
constproto={gender:"男"};constobj=Object.create(proto);obj.name="张三";console.log("name"inobj);// true(自身属性)console.log("gender"inobj);// true(原型属性)console.log(obj.hasOwnProperty("name"));// trueconsole.log(obj.hasOwnProperty("gender"));// false四、对象的遍历
- for…in 循环(遍历可枚举属性,含原型)
constobj={name:"张三",age:20};// 遍历自身可枚举属性(过滤原型)for(letkeyinobj){if(obj.hasOwnProperty(key)){console.log(key,obj[key]);// name 张三, age 20}}- Object.keys() / Object.values() / Object.entries()
Object.keys(obj):返回自身可枚举属性名数组;Object.values(obj):返回自身可枚举属性值数组;Object.entries(obj):返回自身可枚举属性的 [key, value] 数组(可解构遍历)。
constobj={name:"张三",age:20};// 遍历键console.log(Object.keys(obj));// ['name', 'age']// 遍历值console.log(Object.values(obj));// ['张三', 20]// 遍历键值对Object.entries(obj).forEach(([key,value])=>{console.log(key,value);// name 张三, age 20});- Object.getOwnPropertyNames()
返回自身所有属性名(含不可枚举,不含 Symbol):
constobj={};Object.defineProperty(obj,"id",{value:1,enumerable:false});console.log(Object.keys(obj));// [](不可枚举)console.log(Object.getOwnPropertyNames(obj));// ['id']- Reflect.ownKeys()
返回自身所有属性名(含不可枚举、Symbol):
consts=Symbol("id");constobj={[s]:1001,name:"张三"};Object.defineProperty(obj,"age",{value:20,enumerable:false});console.log(Reflect.ownKeys(obj));// [ 'name', 'age', Symbol(id) ]总结
基于JS的HTML会有更加流畅、更加实用、更加美观等效果,注意区分JS与CSS和HTML的语法区别。