JavaScript_基础教程_自学笔记

文章目录

一、概述

JavaScript多用来控制网页的行为。

如需在 HTML 页面中插入 JavaScript,请使用 会告诉 JavaScript 在何处开始和结束。

二、JS基础

2.1 JS在chrome中的运行

2.1.1 chrome F12开发者模式

在这里插入图片描述
回车就可得到结果。

2.1.2 chrome snippets小脚本

在这里插入图片描述

2.2 JS显示数据

JavaScript 可以通过不同的方式来输出数据:1

  • 使用 window.alert() 弹出 –警告框–。
  • 使用 document.write() 方法将内容写到 –HTML 文档–中。
  • 使用 innerHTML 写入到 –HTML 元素–。
  • 使用 console.log() 写入到–浏览器的控制台–。

2.3 JS操作元素

如需从 JavaScript 访问某个 HTML 元素,您可以使用 document.getElementById(id) 方法。

<!DOCTYPE html><html>
<body>
<h1>我的第一个 Web 页面</h1>
	<p id="demo">我的第一个段落</p>
<script>
	document.getElementById("demo").innerHTML = "段落已修改。";
</script>
</body>
</html>

三、JS语法

3.1 JS字面量【所见即所得】

  • 字符串用 “…”
  • 数字用 123
  • 对象用 {Name:“Bob”, age:50, gender:“male”}
  • 数组用 [40, 100, 1, 5, 25, 10]
  • 函数用 function myFunction(a, b) { return a * b;}

3.2 JS变量

在JavaScript中 变量用于存储数据值,使用关键字 var 来定义变量,使用等号 = 来为变量赋值。

var x,y
x = 1
y = 2 
console.log(x+y)
// 控制台输出 3 

3.3 JS操作符

操作符特指算术运算操作符赋值操作符,是JS中完成数值计算、变量赋值的核心符号。

3.3.1 算术运算操作符

用于对数值进行基础数学运算,是最常用的运算符号,需重点注意字符串拼接、特殊运算规则等新手易错点。

运算符含义代码示例执行结果新手必避坑
+加法 / 字符串拼接10 + 5’10’ + 515’105’运算两边只要有一边是字符串,就会执行拼接操作,而非数值加法
-减法10 - 55仅支持纯数值运算,非数字会隐式转换,易出现NaN
*乘法10 * 550浮点数相乘可能出现精度误差,属于JS正常现象
/除法10 / 52除数不能为0,否则结果为Infinity(无穷大)
%取余(模运算)10 % 31常用于判断奇偶性、循环取数、数值取模
**幂运算2 ** 38等价于Math.pow(2,3),用于计算一个数的次方

用于数值的加减乘除等数学计算,注意字符串拼接、取余、浮点数精度等新手常见坑。

运算符含义代码示例执行结果新手必避坑
+加法/字符串拼接10+5 / ‘10’+515 / ‘105’一边是字符串,就会变成拼接而非相加
-减法10-55纯数字运算,无特殊坑点
*乘法10*550浮点数运算可能有精度误差
/除法10/52除数不能为0,否则结果为Infinity
%取余(模运算)10%31常用于判断奇偶、循环取数
**幂运算2**38等价于Math.pow(2,3)
  • ++a:前置自增,先+1,再使用变量值

  • a++:后置自增,先使用变量值,再+1

  • –a:前置自减,先-1,再使用变量值

  • a–:后置自减,先使用变量值,再-1

// 后置自增(常用)
let a = 10;
console.log(a++); // 10(先取值)
console.log(a);   // 11(后+1)

// 前置自增
let b = 10;
console.log(++b); // 11(先+1,再取值)
console.log(b);   // 11
// 算术运算实操示例
// 数值加法
console.log(20 + 8);
// 字符串拼接
console.log('20' + 8);
// 减法运算
console.log(20 - 8);
// 乘法运算
console.log(20 * 8);
// 除法运算
console.log(20 / 5);
// 取余运算
console.log(20 % 3);
// 幂运算
console.log(3 ** 3);

3.3.2 赋值操作符

核心作用是给变量存储数据,同时简化“运算+赋值”的复合写法,避免重复书写变量名,提升代码简洁度。

运算符含义等价普通写法完整代码示例
=基础赋值-let num = 10; // 直接给变量赋值10
+=加后赋值num = num + 5let num = 10; num += 5; // 最终num=15
-=减后赋值num = num - 5let num = 10; num -= 5; // 最终num=5
*=乘后赋值num = num * 5let num = 10; num *= 5; // 最终num=50
/=除后赋值num = num / 5let num = 10; num /= 5; // 最终num=2
%=取余后赋值num = num % 3let num = 10; num %= 3; // 最终num=1
// 赋值操作符实操示例
// 基础赋值
let score = 90;
console.log('基础赋值:', score);

// 复合赋值:加后赋值
score += 10;
console.log('加后赋值:', score);

// 复合赋值:乘后赋值
score *= 2;
console.log('乘后赋值:', score);

3.3.3 两类操作符核心注意事项

  1. 算术操作符优先处理纯数值运算,遇到字符串优先拼接,如需数值相加,需提前用Number()转换数据类型;
  2. 赋值操作符中,**=**是基础核心,其余均为复合简写,执行顺序是先算右侧运算,再赋值给左侧变量;
  3. 避免对非数值变量直接使用算术操作符,容易得到NaN(非数字)结果,导致代码异常。

3.3.4 三元运算符(简化if-else)

语法:条件 ? 条件成立执行 : 条件不成立执行,是if-else的简写形式,适合简单判断。

let age = 20;
// 常规if-else
let result;
if(age >= 18){
  result = '成年';
} else {
  result = '未成年';
}

// 三元运算符简写
let result2 = age >= 18 ? '成年' : '未成年';
console.log(result2); // '成年'

3.3.5 其他常用运算符

(1) typeof 类型判断

判断数据类型,返回字符串结果

console.log(typeof 10);      // 'number'
console.log(typeof '10');    // 'string'
console.log(typeof true);   // 'boolean'
(2)空值合并运算符 ??

判断值是否为null/undefined,是则取默认值

let name = null;
console.log(name ?? '匿名用户'); // '匿名用户'
(3)可选链操作符 ?.

防止对象属性不存在报错,新手必备

let user = { name: '张三' };
console.log(user?.age); // undefined,不报错
(4)运算符优先级(新手速记)

优先级从高到低,不确定时用**小括号()**包裹,小括号优先级最高,避免运算顺序出错:

小括号() > 自增自减 ++/-- > 算术运算 */% > 算术运算 ± > 比较运算 > 逻辑运算 > 赋值运算

3.4 JS数据类型

JS中的数据类型都是 弱类型,无需像 java、C++等强制声明, **“var”**解决一切。

3.4.1 数据类型简介

在这里插入图片描述

值类型(基本类型): 字符串(String)、数字(Number)、布尔(Boolean)、空(Null)、未定义(Undefined)、Symbol。
引用数据类型(对象类型): 对象(Object)、数组(Array)、函数(Function),还有两个特殊的对象:正则(RegExp)和日期(Date)。

3.4.2 JS动态类型

JavaScript拥有动态类型,这会使得相同的变量在不同的地方可作为不同的类型。

JS数据类型分为基本数据类型(值类型)引用数据类型两大类,是JS编程的核心基础,决定了数据存储、传递和使用的方式,新手需重点区分两类数据的核心差异,避免隐式转换、赋值报错等常见问题。

3.4.3 数据类型核心分类

基本数据类型:存储在栈内存,数据本身直接存储,赋值时拷贝完整数据,修改副本不影响原数据,共7种,是日常开发最常用的基础类型。

引用数据类型:存储在堆内存,栈中只存内存地址,赋值时拷贝地址,多个变量指向同一数据,修改一个会影响全部,核心为对象、数组、函数。

3.4.4 基本数据类型(7种,必掌握)

数据类型类型名称写法示例核心说明新手避坑
number数字类型18、3.14、-5、0、NaN包含整数、小数、负数,特殊值NaN代表非数字算术运算出错会得到NaN,typeof NaN结果为number
string字符串类型‘你好’、“JS”、模板字符串文本数据,必须用单引号、双引号或反引号包裹和数字混用+号会拼接,而非相加,需提前转换类型
boolean布尔类型true、false只有两个值,用于条件判断、逻辑运算0、‘’、null、undefined会自动转为false
undefined未定义类型undefined变量声明但未赋值,默认值不是手动赋值,是系统默认状态
null空值类型null手动设置的空对象指针,表示空值typeof null结果为object,属于历史bug
symbol符号类型Symbol(‘唯一标识’)生成唯一值,避免对象属性重名冲突日常基础开发少用,多用于框架、复杂对象
bigint大整数类型100n、BigInt(999)存储超大整数,解决普通数字溢出问题不能和普通number直接运算,需统一类型

3.4.5 引用数据类型(核心3种)

数据类型类型名称写法示例核心说明
object对象类型{name:‘张三’, age:18}存储键值对数据,描述事物属性
array数组类型[1,2,3, ‘前端’, true]有序数据集合,按索引取值,属于特殊对象
function函数类型function fn(){}封装可重复执行的代码块,typeof结果为function

3.4.6 数据类型判断方法(新手首选)

(1) typeof 运算符(最常用,适合基本类型)
// 基本类型判断
console.log(typeof 18);        // number
console.log(typeof '前端');    // string
console.log(typeof true);      // boolean
console.log(typeof undefined); // undefined
console.log(typeof null);      // object(历史bug,特殊记忆)

// 引用类型判断
console.log(typeof {});        // object
console.log(typeof []);        // object
console.log(typeof function(){}); // function

(2) Array.isArray() 专门判断数组
console.log(Array.isArray([1,2,3])); // true
console.log(Array.isArray({}));      // false

3.4.7 两类数据类型核心区别(必记)

基本数据类型:栈内存存储,赋值是深拷贝,修改新变量,原变量不变
引用数据类型:堆内存存储,赋值是浅拷贝,修改新变量,原变量同步改变

// 基本类型:拷贝数据,互不影响
let a = 10;
let b = a;
b = 20;
console.log(a); // 10,原数据不变

// 引用类型:拷贝地址,互相影响
let obj1 = {name:'张三'};
let obj2 = obj1;
obj2.name = '李四';
console.log(obj1.name); // 李四,原数据被修改

3.4.8 新手常见数据类型误区

  1. 误区1:null和undefined一样
    解答:undefined是变量声明未赋值,null是手动设置的空值

  2. 误区2:数组是独立基本类型
    解答:数组属于引用类型,是特殊的对象

  3. 误区3:字符串用+数字是加法
    解答:只要一侧是字符串,+号执行拼接操作

  4. 误区4:typeof能区分对象和数组
    解答:typeof判断对象和数组都返回object,需用Array.isArray()区分

3.4.9 数据类型速记口诀

基本类型七兄弟,数串布尔空未定,符号大整数补上;
引用类型对象组,函数也是其中属;
栈存值来堆存址,拷贝方式要记熟。

3.5 JS注释

3.5.1. 单行注释(最常用)

语法:用双斜杠 // 开头,只作用于当前行,双斜杠后面的内容全部为注释。

使用场景:简短说明、行内解释、临时屏蔽单行代码

// 定义变量存储用户名
let username = "前端小白";

// 这行代码临时屏蔽,不执行
// let age = 18;

console.log(username); // 输出用户名,行尾注释

使用技巧:可以放在代码行开头,也可以放在代码末尾,不影响代码执行,简洁高效。

3.5.2. 多行注释(块注释)

语法:以 /* 开头,*/ 结尾,中间可跨多行书写。

使用场景:长文本说明、批量屏蔽多行代码、文件头部标注

/*
  这是一个计算两数之和的函数
  参数:num1-第一个数字,num2-第二个数字
  返回值:两数相加的结果
  适用场景:基础数值运算
*/
function add(num1, num2) {
  return num1 + num2;
}

/*
批量屏蔽以下代码
console.log(123);
let test = "测试";
*/

注意:多行注释不支持嵌套,内部不能再写 /* */,否则会提前结束注释,导致语法报错。

3.5.3. 文档注释(JSDoc规范)

语法:以 /** 开头,*/ 结尾,属于特殊多行注释,常用于函数、类、变量的标准化说明,支持VS Code等编辑器智能提示。

使用场景:团队协作、函数/组件说明、生成API文档

/**
 * 计算商品总价
 * @param {number} price - 商品单价
 * @param {number} count - 商品数量
 * @param {boolean} isDiscount - 是否打折
 * @returns {number} 最终总价
 */
function calcTotalPrice(price, count, isDiscount) {
  let total = price * count;
  return isDiscount ? total * 0.9 : total;
}

3.6 JS语句

JS语句是代码执行的最小逻辑单元,用于控制代码的执行顺序、分支选择、循环重复,实现各类业务逻辑。语句通常以分号;结尾(可省略但建议规范书写),按功能分为表达式语句、分支语句、循环语句、跳转语句、异常处理语句五大类,本篇聚焦日常开发高频使用的核心语句,搭配实例与注意事项,零基础也能快速掌握。


3.6.1 表达式语句(基础语句)

由表达式构成,执行后会返回一个值,是最基础、最常用的语句,几乎所有代码都离不开这类语句。

核心类型与示例
  • 赋值语句:给变量赋值,最常用的表达式语句
    let num = 10; // 声明+赋值语句 num = num + 5; // 重新赋值语句

  • 算术运算语句:执行数学计算,可单独执行或结合赋值
    10 + 20; // 单纯运算,无实际业务意义 let total = 10 * 20; // 运算+赋值,常用写法

  • 函数调用语句:调用已定义的函数,执行函数内部逻辑
    console.log('Hello JS'); // 控制台输出语句 alert('提示框'); // 浏览器弹窗语句

注意事项
  • 单独的运算表达式无实际作用,需结合赋值或输出才有意义

  • 建议每条语句结尾加分号,避免代码压缩或合并时出现语法错误


3.6.2 分支语句(条件判断,选执行)

根据指定条件的真假,选择执行不同的代码块,实现多路径逻辑选择,是实现业务判断的核心语句。

(1)if 语句(单分支)

满足条件时,执行对应代码块,不满足则跳过。

// 语法
if (条件表达式) {
  // 条件为true时执行的代码
}

// 示例:判断成年
let age = 20;
if (age >= 18) {
  console.log('已成年,具备完全民事行为能力');
}
(2) if…else 语句(双分支)

条件为true执行if代码块,为false执行else代码块,二选一执行。

// 示例:判断成年/未成年
let age = 16;
if (age >= 18) {
  console.log('已成年');
} else {
  console.log('未成年');
}
(3)if…else if…else 语句(多分支)

多个条件依次判断,满足哪个条件就执行对应代码块,都不满足则执行else代码块。

// 示例:判断成绩等级
let score = 85;
if (score >= 90) {
  console.log('优秀');
} else if (score >= 70) {
  console.log('良好');
} else if (score >= 60) {
  console.log('及格');
} else {
  console.log('不及格');
}
(4) switch 语句(精准多分支)

针对一个变量的固定值做精准匹配,适合多固定值判断,比多分支if更简洁。

// 语法:break用于跳出switch,避免穿透;default为默认匹配项
switch (变量/表达式) {
  case1:
    代码块1;
    break;
  case2:
    代码块2;
    break;
  default:
    默认代码块;
}

// 示例:判断星期
let week = 3;
switch (week) {
  case 1:
    console.log('星期一');
    break;
  case 2:
    console.log('星期二');
    break;
  case 3:
    console.log('星期三');
    break;
  default:
    console.log('输入无效');
}
分支语句注意事项
  • if条件表达式会自动转为布尔值,0、‘’、null、undefined、NaN会转为false,其余为true

  • switch匹配是严格相等(===),值和类型都要一致

  • switch的case必须加break,否则会出现“穿透现象”,继续执行后续case代码

  • 多分支逻辑优先用switch,范围判断优先用if


3.6.3 循环语句(重复执行,省代码)

满足循环条件时,重复执行一段代码,用于批量处理数据、遍历数组/对象、重复逻辑,避免冗余代码。

(1) for 循环(最常用,已知循环次数)

适合循环次数固定的场景,语法紧凑,三步控制循环(初始化、条件、更新)。

// 语法
for (初始化变量; 循环条件; 变量更新) {
  循环体代码(重复执行)
}

// 示例:循环输出1-10
for (let i = 1; i <= 10; i++) {
  console.log(i);
}

// 示例:遍历数组
let arr = [10, 20, 30];
for (let i = 0; i < arr.length; i++) {
  console.log(arr[i]);
}
(2)while 循环(未知循环次数)

先判断条件,条件为true再执行循环体,适合循环次数不确定的场景。

// 语法
初始化变量;
while (循环条件) {
  循环体代码;
  变量更新;
}

// 示例:循环输出1-5
let i = 1;
while (i <= 5) {
  console.log(i);
  i++; // 必须更新变量,否则死循环
}
(3)do…while 循环(先执行后判断)

先执行一次循环体,再判断条件,至少执行一次

// 示例
let i = 1;
do {
  console.log(i);
  i++;
} while (i <= 5);
(4) for…in 循环(遍历对象/数组)

专门用于遍历对象的属性,也可遍历数组,循环变量为键名/索引。

let obj = { name: '张三', age: 20 };
for (let key in obj) {
  console.log('属性名:', key, '属性值:', obj[key]);
}
循环语句注意事项
  • 必须设置循环终止条件,否则会造成死循环,导致页面卡顿崩溃

  • for循环适合固定次数,while适合不确定次数,do…while适合至少执行一次

  • 遍历数组优先用for循环,遍历对象优先用for…in

  • 避免在循环体内修改循环变量,防止循环逻辑混乱


3.6.4 跳转语句(改变执行流程)

强制改变代码执行顺序,跳出循环或跳过当前循环,配合分支、循环语句使用。

(1) break 语句

立即跳出当前循环/switch,终止整个循环或switch语句。

// 示例:循环到5时终止
for (let i = 1; i <= 10; i++) {
  if (i === 5) {
    break; // 跳出整个for循环
  }
  console.log(i); // 输出1-4
}
(2)continue 语句

跳过当前一次循环,直接进入下一次循环,不终止整个循环。

// 示例:跳过5,输出其余数字
for (let i = 1; i <= 10; i++) {
  if (i === 5) {
    continue; // 跳过本次循环,不输出5
  }
  console.log(i);
}
跳转语句注意事项
  • break只能用于循环和switch,不能用于普通if语句

  • continue只能用于循环,不能用于switch语句

  • 合理使用跳转语句,避免代码逻辑过于复杂难以维护


3.6.5 异常处理语句(容错,防代码崩溃)

捕获代码执行中的错误,避免因报错导致整个代码停止运行,提升代码稳定性。

// 语法
try {
  // 可能报错的代码
  let num = 10;
  console.log(num.toUpperCase()); // 数字无此方法,会报错
} catch (err) {
  // 捕获错误,执行容错代码,不影响后续代码
  console.log('代码出错了:', err.message);
} finally {
  // 无论是否报错,都会执行的代码(可选)
  console.log('执行完毕');
}
注意事项
  • try包裹易报错代码,catch捕获错误信息,finally用于收尾操作

  • 不要滥用try…catch,优先提前判断避免错误,而非捕获错误


四、 JS对象

对象是JS引用数据类型的核心,是存储复杂数据、描述事物特征与行为的载体,属于**键值对(key-value)**结构,也是前端开发中最常用的数据结构之一,本篇覆盖基础到核心考点,全是实用知识点。


4.1 对象基础概念

  • 定义:对象是无序的键值对集合,每个键(属性名)对应一个值(属性值),键默认是字符串类型,值可以是任意数据类型(数字、字符串、函数、数组甚至另一个对象)。

  • 作用:描述一个具体事物(比如人、商品、用户),存储事物的属性(特征)和方法(行为)。

  • 存储特点:属于引用数据类型,存储在堆内存,变量保存的是内存地址,赋值时传递地址,修改会影响原对象。

4.2 对象的两种创建方式

4.2.1 字面量创建(最常用、推荐)

语法简洁,代码直观,日常开发首选,直接用大括号包裹键值对,键值之间用冒号分隔,多个键值对用逗号分隔。

// 基础对象创建
let person = {
  // 属性:特征描述
  name: "张三",
  age: 20,
  gender: "男",
  // 方法:行为描述
  sayHello: function() {
    console.log("大家好,我是" + this.name);
  }
};

// 调用属性和方法
console.log(person.name); // 张三
person.sayHello(); // 大家好,我是张三

4.2.2 构造函数创建

通过new Object()创建,适合动态添加属性的场景,写法相对繁琐,日常使用少于字面量。

let person = new Object();
// 动态添加属性
person.name = "李四";
person.age = 22;
// 动态添加方法
person.sayHi = function() {
  console.log("Hi~");
};

console.log(person.age); // 22


4.3 对象的核心操作(增删改查)

对象操作主要针对属性和方法,分为点语法方括号语法两种操作方式,适用场景不同。

4.3.1 查(获取属性/方法)

操作方式语法适用场景示例
点语法对象.属性名属性名是合法标识符(无空格、无特殊字符、非数字开头)person.name
方括号语法对象[‘属性名’]属性名含空格、特殊字符、数字开头,或属性名是变量person[‘user name’]、let key=‘age’; person[key]

4.3.2 改(修改属性)

直接给已有属性重新赋值,即可修改原有属性值,方法也可通过同样方式修改。

let person = { name: "张三", age: 20 };
// 点语法修改
person.age = 21;
// 方括号语法修改
person['name'] = "张三三";
console.log(person); // {name: '张三三', age: 21}

4.3.3 增(添加属性/方法)

直接给对象赋值一个不存在的属性名,即可动态新增属性,无需提前声明。

let person = { name: "张三" };
// 新增属性
person.address = "北京";
// 新增方法
person.run = function() {
  console.log("跑步");
};

4.3.4 删(删除属性)

使用delete关键字删除对象的属性或方法,删除后属性彻底消失。

let person = { name: "张三", age: 20 };
delete person.age;
console.log(person.age); // undefined


4.4 对象中的this关键字

核心含义:对象方法中的this,指向当前调用方法的对象本身,可以通过this访问对象自身的其他属性和方法。

let person = {
  name: "张三",
  sayName: function() {
    // this指向person对象
    console.log(this.name);
  }
};
person.sayName(); // 张三

注意:普通函数中的this指向全局对象(window),对象方法中的this指向当前对象,切勿混淆。


4.5 对象的遍历(循环获取所有属性)

遍历对象常用for…in循环,专门用于循环对象的可枚举属性,获取所有键名,再通过键名取值。

let person = { name: "张三", age: 20, gender: "男" };
// for...in遍历对象
for(let key in person) {
  // key是属性名,person[key]是属性值
  console.log("属性名:" + key + ",属性值:" + person[key]);
}


4.6 对象的核心特性

  1. 引用类型特性:对象赋值是传递内存地址,不是拷贝数据,修改新对象会影响原对象。
    let obj1 = { name: "张三" }; let obj2 = obj1; // 传递地址 obj2.name = "李四"; console.log(obj1.name); // 李四(原对象被修改)

  2. 属性名特性:对象的键(属性名)会自动转为字符串,数字键也会转为字符串类型。

  3. 动态特性:对象的属性和方法可以随时增删改,无需提前固定结构。

  4. 方法简写:ES6支持对象方法简写,省略function关键字,写法更简洁。
    let person = { sayHello() { // 方法简写 console.log("你好"); } };


4.7 新手常见注意事项与避坑

1. 访问不存在的属性:不会报错,返回undefined,可用于判断属性是否存在。
2. 点语法和方括号语法不可混用:属性名含特殊字符、变量做属性名,必须用方括号语法。
3. 对象赋值易踩坑:想要拷贝对象而非地址,需用浅拷贝/深拷贝(基础阶段可手动遍历赋值)。
4. 属性名重复:同一对象中属性名重复,后定义的会覆盖先定义的。
5. this指向误区:对象方法单独调用时,this会丢失指向,不再指向原对象。


五、JS作用域

作用域是JS中变量、函数、对象的可访问范围,决定了代码块中变量和其他资源的可见性,是JS核心基础知识点,也是避免变量污染、排查变量报错的关键。作用域的核心作用是隔离变量,不同作用域下的同名变量不会冲突,同时控制变量的生命周期。


5.1 作用域基础核心概念

  1. 全局作用域:代码最外层的作用域,整个脚本文件、浏览器窗口或Node环境中都能访问,生命周期伴随页面/进程始终。

  2. 局部作用域:也叫函数作用域,仅在函数内部可访问,函数外部无法直接使用,函数执行完毕后变量会被销毁。

  3. 块级作用域:ES6新增,由letconst声明产生,在{}包裹的代码块(if、for、while等)内有效,代码块执行完毕变量销毁。

  4. 作用域链:内部函数访问外部函数变量时,会逐级向上查找作用域,直到全局作用域,这个层级关系就是作用域链,查找顺序是局部→外层→全局

核心注意事项:JS采用词法作用域(静态作用域),作用域在代码定义时就已确定,而非执行时,这是作用域最核心的规则,切勿混淆。


5.2 作用域分类与详细用法

5.2.1 全局作用域

在任何地方都能访问的变量/函数,属于全局作用域,全局变量会挂载到浏览器的window对象(Node中挂载到global)。

产生场景
  • 代码最外层直接声明的变量、函数

  • 未使用var/let/const声明的变量(隐式全局变量,严禁使用)

  • 浏览器内置对象(window、document、console等)

// 全局变量,全局可访问
let globalNum = 100;
// 全局函数
function globalFn() {
  console.log(globalNum); // 函数内部可访问全局变量
}
globalFn();
console.log(globalNum); // 函数外部也可访问

// 隐式全局变量(无声明关键字)
function test() {
  hiddenVar = 200; // 未声明,自动变为全局变量
}
test();
console.log(hiddenVar); // 可访问,不推荐

注意事项:尽量减少全局变量的使用,过多全局变量会造成变量污染,不同代码块的同名变量互相覆盖,引发难以排查的bug;严禁使用无声明关键字的隐式全局变量。

5.2.2 函数作用域(局部作用域)

变量/函数仅在当前函数内部可访问,函数外部无法访问,函数执行结束后,内部变量会被垃圾回收机制销毁。

function outer() {
  // 函数内部变量,局部作用域
  let innerNum = 300;
  console.log(innerNum); // 内部可访问
  // 嵌套函数,内层可访问外层函数作用域
  function inner() {
    console.log(innerNum); // 访问外层函数变量
  }
  inner();
}
outer();
// 外部无法访问函数内部变量
console.log(innerNum); // 报错:innerNum is not defined

注意事项:函数作用域内的变量,优先级高于同名全局变量,就近访问;函数参数也属于当前函数的局部作用域,外部无法访问。

5.2.3 块级作用域(ES6新增)

letconst声明的变量,在{}包裹的代码块(if、for、while、switch等)内有效,代码块执行完毕,变量立即销毁,解决了ES5中变量提升、循环变量污染的问题。

// if代码块,块级作用域
if(true) {
  let blockVar = 400; // 块级变量
  const blockConst = 500; // 块级常量
  console.log(blockVar); // 内部可访问
}
// 代码块外部无法访问
console.log(blockVar); // 报错:blockVar is not defined

// for循环块级作用域
for(let i = 0; i < 3; i++) {
  console.log(i); // 每次循环都是独立块级作用域
}
console.log(i); // 报错,i仅在循环内有效

注意事项var声明的变量没有块级作用域,只有函数作用域和全局作用域,会穿透代码块;日常开发优先使用letconst,避免var带来的作用域问题。


5.3 作用域链核心原理

当在当前作用域查找一个变量时,会先在自身作用域内查找,找不到就向上一级作用域查找,逐级追溯,直到全局作用域,若全程都找不到,直接抛出is not defined错误。

// 全局作用域
let a = 1;
function fn1() {
  // fn1作用域
  let b = 2;
  function fn2() {
    // fn2作用域
    let c = 3;
    // 查找变量:先fn2→再fn1→最后全局
    console.log(a + b + c); // 1+2+3=6
  }
  fn2();
}
fn1();

注意事项:作用域链是单向向上查找,外层作用域无法访问内层作用域的变量,只有内层能访问外层,这是作用域隔离的核心规则。


5.4 变量提升与作用域的关系

5.4.1 var声明的变量提升

var声明的变量存在变量提升,会提升到当前作用域顶部,声明提前、赋值不提前,容易导致变量未赋值就使用的问题。

console.log(num); // undefined(变量提升,未赋值)
var num = 10;
// 实际执行顺序:var num; console.log(num); num=10;

5.4.2 let/const声明的变量提升

letconst存在暂时性死区(TDZ),变量会提升但不能在声明前使用,从代码块开始到声明位置,都属于暂时性死区,使用会直接报错。

console.log(letNum); // 报错:Cannot access 'letNum' before initialization
let letNum = 20;

注意事项:暂时性死区是块级作用域的重要特性,严禁在let/const声明前使用对应变量,避免语法报错;var的变量提升容易引发逻辑错误,优先弃用var。


5.5 闭包与作用域(核心延伸)

闭包:函数嵌套时,内层函数访问外层函数作用域的变量,且内层函数被外部调用,导致外层函数作用域变量无法被销毁,这种现象就是闭包。

function outer() {
  let count = 0;
  // 内层函数,形成闭包
  return function inner() {
    count++;
    console.log(count);
  }
}
const fn = outer();
fn(); // 1
fn(); // 2
// 外层函数执行完毕,count变量因闭包未被销毁

注意事项:闭包可以延长变量生命周期,但过度使用会造成内存泄漏,因为闭包占用的内存不会被自动回收,使用完毕后需手动解除引用(fn=null);闭包是作用域链的典型应用,也是高频考点。


5.6 作用域核心易错点总结

  1. var没有块级作用域,let/const有块级作用域,这是三者最核心区别

  2. 局部作用域变量优先级高于同名全局变量,就近访问,不会覆盖全局变量

  3. 作用域在代码定义时确定,而非执行时,词法作用域规则牢记

  4. 外层作用域无法访问内层作用域变量,内层可访问外层,单向查找

  5. 闭包虽好用,但需注意内存泄漏问题,及时清理引用

  6. 避免隐式全局变量,所有变量必须用var/let/const声明


六、JS事件

JS事件是前端实现交互效果的核心,指页面中元素发生的特定动作(比如点击、输入、鼠标移动等),通过编写事件处理函数,在动作触发时执行对应代码,实现网页与用户的双向互动,是前端开发必备核心知识点。


6.1 事件基础概念

事件:用户或浏览器执行的动作,如点击click、输入input、页面加载load等。
事件源:触发事件的元素,如按钮、输入框、div等。
事件处理函数:事件触发后要执行的代码逻辑,也叫事件回调。
事件绑定:将事件源、事件类型、处理函数关联起来,让元素监听对应动作。

所有事件绑定的核心目的,是让页面监听用户操作,实时做出反馈,完成表单验证、按钮交互、动态渲染等功能。

6.2 JS事件三种绑定方式

6.2.1 行内事件绑定(HTML属性绑定)

直接在HTML标签内通过on+事件名的属性绑定,写法简单,适合简单交互和临时测试,不适合复杂项目。

<!-- 点击按钮触发alert事件 -->
<button onclick="alert('行内绑定触发')">点我</button>

<!-- 绑定自定义函数 -->
<button onclick="handleClick()">点我执行函数</button>
<script>
  function handleClick() {
    console.log('行内绑定,调用自定义函数');
  }
</script>

这种方式耦合了HTML和JS代码,不利于代码维护,大型项目不推荐使用。

6.2.2 DOM对象事件绑定(on+事件名)

通过JS获取DOM元素,给元素绑定on+事件名属性,实现JS与HTML分离,是常用基础绑定方式,同一元素同一事件只能绑定一个处理函数。

// 获取按钮元素
const btn = document.querySelector('button');
// 绑定点击事件
btn.onclick = function() {
  console.log('DOM事件绑定,点击触发');
};
// 解绑事件
// btn.onclick = null;

同一元素重复绑定同一事件,后绑定的会覆盖先绑定的,无法实现多事件处理。

6.2.3 事件监听绑定(addEventListener,推荐)

通过addEventListener方法绑定事件,支持同一元素同一事件绑定多个处理函数,支持控制事件流,是现代前端标准绑定方式,兼容性好且功能强大。

const btn = document.querySelector('button');
// 语法:元素.addEventListener('事件名', 处理函数, 布尔值/配置)
btn.addEventListener('click', function() {
  console.log('事件监听绑定,第一个处理函数');
});
// 同一事件绑定多个函数,都会执行
btn.addEventListener('click', function() {
  console.log('事件监听绑定,第二个处理函数');
});

解绑需使用removeEventListener,且处理函数不能是匿名函数,需单独定义;第三个参数默认false,代表冒泡阶段触发,true代表捕获阶段触发。

6.3 JS常用事件类型分类

6.3.1 鼠标事件(用户鼠标操作)

事件名触发时机适用场景
click鼠标左键单击按钮点击、菜单切换
dblclick鼠标左键双击双击编辑、打开弹窗
mouseover鼠标移入元素(含子元素)悬浮提示、下拉菜单
mouseout鼠标移出元素(含子元素)隐藏悬浮内容
mouseenter鼠标移入元素(不含子元素)悬浮交互,无冒泡干扰
mouseleave鼠标移出元素(不含子元素)配合mouseenter使用
mousemove鼠标在元素内移动鼠标跟随、拖拽效果
mouseenter和mouseleave不会触发事件冒泡,交互更稳定,优先使用;mouseover和mouseout会受子元素影响,容易重复触发。

6.3.2 表单事件(输入框、表单操作)

事件名触发时机适用场景
input输入框内容实时变化实时搜索、字数统计
change输入框失去焦点且内容改变表单验证、下拉框选择
focus输入框获得焦点输入框高亮、提示文字
blur输入框失去焦点表单字段验证
submit表单提交时表单提交拦截、验证
submit事件默认会刷新页面,需要阻止默认行为才能实现异步提交;input事件实时触发,比change更灵敏。

6.3.3 键盘事件(键盘按键操作)

  • keydown:键盘按键按下时触发,持续按住会重复触发

  • keyup:键盘按键抬起时触发,适合获取最终输入值

键盘事件通常绑定在document或输入框上,可通过事件对象获取按键编码。

6.3.4 浏览器/页面事件

  • load:页面所有资源加载完成后触发

  • DOMContentLoaded:DOM结构加载完成就触发,无需等待图片等资源

  • resize:浏览器窗口大小改变时触发

  • scroll:页面滚动时触发

DOMContentLoaded比load触发更快,适合DOM操作初始化;scroll事件触发频率高,建议做节流优化。

6.4 事件流(事件执行顺序)

事件流描述事件在页面中传播的顺序,分为三个阶段,是理解事件冒泡和捕获的核心。

  1. 捕获阶段:从最外层document向内层事件源传递,从上到下

  2. 目标阶段:到达触发事件的元素本身

  3. 冒泡阶段:从内层事件源向外层document传递,从下到上(默认执行阶段)

默认情况下,事件监听在冒泡阶段执行,addEventListener第三个参数设为true,可切换为捕获阶段执行。

6.5 事件冒泡与事件捕获

6.5.1 事件冒泡(默认)

子元素事件触发后,会逐级向上触发父元素、祖先元素的同名事件,直到document。

<div class="parent">
  <button class="child">点我</button>
</div>
<script>
  const parent = document.querySelector('.parent');
  const child = document.querySelector('.child');
  // 子元素点击
  child.addEventListener('click', function() {
    console.log('子元素点击');
  });
  // 父元素点击,会被子元素冒泡触发
  parent.addEventListener('click', function() {
    console.log('父元素点击(冒泡触发)');
  });
</script>

事件冒泡会导致意外触发父元素事件,影响交互逻辑,需要手动阻止。

6.5.2 阻止事件冒泡

通过事件对象的stopPropagation方法,阻止事件继续向上传播。

child.addEventListener('click', function(e) {
  // 阻止冒泡
  e.stopPropagation();
  console.log('子元素点击,不触发父元素');
});

stopPropagation只阻止冒泡,不影响当前元素自身的事件执行。

6.5.3 事件捕获

addEventListener第三个参数设为true,事件在捕获阶段执行,先触发父元素,再触发子元素,日常开发使用较少,多用于特殊交互场景。

6.6 事件对象(e/event)

事件触发时,浏览器会自动生成事件对象,包含事件相关信息,作为参数传递给处理函数,通常用e或event表示。

常用属性和方法

  • e.target:实际触发事件的元素(事件源)

  • e.currentTarget:绑定事件的元素

  • e.preventDefault():阻止元素默认行为

  • e.stopPropagation():阻止事件冒泡

  • e.key:键盘事件中,获取按下的按键

// 阻止a标签默认跳转
const link = document.querySelector('a');
link.addEventListener('click', function(e) {
  e.preventDefault();
  console.log('阻止a标签默认跳转');
});

所有事件处理函数都能接收事件对象,匿名函数和具名函数都可直接获取;preventDefault常用于阻止表单提交、a标签跳转等默认行为。

6.7 事件委托(事件代理,重点)

利用事件冒泡原理,将子元素的事件绑定到父元素上,通过e.target判断实际触发的子元素,实现事件批量绑定,适合动态生成的元素。

<ul class="list">
  <li>列表项1</li>
  <li>列表项2</li>
  <!-- 动态新增的li也能触发事件 -->
</ul>
<script>
  const list = document.querySelector('.list');
  // 父元素委托事件
  list.addEventListener('click', function(e) {
    // 判断触发元素是否为li
    if(e.target.tagName === 'LI') {
      console.log('点击了列表项', e.target.innerText);
    }
  });
</script>

事件委托减少事件绑定数量,提升性能,动态添加的元素无需重新绑定事件,是前端高频实用技巧。

6.8 JS事件核心注意事项

  1. 行内事件绑定耦合HTML与JS,项目开发优先用事件监听addEventListener

  2. 同一元素用on+事件名绑定,重复绑定会覆盖,addEventListener可绑定多个处理函数

  3. 事件冒泡是默认机制,容易引发交互bug,不确定时可主动阻止冒泡

  4. 事件对象e是自动传递的,无需手动传参,直接在函数内接收即可

  5. 动态生成的元素,无法直接绑定事件,必须用事件委托解决

  6. preventDefault阻止默认行为,stopPropagation阻止冒泡,二者功能不同,不可混用

  7. 高频触发事件(scroll、mousemove),建议做节流或防抖,避免性能损耗

七、JS比较、逻辑运算符【操作符补充1】

比较运算符和逻辑运算符是JS中实现条件判断、逻辑分支的核心工具,二者常配合if语句、循环语句使用,运算结果均为布尔值(truefalse)。


7.1 比较运算符

比较运算符用于对两个数据进行大小、相等性对比,执行后返回唯一布尔值结果,是所有条件判断的基础,分为相等判断大小比较两大类,使用时需重点区分宽松对比和严格对比的差异。

7.1.1 相等性比较运算符(核心高频)

运算符名称核心规则代码示例执行结果
==宽松相等仅对比数据的值,自动进行隐式类型转换,不校验数据类型10 == ‘10’true
===严格相等同时对比值和数据类型,不做任何隐式转换,完全一致才返回true10 === ‘10’false
!=宽松不等宽松相等的反向,值不同则返回true,支持隐式类型转换10 != ‘10’false
!==严格不等严格相等的反向,值或类型任意一项不同,返回true10 !== ‘10’true
关键注意事项:日常开发中**===!==** 必须优先使用严格相等和严格不等,宽松相等==的隐式类型转换极易引发逻辑bug,例如0 == ''null == undefined均返回true,不符合常规判断逻辑,需坚决避免使用。

7.1.2 大小比较运算符

运算符含义代码示例执行结果
>大于15 > 8true
<小于15 < 8false
>=大于等于20 >= 20true
<=小于等于20 <= 18false
关键注意事项:大小比较默认适用于数值类型,若对比字符串,会按照字符Unicode编码逐位对比,而非数值大小,例如'9' > '10'返回true,因为字符’9’的编码大于’1’,此类场景需先将字符串转为数值再对比;对比NaN时,所有比较结果均为false,判断NaN需用isNaN()方法。

7.2 逻辑运算符

逻辑运算符用于连接多个比较条件,实现复杂逻辑判断,同样返回布尔值,也可用于布尔值取反、短路运算等场景,包含逻辑与、逻辑或、逻辑非三种,是组合条件的核心工具。

7.2.1 三大逻辑运算符详情

运算符名称逻辑规则代码示例执行结果
&逻辑与(且)所有条件全为true,结果才为true;一假则假18 > 10 && 5 < 8true
``逻辑或(或)任意一个条件为true,结果就为true;一真则真
!逻辑非(取反)单目运算符,直接对布尔值取反,true变false,false变true!(18 > 10)false

7.2.2 实际业务场景示例

let age = 22;
let score = 85;
// 逻辑与:两个条件同时满足
console.log(age >= 18 && score >= 60); // true

// 逻辑或:满足任一条件
console.log(age < 18 || score < 60); // false

// 逻辑非:取反判断
console.log(!(score >= 90)); // true

7.2.3 核心注意事项

逻辑运算符存在短路运算特性,可提升代码执行效率:逻辑与&&遇到第一个false条件,直接返回false,后续条件不再执行;逻辑或||遇到第一个true条件,直接返回true,后续条件不再执行。非布尔值参与逻辑运算时,会先转为布尔值再判断,0、''、null、undefined、NaN会转为false,其余数据转为true;连续使用逻辑非(!!)可快速将任意数据转为布尔值,例如!!'hello'返回true。


7.3 两类运算符综合速记

  1. 比较运算符最终返回true/false,相等判断**===!==** 只用和,杜绝隐式转换风险

  2. 字符串做大小对比,务必先通过Number()转换为数值类型

  3. 逻辑与&amp;&amp;需全满足,逻辑或||满足其一即可,逻辑非!直接取反

  4. 短路运算可优化代码执行,避免无效条件判断

  5. 两类运算符常配合使用,实现复杂多条件分支逻辑

八、JS this关键字

this是JavaScript中的关键字,指向一个运行时确定的对象,并非定义时确定,核心作用是简化对象调用、实现函数复用,是JS核心难点也是高频考点。this的指向完全取决于函数的调用方式,而非函数声明位置,牢记绑定规则即可精准判断指向。


8.1 this核心基础认知

this是函数执行时,自动生成的一个内置对象,指向当前函数执行的上下文对象;普通函数独立调用时,this默认指向全局对象(浏览器中为window,Node环境中为globalThis/undefined),严格模式下普通函数独立调用this指向undefined,避免全局污染。

所有判断this指向的核心原则:谁调用函数,this就指向谁,结合调用场景逐一对应规则,即可快速锁定指向。


8.2 this五大绑定规则(按优先级排序)

8.2.1 new绑定(优先级最高)

使用new关键字调用构造函数时,this指向new创建的实例对象,new会强制改变this指向,优先级高于其他所有绑定规则。

function Person(name) {
  // this指向new创建的实例对象
  this.name = name;
}
const p = new Person('张三');
console.log(p.name); // 张三

注意:构造函数中无需手动return对象,new会自动返回实例,若手动return普通对象,this会指向该返回对象,return基本数据类型则不影响this指向。

8.2.2 显式绑定(call/apply/bind)

通过call()、apply()、bind()方法手动指定this指向,优先级高于隐式绑定和默认绑定,三者均可强制改变this指向,区别仅在于传参和执行方式。

  • call():立即执行函数,参数逐个传递

  • apply():立即执行函数,参数以数组形式传递

  • bind():不立即执行,返回一个绑定好this的新函数,永久绑定this,后续无法更改

const obj = { name: '李四' };
function sayHi(age, gender) {
  console.log(this.name, age, gender);
}
// call传参
sayHi.call(obj, 20, '男');
// apply传参
sayHi.apply(obj, [20, '男']);
// bind返回新函数
const newFn = sayHi.bind(obj, 20, '男');
newFn();

注意:call/apply/bind第一个参数为null/undefined时,默认绑定失效,this指向全局对象(非严格模式),严格模式下仍指向传入的null/undefined。

8.2.3 隐式绑定

函数作为对象的方法调用时,this指向调用该方法的对象,也就是方法前面的对象,多层对象嵌套时,this指向直接调用的对象。

const user = {
  name: '王五',
  sayName: function() {
    console.log(this.name); // this指向user对象
  }
};
// 对象调用方法,隐式绑定
user.sayName(); // 王五

// 多层对象嵌套
const parent = {
  name: '父对象',
  child: {
    name: '子对象',
    fn: function() {
      console.log(this.name); // this指向child子对象
    }
  }
};
parent.child.fn(); // 子对象

注意:隐式绑定容易出现this丢失问题,将对象方法赋值给独立变量后调用,会触发默认绑定,this指向全局对象。

8.2.4 默认绑定

函数独立调用(无对象调用、无new、无显式绑定)时,触发默认绑定,非严格模式下this指向全局window,严格模式下指向undefined。

// 独立调用函数
function test() {
  console.log(this); // 非严格模式:window
}
test();

// 隐式丢失后独立调用
const user = { name: '赵六', fn: function() { console.log(this.name); } };
const fn1 = user.fn;
fn1(); // undefined,this指向window,无name属性

注意:全局作用域下的函数声明,独立调用一律触发默认绑定,避免在全局函数中随意使用this,防止全局变量污染。

8.2.5. 箭头函数绑定(优先级仅次于new)

ES6箭头函数没有自己的this,继承外层作用域的this,不遵循以上四条规则,无法通过call/apply/bind改变this指向,也不能作为构造函数使用new调用。

const obj = { name: '箭头函数' };
// 普通函数this指向obj
const fn2 = function() {
  // 箭头函数继承外层fn2的this
  return () => {
    console.log(this.name);
  };
};
const arrowFn = fn2.call(obj);
arrowFn(); // 箭头函数

注意:箭头函数适合回调场景(定时器、事件监听),解决普通函数this指向混乱问题,但不适合作为对象方法和构造函数,避免this指向异常。


8.3 this绑定优先级速记

new绑定 > 显式绑定(call/apply/bind) > 隐式绑定 > 默认绑定;箭头函数无自身this,继承外层this,优先级高于普通函数的默认、隐式绑定,低于new绑定。


8.4 高频特殊场景与this指向

8.4.1 定时器中的this

setTimeout/setInterval中的普通回调函数,独立执行触发默认绑定,this指向window;箭头函数则继承外层作用域this。

const obj = { name: '定时器', fn: function() {
  setTimeout(() => {
    console.log(this.name); // 继承fn的this,指向obj
  }, 1000);
}};
obj.fn(); // 定时器

8.4.2 事件监听中的this

DOM事件监听中,普通回调函数的this指向绑定事件的DOM元素,箭头函数继承外层this,不指向DOM元素,事件监听不推荐使用箭头函数。

8.4.3 闭包中的this

闭包内的普通函数独立调用,this默认指向window,需通过缓存外层this(const that = this)或箭头函数解决指向问题。


8.5 高频易错点总结

  1. this指向只和调用方式有关,和函数声明位置、是否嵌套无关

  2. 严格模式下默认绑定this为undefined,可有效减少全局污染问题

  3. bind是永久绑定this,返回的新函数无法通过call/apply再次改变this指向

  4. 箭头函数没有arguments、没有自己的this,不能用作构造函数,无法使用new

  5. 对象方法赋值给变量后调用,会丢失隐式绑定,触发默认绑定,可通过bind固定this

  6. 判断this指向,先看是否为箭头函数,再按优先级排查new、显式、隐式、默认绑定


九、JS HTML DOM

DOM全称文档对象模型(Document Object Model),是HTML和XML文档的编程接口,它将整个网页文档解析成树状结构(DOM树),让JavaScript可以动态访问、修改网页的内容、结构和样式,实现网页的动态交互效果,是前端JS操作网页的核心基础。


9.1 DOM核心基础概念

  • 文档:整个HTML网页文档,对应DOM中的document对象,是DOM树的根节点,所有DOM操作都从document开始。

  • 元素:HTML中的各类标签,如

    、,是DOM操作的主要对象。

  • 节点:DOM树中最小单元,包含元素节点、文本节点、属性节点、注释节点等,其中元素节点是最常用操作对象。

  • DOM树:网页标签按照嵌套关系形成的层级树结构,父子节点、兄弟节点关系明确,方便层级查找。


9.2 DOM元素获取(核心操作第一步)

想要操作网页元素,首先要通过JS获取到对应的DOM元素,以下是高频常用的获取方法,覆盖绝大多数场景:

获取方法语法格式返回结果适用场景
根据ID获取document.getElementById(‘id名’)单个元素对象/null获取唯一元素,ID具有唯一性,效率最高
根据类名获取document.getElementsByClassName(‘类名’)类数组对象(HTMLCollection)获取多个同类名元素
根据标签名获取document.getElementsByTagName(‘标签名’)类数组对象(HTMLCollection)获取同类标签元素,如所有p、div
选择器获取单个document.querySelector(‘CSS选择器’)单个元素对象/null支持CSS选择器,灵活获取单个元素,推荐使用
选择器获取全部document.querySelectorAll(‘CSS选择器’)类数组对象(NodeList)支持CSS选择器,批量获取多个元素,推荐使用
关键注意:通过类数组获取的元素,不能直接操作,需通过下标索引取出单个元素后再操作,例如document.getElementsByClassName('box')[0]

9.3 DOM元素内容操作

获取元素后,可动态修改元素内部的文本、HTML结构,实现内容实时更新,常用三种操作属性:

  • innerText:仅操作元素内的纯文本内容,不解析HTML标签,安全性高,无法识别标签。
    const box = document.querySelector('.box'); // 设置纯文本 box.innerText = '更新后的文本内容';

  • innerHTML:操作元素内的HTML结构+文本,可解析HTML标签,适合动态插入标签,注意防范XSS攻击。
    // 插入HTML结构 box.innerHTML = '<h3>动态标题</h3><p>动态段落</p>';

  • textContent:类似innerText,会保留文本格式和隐藏文本,兼容性更好,推荐优先使用。


9.4 DOM元素属性操作

9.4.1 原生属性操作(自带属性,如id、src、href、title)

直接通过元素.属性名获取或修改,语法简洁,适配元素自带属性。

const img = document.querySelector('img');
// 修改src属性
img.src = 'images/new.jpg';
// 修改title属性
img.title = '新图片描述';

9.4.2 自定义属性操作

针对自定义属性(如data-开头的自定义属性),使用getAttribute()、setAttribute()、removeAttribute()方法操作。

const div = document.querySelector('div');
// 设置自定义属性
div.setAttribute('data-index', '1');
// 获取自定义属性
console.log(div.getAttribute('data-index'));
// 删除自定义属性
div.removeAttribute('data-index');

9.4.3 类名操作(样式控制核心)

  • 元素.className:直接覆盖或设置类名,会替换原有类名

  • 元素.classList.add(‘类名’):添加类名,不覆盖原有

  • 元素.classList.remove(‘类名’):移除指定类名

  • 元素.classList.toggle(‘类名’):切换类名(有则删,无则加)

  • 元素.classList.contains(‘类名’):判断是否包含该类名,返回布尔值

9.4.4 样式操作(行内样式)

通过元素.style.样式属性修改行内样式,属性名采用驼峰命名(如backgroundColor、fontSize)。

const box = document.querySelector('.box');
box.style.width = '200px';
box.style.backgroundColor = '#ccc';
box.style.fontSize = '16px';

9.5 DOM节点操作(增删改查节点)

9.5.1 创建新节点

// 创建元素节点
const newDiv = document.createElement('div');
// 创建文本节点
const textNode = document.createTextNode('新建文本');

9.5.2 添加节点到页面

  • 父元素.appendChild(子元素):追加到父元素末尾

  • 父元素.insertBefore(新元素, 参考元素):插入到参考元素前面

9.5.3 删除节点

// 父元素删除子节点
父元素.removeChild(要删除的子元素);

9.5.4 替换节点

父元素.replaceChild(新元素, 被替换元素);

9.5.5 节点层级关系查找

  • 父元素:元素.parentNode

  • 子元素:元素.children(仅获取元素子节点,推荐)、元素.childNodes(含所有节点)

  • 第一个子元素:元素.firstElementChild

  • 最后一个子元素:元素.lastElementChild

  • 上一个兄弟元素:元素.previousElementSibling

  • 下一个兄弟元素:元素.nextElementSibling


9.6 DOM事件基础(交互核心)

DOM操作常配合事件实现交互,给元素绑定事件,触发后执行对应操作,常用绑定方式:

  1. DOM0级:元素.on+事件名 = 函数(覆盖式绑定)
    const btn = document.querySelector('button'); btn.onclick = function(){ alert('点击触发') };

  2. DOM2级:元素.addEventListener(‘事件名’, 函数)(可绑定多个事件,推荐)
    btn.addEventListener('click', function(){ console.log('点击触发') });

常用DOM事件:click(点击)、input(输入)、change(内容改变)、mouseenter(鼠标移入)、mouseleave(鼠标移出)、submit(表单提交)。


9.7 DOM操作高频注意事项

  1. DOM操作必须等待HTML文档加载完成后执行,否则获取不到元素,可将script标签放在body末尾,或用DOMContentLoaded事件监听。

  2. 类数组对象不能直接调用数组方法,如需遍历可转为数组或用for循环。

  3. innerHTML插入外部内容时,注意防范XSS攻击,避免插入不可信的HTML代码。

  4. 频繁DOM操作会影响页面性能,建议先拼接好内容,再一次性插入页面。

  5. 获取不存在的元素,返回null,操作null会报错,获取后建议先判断是否存在。



  1. 使用 document.write() 可以向文档写入内容。如果在文档已完成加载后执行 document.write,整个 HTML 页面将被覆盖。 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值