JavaScript 基础入门:从概念解析到流程控制
在数字化时代,JavaScript 是全球热门编程语言,应用覆盖前端交互、Node.js 后端服务、移动应用开发等领域。其无需编译、逐行解释执行的特性,既适合初学者入门,也能满足大型复杂项目需求。本文将系统梳理 JavaScript 从基础概念到流程控制的核心知识,助力读者构建完整知识框架、掌握实用技能。
1. JavaScript 核心认知
JavaScript 本质是一种客户端脚本语言,无需编译,运行时由 JavaScript 引擎(解释器)逐行解释执行。随着 Node.js 技术的出现,JavaScript 突破了“仅客户端运行”的限制,现已广泛应用于服务器端编程,实现了“前后端统一语言”的开发模式。
1.1 浏览器与 JavaScript 的关系
浏览器的核心功能由两部分实现,二者协同完成网页的渲染与交互:
- 渲染引擎(内核):负责解析 HTML 和 CSS,将代码转换为可视化的网页界面(如 Chrome 的 Blink 引擎、Firefox 的 Gecko 引擎)。
- JS 引擎:独立于渲染引擎,专门读取并执行 JavaScript 代码(如 Chrome 的 V8 引擎,也是 Node.js 的底层引擎)。
关键说明:浏览器本身不直接执行 JS 代码,而是通过内置的 JS 引擎将源码逐行转换为机器语言,再交由计算机执行。这也是 JavaScript 被归为“脚本语言”的核心原因。

1.2 JavaScript 的三大核心组成
JavaScript 的功能覆盖“语法基础”“网页操作”“浏览器控制”,具体由以下三部分构成:

-
ECMAScript:JavaScript 的语法核心
定义了 JavaScript 的基础语法规则,包括变量声明、数据类型、运算符、语句(if-else、for 等)、函数、对象等,是所有浏览器厂商共同遵守的工业标准。 -
DOM(文档对象模型):网页内容的操作接口
将 HTML/XML 文档抽象为树形结构(DOM 树),树中的每个节点对应网页中的一个元素(如<div>、<p>)。通过 DOM 提供的 API,JavaScript 可动态修改网页的内容、结构和样式(如添加元素、修改文本、改变颜色)。 -
BOM(浏览器对象模型):浏览器窗口的控制接口
提供与浏览器窗口交互的对象和方法,允许 JavaScript 控制浏览器的行为,如打开/关闭窗口、调整窗口大小、获取浏览器版本、操作地址栏等。
1.3 JavaScript 引入
在 HTML 中引入 JavaScript 有三种方式,需根据场景选择,同时需注意代码的可维护性和性能:
1.3.1 内联脚本(事件属性绑定)
将 JS 代码直接嵌入 HTML 标签的事件属性中(如 onclick、oninput),事件触发时执行代码。
适用于极简单的交互(如点击提示、单步表单验证),不建议用于复杂逻辑。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>内联脚本示例</title>
</head>
<body>
<!-- 点击按钮弹出提示(注意单引号包裹字符串,避免与 HTML 双引号冲突) -->
<button onclick="alert('点击成功!')">点击我</button>
<!-- 输入内容实时打印到控制台(this 指向当前输入框元素) -->
<input type="text" oninput="console.log('当前输入:' + this.value)">
</body>
</html>
优缺点:
- ✅ 优点:简单直接,无需额外代码块。
- ❌ 缺点:JS 与 HTML 强耦合(代码分散在标签中),难以维护;无法实现复杂逻辑。
1.3.2 内部脚本(<script> 标签嵌入)
将 JS 代码放在 HTML 文件的 <script> 标签内,可位于 <head> 或 <body> 中。 若脚本需操作 DOM(如获取 <body> 中的元素),需确保脚本在 DOM 加载完成后执行(可通过 window.onload 或将 <script> 放在 <body> 末尾实现)。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>内部脚本示例</title>
<script>
// 等待页面所有资源(DOM、图片等)加载完成后执行
window.onload = function () {
// 1. 创建按钮元素
const button = document.createElement('button');
button.textContent = '动态创建的按钮';
// 2. 为按钮绑定点击事件
button.onclick = function () {
alert('动态按钮被点击了!');
};
// 3. 将按钮添加到页面中
document.body.appendChild(button);
};
</script>
</head>
<body>
<!-- 脚本通过 window.onload 等待 DOM 加载,此处无需额外操作 -->
</body>
</html>
优缺点:
- ✅ 优点:JS 代码集中管理,便于维护;可直接操作 DOM(需注意加载顺序)。
- ❌ 缺点:若代码量大,会增加 HTML 文件体积;无法在多个页面复用。
1.3.3 外部脚本(独立 .js 文件引入)
将 JS 代码单独存放在 .js 文件中,通过 <script> 标签的 src 属性引入 HTML。
适用于中大型项目、多页面复用相同逻辑(如公共组件、工具函数)。
- 创建外部 JS 文件(
script.js)
// script.js
window.onload = function () {
const button = document.createElement('button');
button.textContent = '外部脚本创建的按钮';
button.onclick = function () {
alert('外部脚本生效!');
};
document.body.appendChild(button);
};
- 在 HTML 中引入
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>外部脚本示例</title>
<!-- 引入外部 JS 文件(src 属性指定文件路径) -->
<script src="script.js"></script>
<!-- 若需引入多个脚本,可多次使用 <script> 标签 -->
<!-- <script src="utils.js"></script> -->
</head>
<body>
</body>
</html>
大型项目中,可添加
async或defer属性实现脚本异步加载(避免阻塞 HTML 解析):
async:脚本加载完成后立即执行(顺序不保证);defer:脚本加载完成后,等待 HTML 解析完毕再执行(顺序与引入顺序一致)。<script src="script.js" defer></script>
优缺点:
- ✅ 优点:代码与 HTML 完全分离,可维护性高;支持多页面复用;便于团队协作(分工编写 JS 和 HTML)。
- ❌ 缺点:需额外发起 HTTP 请求加载文件(可通过打包工具合并文件优化)。
1.4 JavaScript 注释
注释是代码的“说明书”,用于解释逻辑、标注功能,不会被 JS 引擎执行。规范的注释可大幅提升代码可读性和可维护性,分为以下三类:
- 单行注释:以
//开头,注释范围仅限当前行,适用于简短说明(如变量含义、代码功能)。
// 声明用户年龄变量(单行注释)
let userAge = 18;
console.log(userAge); // 打印用户年龄(行尾注释)
- 多行注释:以
/*开头、*/结尾,注释范围可跨多行,适用于复杂逻辑的说明(如函数功能、代码块用途)。
/*
* 功能:计算两个数的和
* 输入:num1(第一个数)、num2(第二个数)
* 输出:两数之和
*/
function add(num1, num2) {
return num1 + num2;
}
- 文档注释(JSDoc 规范):以
/**开头、*/结尾,是一种标准化的多行注释,可通过工具(如 JSDoc、VS Code 插件)自动生成 HTML 文档,适用于函数、类、模块的说明。
/**
* 计算两个数的乘积
* @param {number} num1 - 第一个乘数(必须为数字)
* @param {number} num2 - 第二个乘数(必须为数字)
* @returns {number} 两个数的乘积
* @example multiply(2, 3) // 返回 6
*/
function multiply(num1, num2) {
return num1 * num2;
}
1.5 JavaScript 输入输出语句
输入输出是与用户交互、调试代码的核心手段,浏览器提供了以下常用方法:
| 方法 | 功能描述 | 归属 | 数据流向 | 适用场景 |
|---|---|---|---|---|
alert(message) |
弹出警示框,显示文本信息 | 浏览器 | 输出 | 向用户展示简单提示(如操作结果) |
console.log(msg) |
在浏览器控制台打印信息(F12 打开控制台) | 浏览器 | 输出 | 开发者调试代码(查看变量值、执行流程) |
prompt(info, def) |
弹出输入框,接收用户输入(def 为默认值) | 浏览器 | 输入 | 收集用户简单输入(如用户名、年龄) |
confirm(msg) |
弹出确认框(含“确定”“取消”),返回布尔值 | 浏览器 | 输入+输出 | 确认用户操作(如删除数据、退出登录) |
// 1. 弹出提示
alert('欢迎使用用户信息收集工具!');
// 2. 接收用户输入(默认值为“请输入姓名”)
let userName = prompt('请输入您的姓名:', '请输入姓名');
// 3. 确认用户输入
let isConfirm = confirm(`您输入的姓名是:${userName},是否确认?`);
// 4. 打印结果到控制台(调试用)
if (isConfirm) {
console.log(`用户确认姓名:${userName}`);
alert(`欢迎您,${userName}!`);
} else {
console.log('用户取消确认');
alert('请重新输入姓名!');
}
2. 变量
变量是程序在内存中申请的一块存储数据的空间,通过“变量名”可快速访问或修改其中的数据。
2.1 变量的声明与赋值(ES5 vs ES6)
JavaScript 中声明变量的方式有三种,需注意各自的特性(尤其是作用域和可修改性):
| 声明方式 | 作用域 | 可重复声明 | 可重新赋值 | 初始化要求 | 适用场景 |
|---|---|---|---|---|---|
var |
函数级作用域 | 是 | 是 | 否 | ES5 及以前代码(不推荐) |
let |
块级作用域 | 否 | 是 | 否 | 需修改的变量(推荐) |
const |
块级作用域 | 否 | 否 | 是 | 常量(如 PI、配置项,推荐) |
// 1. var 声明(ES5,存在“变量提升”和“全局污染”问题)
var age = 18;
var age = 20; // 允许重复声明,覆盖原有值
console.log(age); // 输出 20
// 2. let 声明(ES6,块级作用域,无重复声明)
let name = 'Alice';
// let name = 'Bob'; // 报错:Identifier 'name' has already been declared
name = 'Bob'; // 允许重新赋值
console.log(name); // 输出 Bob
// 3. const 声明(ES6,常量,不可修改)
const PI = 3.14159;
// PI = 3.14; // 报错:Assignment to constant variable
const user = { name: 'Charlie' };
user.name = 'David'; // 允许修改对象内部属性(const 仅限制变量指向的地址,不限制对象内容)
console.log(user.name); // 输出 David
- 初始化:声明变量的同时赋值(推荐,避免
undefined):let score = 90; // 初始化变量 - 值覆盖:变量重新赋值后,原有值被覆盖,以最后一次赋值为准:
let score = 90; score = 95; // 覆盖原有值 console.log(score); // 输出 95 - 批量声明:使用
var或let批量声明变量(用逗号分隔):let name = 'Eve', age = 22, isStudent = true;
变量声明的特殊情况
| 场景 | 说明 | 结果 | 风险 |
|---|---|---|---|
var a; console.log(a); |
只声明,不赋值 | undefined(未定义) |
可能导致逻辑错误(如 a + 1 结果为 NaN) |
console.log(b); |
不声明,不赋值,直接使用 | 报错(ReferenceError: b is not defined) |
语法错误,代码终止执行 |
c = 10; console.log(c); |
不声明,只赋值(隐式全局变量) | 10 | 污染全局作用域,易与其他变量冲突(严格模式下报错) |
严格模式(
'use strict'):在脚本开头添加该语句,可禁止隐式全局变量、禁止重复声明等,提升代码规范性:'use strict'; c = 10; // 报错:ReferenceError: c is not defined
2.2 变量命名规范(行业标准)
变量名需遵循“合法、易读、语义化”原则,具体规则如下:
2.2.1 语法规则(必须遵守)
- 可包含:字母(A-Z, a-z)、数字(0-9)、下划线(
_)、美元符号($); - 不能以数字开头(如
123name非法); - 区分大小写(
userName和username是两个不同变量); - 不能使用 JavaScript 关键字(如
var、let、function)和保留字(如class、enum)。
2.2.2 风格规范(推荐遵守)
- 小驼峰命名法(变量、函数):首字母小写,后续单词首字母大写(如
userName、getUserInfo); - 语义化命名:变量名需体现数据含义(如
age而非a,totalScore而非ts); - 避免缩写:除非是通用缩写(如
id、url),否则不使用模糊缩写(如usr不如user清晰)。
- 规范与不规范命名对比
不规范命名 问题 规范命名 a语义不清晰 ageuser_name不符合小驼峰 userName123score以数字开头 score123let使用关键字 letValue
2.3 变量数据类型
JavaScript 是弱类型(动态类型)语言:无需提前声明变量类型,变量类型由赋值的值自动决定,且可动态改变。
2.3.1 数据类型分类
JavaScript 数据类型分为:简单数据类型(基本类型)和 复杂数据类型(引用类型):
| 类型分类 | 具体类型 | 说明 | 示例 |
|---|---|---|---|
| 简单数据类型 | Number |
数字(整数、小数、特殊值) | 10、3.14、Infinity |
String |
字符串(文本,需用引号包裹) | "Hello"、'JavaScript' |
|
Boolean |
布尔值(逻辑判断,仅 true/false) |
true、false |
|
Undefined |
未定义(变量声明未赋值) | let a;(a 为 Undefined) |
|
Null |
空值(变量指向“无”) | let b = null; |
|
| 复杂数据类型 | Object |
对象(键值对集合,如数组、函数、DOM 元素) | { name: 'Alice' }、[1,2,3] |
2.3.2 简单数据类型详解
1. 数字型(Number)
-
包含范围:整数(如
10)、小数(如3.14)、特殊值(Infinity、-Infinity、NaN); -
进制表示:
- 十进制:默认(如
10); - 八进制:以
0开头(如012等于十进制10); - 十六进制:以
0x开头(如0xA等于十进制10);
- 十进制:默认(如
-
特殊值说明:
Infinity:无穷大(如1 / 0);-Infinity:无穷小(如-1 / 0);NaN:非数字(Not a Number,如'abc' - 1),且NaN !== NaN(唯一不等于自身的值)。
-
判断是否为数字:
isNaN(value)函数,返回true表示“非数字”,false表示“数字”:console.log(isNaN(123)); // false(123 是数字) console.log(isNaN('123')); // false('123' 可隐式转换为数字) console.log(isNaN('abc')); // true('abc' 无法转换为数字) -
浮点数精度问题:JavaScript 浮点数精度有限(最高 17 位小数),避免直接比较浮点数:
console.log(0.1 + 0.2); // 输出 0.30000000000000004(非 0.3) // 正确比较方式:判断差值的绝对值是否小于极小值(如 1e-10) console.log(Math.abs(0.1 + 0.2 - 0.3) < 1e-10); // true
2. 字符串型(String)
-
语法规则:需用单引号(
')、双引号(")或反引号(`,ES6 新增)包裹,推荐单引号或反引号; -
引号嵌套:遵循“外单内双”或“外双内单”,避免冲突:
let str1 = 'He said: "Hello!"'; // 外单内双 let str2 = "She's a student"; // 外双内单 -
反引号特性(ES6 模板字符串):
- 支持多行字符串(无需
\n); - 支持变量插值(
${变量名});
let name = 'Alice'; let age = 18; // 多行字符串 + 变量插值 let info = `Name: ${name} Age: ${age}`; console.log(info); // 输出: // Name: Alice // Age: 18 - 支持多行字符串(无需
-
字符串转义符:以
\开头,用于表示特殊字符:转义符 说明 示例 \n换行 "Line1\nLine2"\\反斜杠 "C:\\Users"\'单引号 'He\'s here'\"双引号 "She said \"Hi\""\t制表符(Tab 缩进) "Name:\tAlice" -
字符串长度:通过
length属性获取字符串的字符个数(包含空格和转义符):let str = 'Hello World!'; console.log(str.length); // 输出 12(空格和感叹号均算一个字符) -
字符串拼接:使用
+运算符,规则为“字符串 + 任何类型 = 新字符串”(非字符串会先转为字符串):console.log('Age: ' + 18); // 输出 "Age: 18"(数字 18 转为字符串) console.log('Hello' + ' ' + 'World'); // 输出 "Hello World"(字符串拼接) console.log('100' + 20); // 输出 "10020"(数字 20 转为字符串)口诀:“数值相加,字符相连”——若
+两边均为数字,则执行加法;否则执行字符串拼接。
3. 布尔型(Boolean)
- 取值:仅
true(真,等价于数字1)和false(假,等价于数字0); - 与其他类型的转换:
- 布尔值与数字相加时,
true按1计算,false按0计算:console.log(true + 1); // 输出 2 console.log(false + 1); // 输出 1 - 其他类型转为布尔值的规则:
类型 转为 false的情况转为 true的情况Number 0、NaN非 0且非NaN(如1、3.14)String 空字符串( "")非空字符串(如 "abc"、" ")Undefined undefined- Null null- Object - 所有对象(如 {}、[])
- 布尔值与数字相加时,
4. Undefined 与 Null
-
Undefined:变量声明未赋值时的默认值,或函数无返回值时的返回值:
let a; console.log(a); // 输出 undefined function noReturn() {} console.log(noReturn()); // 输出 undefined- 与其他类型运算的结果:
console.log('Hello' + undefined); // 输出 "Helloundefined" console.log(1 + undefined); // 输出 NaN console.log(true + undefined); // 输出 NaN
- 与其他类型运算的结果:
-
Null:表示“空值”,通常用于主动清空变量(如释放对象引用):
let obj = { name: 'Alice' }; obj = null; // 清空 obj 的引用,释放内存- 与其他类型运算的结果:
console.log('Hello' + null); // 输出 "Hellonull" console.log(1 + null); // 输出 1(null 等价于 0) console.log(true + null); // 输出 1(null 等价于 0)
- 与其他类型运算的结果:
-
区别:
undefined表示“未定义”(变量未赋值),null表示“空”(变量主动清空);typeof null返回object(历史遗留问题),typeof undefined返回undefined。
2.4 获取变量类型:typeof 运算符
typeof 用于检测变量的数据类型,返回值为字符串(如 "number"、"string"),语法为 typeof 变量名 或 typeof(变量名)。
let num = 10;
let str = 'Hello';
let bool = true;
let undef;
let nul = null;
let obj = { name: 'Alice' };
console.log(typeof num); // 输出 "number"
console.log(typeof str); // 输出 "string"
console.log(typeof bool); // 输出 "boolean"
console.log(typeof undef); // 输出 "undefined"
console.log(typeof nul); // 输出 "object"(历史遗留问题,需注意)
console.log(typeof obj); // 输出 "object"
- 注意:
typeof null的特殊情况
typeof null 返回 object 是 JavaScript 的历史 bug(早期实现中,null 被视为空对象指针),需通过其他方式判断 null:
let nul = null;
console.log(nul === null); // 输出 true(直接比较值)
2.5 数据类型转换
在实际开发中,经常需要将一种数据类型转换为另一种(如将表单输入的字符串转为数字进行计算),主要分为“显式转换”和“隐式转换”。
2.5.1 转换为字符串(3种方式)
| 方式 | 语法 | 说明 | 示例 |
|---|---|---|---|
toString() 方法 |
变量.toString() |
适用于 Number、Boolean 等类型,null 和 undefined 无此方法 |
let num = 10; num.toString(); // "10" |
String() 函数 |
String(变量) |
通用方法,可转换所有类型 | String(null); // "null" |
字符串拼接(+ "") |
变量 + "" |
隐式转换,简单高效 | let num = 10; num + ""; // "10" |
let num = 10;
let bool = true;
let nul = null;
// 1. toString() 方法
console.log(num.toString()); // "10"
console.log(bool.toString()); // "true"
// console.log(nul.toString()); // 报错(null 无此方法)
// 2. String() 函数
console.log(String(num)); // "10"
console.log(String(nul)); // "null"
// 3. 字符串拼接
console.log(num + ""); // "10"
console.log(bool + ""); // "true"
2.5.2 转换为数字型(4种方式)
| 方式 | 语法 | 说明 | 示例 |
|---|---|---|---|
parseInt() 函数 |
parseInt(字符串) |
提取整数(忽略非数字字符,从左到右),不处理小数 | parseInt("123abc"); // 123 parseInt("12.34"); // 12 |
parseFloat() 函数 |
parseFloat(字符串) |
提取浮点数(支持小数),同样忽略非数字字符 | parseFloat("12.34abc"); // 12.34 |
Number() 函数 |
Number(变量) |
严格转换,仅纯数字字符串可转为数字,否则为 NaN |
Number("123"); // 123 Number("12a"); // NaN |
隐式转换(- * /) |
字符串 - 0 / 字符串 * 1 |
利用算术运算符触发隐式转换,效果同 Number() |
"123" - 0; // 123 "12a" * 1; // NaN |
<input type="text" id="scoreInput" placeholder="请输入成绩">
<button onclick="calculate()">计算成绩等级</button>
<script>
function calculate() {
// 1. 获取表单输入(默认是字符串)
let scoreStr = document.getElementById("scoreInput").value;
// 2. 转换为数字(使用 parseInt(),成绩为整数)
let score = parseInt(scoreStr);
// 3. 判断是否为有效数字
if (isNaN(score) || score < 0 || score > 100) {
alert("请输入 0-100 之间的有效数字!");
return;
}
// 4. 计算等级
let grade = score >= 90 ? "A" : (score >= 80 ? "B" : "C");
alert(`您的成绩等级是:${grade}`);
}
</script>
2.5.3 转换为布尔型(2种方式)
| 方式 | 语法 | 说明 | 示例 |
|---|---|---|---|
Boolean() 函数 |
Boolean(变量) |
显式转换,遵循“假值规则” | Boolean(""); // false Boolean(1); // true |
逻辑非(!!) |
!!变量 |
隐式转换,两次取反(第一次转为布尔值,第二次恢复原布尔值) | !!0; // false !!"abc"; // true |
let emptyStr = "";
let num = 10;
let undef;
console.log(Boolean(emptyStr)); // false
console.log(Boolean(num)); // true
console.log(Boolean(undef)); // false
console.log(!!emptyStr); // false
console.log(!!num); // true
console.log(!!undef); // false
假值规则:以下值会转为
false,其余均转为true:
- 空字符串(
"")- 数字
0和NaNundefined和null
3. 运算符
运算符(Operator)是用于操作变量或值的符号,实现赋值、算术计算、比较判断等功能。JavaScript 中的运算符种类繁多,需重点掌握常用类型的用法和优先级。
3.1 算术运算符
用于执行基本的数学运算,包括加、减、乘、除、取余(模)。
| 运算符 | 名称 | 功能 | 示例 | 结果 |
|---|---|---|---|---|
+ |
加法 | 两数相加 / 字符串拼接 | 10 + 20 / "10" + 20 |
30 / "1020" |
- |
减法 | 两数相减 | 20 - 10 |
10 |
* |
乘法 | 两数相乘 | 10 * 20 |
200 |
/ |
除法 | 两数相除(结果为浮点数) | 20 / 10 / 20 / 3 |
2 / 6.666... |
% |
取余(模) | 返回除法的余数(符号与被除数一致) | 9 % 2 / -9 % 2 |
1 / -1 |
- 加法的双重含义:若
+两边均为数字,执行加法;否则执行字符串拼接(见 2.3.2 字符串拼接)。 - 除法的浮点数结果:即使整除,结果也为浮点数(如
10 / 2 = 5,但类型为Number)。 - 取余的应用场景:判断奇偶数(
num % 2 === 0为偶数)、循环周期(如每隔 3 次执行一次操作)。
示例:取余判断奇偶数
function isEven(num) {
// 若 num 为偶数,返回 true;否则返回 false
return num % 2 === 0;
}
console.log(isEven(10)); // true
console.log(isEven(11)); // false
3.2 递增/递减运算符
用于实现变量“自加 1”或“自减 1”,是 num = num + 1 / num = num - 1 的简写,分为“前置”和“后置”两种形式。
| 运算符 | 名称 | 语法 | 执行顺序 | 示例 | 结果 |
|---|---|---|---|---|---|
++ |
前置递增 | ++num |
先自加,后使用变量值 | let num = 10; console.log(++num); |
11(num 变为 11) |
++ |
后置递增 | num++ |
先使用变量值,后自加 | let num = 10; console.log(num++); |
10(num 变为 11) |
-- |
前置递减 | --num |
先自减,后使用变量值 | let num = 10; console.log(--num); |
9(num 变为 9) |
-- |
后置递减 | num-- |
先使用变量值,后自减 | let num = 10; console.log(num--); |
10(num 变为 9) |
示例:前置与后置的区别
// 1. 前置递增
let a = 10;
let b = ++a; // a 先自加为 11,再赋值给 b
console.log(a); // 11
console.log(b); // 11
// 2. 后置递增
let c = 10;
let d = c++; // c 先赋值给 d(d=10),再自加为 11
console.log(c); // 11
console.log(d); // 10
应用:循环计数器
// 使用后置递增实现循环(i 从 0 到 4)
for (let i = 0; i < 5; i++) {
console.log(i); // 输出 0,1,2,3,4
}
3.3 比较运算符
用于比较两个值的关系,返回结果为布尔值(true 或 false),常用于分支判断(if)和循环条件(for/while)。
| 运算符 | 名称 | 功能 | 示例 | 结果 |
|---|---|---|---|---|
< |
小于 | 左值 < 右值? | 10 < 20 |
true |
> |
大于 | 左值 > 右值? | 10 > 20 |
false |
<= |
小于等于 | 左值 ≤ 右值? | 10 <= 10 |
true |
>= |
大于等于 | 左值 ≥ 右值? | 10 >= 20 |
false |
== |
相等(松散比较) | 左值 == 右值?(忽略类型,先隐式转换) | 10 == "10" |
true |
!= |
不相等(松散比较) | 左值 != 右值?(忽略类型) | 10 != "10" |
false |
=== |
全等(严格比较) | 左值 === 右值?(要求值和类型均一致) | 10 === "10" |
false |
!== |
不全等(严格比较) | 左值 !== 右值?(值或类型不一致) | 10 !== "10" |
true |
关键注意:== 与 === 的区别(重点)
==(松散比较):会先将两边的值转为同一类型(隐式转换),再比较值是否相等;===(严格比较):不进行类型转换,直接比较值和类型是否均一致(推荐使用,避免隐式转换导致的意外结果)。
示例:== 的隐式转换问题
console.log(0 == ""); // true(0 转为 false,"" 转为 false,false == false)
console.log(null == undefined); // true(特殊规则)
console.log(1 == true); // true(1 转为 true)
// 严格比较可避免这些问题
console.log(0 === ""); // false(类型不同)
console.log(null === undefined); // false(类型不同)
console.log(1 === true); // false(类型不同)
3.4 逻辑运算符
用于组合多个布尔值条件,返回结果仍为布尔值,主要有“与”“或”“非”三种,常用于复杂条件判断。
| 运算符 | 名称 | 语法 | 逻辑规则 | 示例 | 结果 |
|---|---|---|---|---|---|
&& |
逻辑与(AND) | 条件1 && 条件2 |
两边均为 true,结果才为 true(一假则假) |
true && false |
false |
| ` | ` | 逻辑或(OR) | `条件1 | ||
! |
逻辑非(NOT) | !条件 |
取反(true 变 false,false 变 true) |
!true |
false |
示例:组合条件判断
let age = 18;
let hasId = true;
// 逻辑与:同时满足“年龄≥18”和“有身份证”,才能进入
let canEnter = age >= 18 && hasId;
console.log(canEnter); // true
// 逻辑或:满足“年龄≥60”或“有老年证”,即可享受优惠
let hasDiscount = age >= 60 || hasId === false;
console.log(hasDiscount); // false
// 逻辑非:取反“能进入”的结果
let cannotEnter = !canEnter;
console.log(cannotEnter); // false
短路运算(逻辑中断)
逻辑运算符具有“短路特性”:若左边的条件已能确定最终结果,右边的条件将不再执行(提升性能)。
- 逻辑与(
&&)的短路规则
- 若
条件1为false,则无需判断条件2,直接返回条件1的值;- 若
条件1为true,则返回条件2的值(需判断条件2)。
// 条件1 为 false,短路(不执行条件2)
console.log(false && console.log("条件2")); // 输出 false(条件2 未执行)
// 条件1 为 true,执行条件2 并返回其值
console.log(true && "条件2结果"); // 输出 "条件2结果"
- 逻辑或(
||)的短路规则
- 若
条件1为true,则无需判断条件2,直接返回条件1的值;- 若
条件1为false,则返回条件2的值(需判断条件2)。
// 若 userName 未赋值(undefined),则使用默认值 "Guest"
let userName = undefined;
let displayName = userName || "Guest";
console.log(displayName); // 输出 "Guest"
// 若 userName 已赋值,则使用该值
userName = "Alice";
displayName = userName || "Guest";
console.log(displayName); // 输出 "Alice"
3.5 赋值运算符
用于将值赋给变量,或在赋值的同时执行算术运算(复合赋值)。
| 运算符 | 名称 | 语法 | 等价于 | 示例 | 结果 |
|---|---|---|---|---|---|
= |
简单赋值 | num = 10 |
- | let num; num = 10 |
num = 10 |
+= |
加后赋值 | num += 5 |
num = num + 5 |
let num = 10; num += 5 |
num = 15 |
-= |
减后赋值 | num -= 5 |
num = num - 5 |
let num = 10; num -= 5 |
num = 5 |
*= |
乘后赋值 | num *= 5 |
num = num * 5 |
let num = 10; num *= 5 |
num = 50 |
/= |
除后赋值 | num /= 5 |
num = num / 5 |
let num = 10; num /= 5 |
num = 2 |
%= |
取余后赋值 | num %= 5 |
num = num % 5 |
let num = 10; num %= 3 |
num = 1 |
示例:复合赋值的应用
let score = 80;
score += 5; // 等价于 score = score + 5 → 85
score *= 0.8; // 等价于 score = score * 0.8 → 68
console.log(score); // 输出 68
3.6 运算符优先级
当多个运算符同时出现时,遵循“优先级高的先执行”的规则,若优先级相同则从左到右执行。以下是常用运算符的优先级(从高到低):
| 优先级 | 运算符类型 | 具体运算符 | 说明 |
|---|---|---|---|
| 1 | 括号 | () |
改变运算顺序,优先级最高 |
| 2 | 一元运算符 | ++、--、! |
自增/自减、逻辑非 |
| 3 | 算术运算符 | *、/、% → +、- |
先乘除取余,后加减 |
| 4 | 关系运算符 | >、>=、<、<= → ==、!=、===、!== |
先比较大小,后判断相等 |
| 5 | 逻辑运算符 | && → ` |
|
| 6 | 赋值运算符 | =、+=、-= 等 |
优先级最低 |
| 7 | 逗号运算符 | , |
分隔多个表达式,优先级最低 |
示例:复杂表达式的执行顺序
// 计算:(3 + 2) * 4 > 10 && !false
let result = (3 + 2) * 4 > 10 && !false;
// 执行步骤:
// 1. 括号:3 + 2 = 5
// 2. 算术运算:5 * 4 = 20
// 3. 关系运算:20 > 10 = true
// 4. 一元运算符:!false = true
// 5. 逻辑与:true && true = true
console.log(result); // 输出 true
口诀:“括号优先,一元其次,算术关系,逻辑赋值,逗号最后”——不确定时,直接用括号明确顺序(可读性优先)。
4. 流程控制
默认情况下,JavaScript 代码按“从上到下、从左到右”的顺序执行(顺序结构)。但实际开发中,需根据条件执行不同代码(分支结构)或重复执行某段代码(循环结构),这就是流程控制。
4.1 流程控制的三种结构

- 顺序结构:代码默认执行方式,从上到下依次执行(如变量声明、赋值);
- 分支结构:根据条件判断,选择执行不同代码块(如 if、switch);
- 循环结构:根据条件,重复执行某段代码块(如 for、while)。
4.2 分支结构(条件判断)
分支结构用于“根据不同情况做不同事情”,JavaScript 提供两种分支语句:if 语句和 switch 语句。
4.2.1 if 语句
if 语句根据条件表达式的布尔值(true/false)决定是否执行代码块,分为“单分支”“双分支”“多分支”三种形式。
- 单分支 if 语句(满足条件才执行)
if (条件表达式) {
// 条件为 true 时执行的代码块(若只有一行代码,可省略大括号,但不推荐)
}
// 判断年龄是否成年
let age = 18;
if (age >= 18) {
console.log("您已成年,可独立办理业务!");
}
- 双分支 if-else 语句(二选一)
if (条件表达式) {
// 条件为 true 时执行的代码块
} else {
// 条件为 false 时执行的代码块
}
// 判断成绩是否及格
let score = 75;
if (score >= 60) {
console.log("成绩及格,继续加油!");
} else {
console.log("成绩不及格,需要补考!");
}
- 多分支 if-else if 语句(多选一)
if (条件表达式1) {
// 条件1 为 true 时执行
} else if (条件表达式2) {
// 条件1 为 false,条件2 为 true 时执行
} else if (条件表达式3) {
// 条件1、2 为 false,条件3 为 true 时执行
} else {
// 所有条件均为 false 时执行(可选)
}
// 根据成绩划分等级
let score = 85;
if (score >= 90) {
console.log("等级:A(优秀)");
} else if (score >= 80) {
console.log("等级:B(良好)");
} else if (score >= 60) {
console.log("等级:C(及格)");
} else {
console.log("等级:D(不及格)");
}
注意:多分支语句中,只要有一个条件满足,后续条件将不再判断(避免冗余),因此需合理安排条件顺序(如先判断范围小的条件)。
4.2.2 三元表达式
三元表达式是 if-else 双分支语句的简写形式,语法简洁,适用于简单的二选一场景。
条件表达式 ? 表达式1(条件为 true 时执行) : 表达式2(条件为 false 时执行);
// 判断奇偶性
let num = 10;
let result = num % 2 === 0 ? "偶数" : "奇数";
console.log(result); // 输出 "偶数"
应用场景:变量赋值、简单逻辑判断(不推荐用于复杂代码块,可读性差)。
4.2.3 switch 语句
switch 语句根据“表达式的值”与“case 后的值”是否全等(===),选择执行对应的代码块,适用于“固定值匹配”场景(如根据状态码、类型值判断)。
switch (表达式) {
case 值1:
// 表达式 === 值1 时执行的代码
break; // 跳出 switch 语句(避免继续执行后续 case)
case 值2:
// 表达式 === 值2 时执行的代码
break;
case 值3:
// 表达式 === 值3 时执行的代码
break;
default:
// 表达式与所有 case 值均不全等时执行的代码(可选)
break;
}
// 根据星期几显示对应活动
let week = 3; // 1=周一,2=周二,...,7=周日
switch (week) {
case 1:
console.log("周一:开会");
break;
case 2:
console.log("周二:培训");
break;
case 3:
console.log("周三:项目开发");
break;
case 4:
console.log("周四:测试");
break;
case 5:
console.log("周五:总结");
break;
case 6:
case 7: // 多个 case 共享同一代码块(周六和周日均休息)
console.log("周末:休息");
break;
default:
console.log("无效的星期数");
break;
}
break的作用:执行完某个 case 后,必须用break跳出 switch 语句,否则会继续执行后续 case(“穿透现象”);- 全等比较:
switch比较的是“全等(===)”,需确保表达式和 case 值的类型一致; default的位置:default可放在任意位置(通常在最后),若放在前面,需加break,否则会继续执行后续 case。
4.2.4 if 与 switch 的区别
| 维度 | if 语句 | switch 语句 |
|---|---|---|
| 适用场景 | 范围判断(如 score >= 60)、复杂条件组合 |
固定值匹配(如 week === 3、status === "success") |
| 比较方式 | 支持各种比较运算符(>, <, === 等) |
仅支持全等(===) |
| 可读性 | 分支少(1-3个)时清晰,分支多(>3个)时冗余 | 分支多(>3个)时结构清晰,分支少(<3个)时冗余 |
| 执行效率 | 分支越多,判断次数越多 | 直接匹配 case 值,效率较高(部分引擎优化) |
选择建议:
- 范围判断、复杂条件 → 用
if语句; - 固定值匹配(如状态码、类型、枚举值) → 用
switch语句。
4.3 循环结构(重复执行)
循环结构用于“重复执行某段代码,直到满足退出条件”,JavaScript 提供四种循环语句:for、for...in、while、do...while,其中 for 和 while 最常用。
4.3.1 for 循环
for 循环是最常用的循环语句,适用于“已知循环次数”的场景(如遍历数组、重复执行 N 次)。
for (初始化变量; 条件表达式; 操作表达式) {
// 循环体:条件表达式为 true 时执行的代码块
}
| 部分 | 作用 | 示例 |
|---|---|---|
| 初始化变量 | 声明循环计数器(仅执行一次) | let i = 0 |
| 条件表达式 | 判断是否继续循环(每次循环前执行) | i < 5 |
| 操作表达式 | 更新循环计数器(每次循环体执行后执行) | i++ |
- 执行“初始化变量”(仅一次);
- 执行“条件表达式”:
- 若为
true→ 执行循环体 → 执行“操作表达式” → 回到步骤 2; - 若为
false→ 退出循环,执行后续代码。
- 若为
示例 1:打印 1-5 的数字
// 循环 5 次(i 从 0 到 4)
for (let i = 0; i < 5; i++) {
console.log(i + 1); // 输出 1,2,3,4,5
}
示例 2:计算 1-100 的总和
let sum = 0;
// i 从 1 到 100,累加每个 i 到 sum
for (let i = 1; i <= 100; i++) {
sum += i; // 等价于 sum = sum + i
}
console.log("1-100 的总和:", sum); // 输出 5050
4.3.2 双重 for 循环
双重 for 循环是“在一个 for 循环内部再嵌套一个 for 循环”,外层循环执行一次,内层循环执行全部次数,适用于“二维数据遍历”(如矩阵、表格)。
for (外层初始化; 外层条件; 外层操作) {
// 外层循环体
for (内层初始化; 内层条件; 内层操作) {
// 内层循环体(外层执行一次,内层执行全部次数)
}
}
示例:打印 5 行 5 列的星号(*)矩阵
// 外层循环:控制行数(5 行)
for (let row = 0; row < 5; row++) {
let line = ""; // 存储当前行的星号
// 内层循环:控制每行的列数(5 列)
for (let col = 0; col < 5; col++) {
line += "* "; // 每行添加一个星号和空格
}
console.log(line); // 打印当前行
}
// 输出结果:
// * * * * *
// * * * * *
// * * * * *
// * * * * *
// * * * * *
- 变量命名:外层和内层的循环变量需区分(如
row和col),避免变量污染; - 执行顺序:外层循环执行一次,内层循环执行完所有次数(如上述示例中,外层
row=0时,内层col从 0 到 4 执行 5 次); - 性能优化:避免不必要的循环(如内层循环的条件尽量与外层无关,减少计算量)。
4.3.3 while 循环
while 循环适用于“未知循环次数”的场景(如等待用户输入正确值、处理动态数据),仅需指定“循环条件”,不直接指定次数。
while (条件表达式) {
// 循环体:条件为 true 时执行的代码块
// (必须包含更新条件的代码,否则会导致死循环)
}
- 执行“条件表达式”:
- 若为
true→ 执行循环体 → 回到步骤 1; - 若为
false→ 退出循环。
- 若为
示例:等待用户输入正确的年龄(1-120)
let age;
// 循环条件:age 未定义 或 不在 1-120 范围内
while (!age || age < 1 || age > 120) {
// 接收用户输入(转为数字)
age = parseInt(prompt("请输入您的年龄(1-120):"));
// 判断输入是否有效
if (!age || age < 1 || age > 120) {
alert("输入无效,请重新输入!");
}
}
console.log("您的年龄是:", age);
关键注意:避免死循环
while 循环必须在循环体内更新“影响条件表达式的变量”(如上述示例中的 age),否则条件将永远为 true,导致死循环(浏览器会卡顿甚至崩溃)。
- 死循环示例(错误):
let i = 0; while (i < 5) { console.log(i); // 未更新 i,i 永远为 0,条件永远为 true }
4.3.4 do…while 循环
do...while 循环与 while 循环类似,但先执行一次循环体,再判断条件,适用于“循环体至少需要执行一次”的场景(如菜单选择、表单提交验证)。
do {
// 循环体:至少执行一次的代码块
// (必须包含更新条件的代码)
} while (条件表达式); // 注意末尾的分号
- 执行“循环体”(至少一次);
- 执行“条件表达式”:
- 若为
true→ 回到步骤 1,继续执行循环体; - 若为
false→ 退出循环。
- 若为
示例:菜单选择(至少显示一次菜单)
let choice;
do {
// 显示菜单(循环体至少执行一次)
choice = prompt(`请选择操作:
1. 查看信息
2. 修改信息
3. 退出
请输入选项(1-3):`);
// 根据选择执行操作
switch (choice) {
case "1":
alert("查看信息...");
break;
case "2":
alert("修改信息...");
break;
case "3":
alert("退出程序!");
break;
default:
alert("选项无效,请重新选择!");
break;
}
// 循环条件:choice 不是 "3"(未选择退出)
} while (choice !== "3");
与 while 循环的区别
| 循环类型 | 执行顺序 | 适用场景 |
|---|---|---|
| while | 先判断条件,再执行循环体 | 可能一次都不执行(条件初始为 false) |
| do…while | 先执行循环体,再判断条件 | 至少执行一次(如菜单、表单验证) |
4.3.5 循环控制:continue 与 break
continue 和 break 用于控制循环的执行流程,可在循环体内根据条件提前跳过或终止循环。
- continue(跳过本次循环)
continue 用于“立即跳出当前次循环”,直接进入下一次循环的条件判断(后续循环体代码不再执行)。
示例:打印 1-10 中的奇数
for (let i = 1; i <= 10; i++) {
// 若 i 为偶数,跳过本次循环(不执行 console.log)
if (i % 2 === 0) {
continue;
}
console.log(i); // 输出 1,3,5,7,9
}
- break(终止整个循环)
break 用于“立即终止整个循环”,直接跳出循环体,执行循环后的代码(后续所有循环均不再执行)。
示例:查找数组中的第一个偶数
let arr = [1, 3, 5, 4, 7, 8];
let firstEven;
for (let i = 0; i < arr.length; i++) {
if (arr[i] % 2 === 0) {
firstEven = arr[i];
break; // 找到后立即终止循环(无需继续查找)
}
}
console.log("第一个偶数:", firstEven); // 输出 4
注意:在嵌套循环中的作用范围
continue 和 break 仅作用于“当前所在的循环”(内层循环中的 break 不会终止外层循环):
// 外层循环(3 次)
for (let outer = 1; outer <= 3; outer++) {
console.log("外层循环:", outer);
// 内层循环(3 次)
for (let inner = 1; inner <= 3; inner++) {
if (inner === 2) {
break; // 仅终止内层循环,外层循环继续
}
console.log(" 内层循环:", inner);
}
}
// 输出结果:
// 外层循环:1
// 内层循环:1
// 外层循环:2
// 内层循环:1
// 外层循环:3
// 内层循环:1
JavaScript 是前端开发的基石,也是全栈开发的重要工具,掌握基础后持续实践,才能在编程之路上走得更远。
更多推荐


所有评论(0)