JavaScript零基础入门:变量、数据类型与运算符详解

作者:异步漫步

时间:2026-11-06

浏览:87

面向零基础读者的JavaScript核心教程。详细讲解变量声明与作用域机制、8大数据类型及其栈堆存储原理、常用运算符求值逻辑与类型转换规律,包含完整的代码示例与直观图解。

文章目录
学习 JavaScript 的第一步,是建立对程序如何存储数据、区分数据形态以及处理数据关系的清晰认知。本文系统梳理 JavaScript 的三大核心基石:变量的声明与作用域规则、基础与引用数据类型的底层存储机制,以及常用运算符的求值逻辑与类型转换规律。读者通过文中的示例与对照分析,能够掌握规范的代码编写方式,避开初学者常见的隐式转换与作用域陷阱。
JavaScript零基础入门:变量、数据类型与运算符详解
图 1:JavaScript 核心语法三要素脉络总览

一、变量声明与作用域规范:let、const 与 var

在程序中,变量本质上是一块具有明确名称的内存空间引用,用于暂存、读取和更新数据。编写 JavaScript 代码时,我们使用声明关键字向运行环境申请创建变量。现代 JavaScript(ECMAScript 2015 / ES6 规范之后)提供了 let 与 const,并明确将老旧的 var 列为淘汰实践。

1. 选型原则:何时使用 const,何时使用 let

在实际编写代码时,变量声明遵循一条极简且安全的默认法则:优先声明为 const,仅在明确需要重新赋值时使用 let。

  • const(常量声明):用于声明初始化后不再改变引用的变量。声明时必须立即赋初值。使用 const 可以防止意外篡改,让代码意图更加明确,也是工业级代码审查的首要要求。
  • let(变量声明):用于声明后续需要改变其值的变量,例如 for 循环的计数器、累加求和变量或状态机标记。
// 声明常量:初始化后不可重新赋值
const maxRetries = 3;
const apiBaseUrl = "https://api.example.com";

// 声明可变变量:后续按需更新
let currentAttempt = 0;
currentAttempt += 1; // 合法更新

// 错误示范:尝试修改 const 会直接抛出 TypeError
// maxRetries = 5; // Uncaught TypeError: Assignment to constant variable.

2. 深度对比:为什么坚决淘汰 var

很多早期教程仍然使用 var,但现代工程已全面弃用。var 与 let/const 存在三个关键差异,这些差异直接决定了代码是否稳健:

  • 作用域隔离能力不同:var 仅具备函数作用域,无法被 if、for 等代码块 { } 限制,极易造成局部变量泄漏到全局。而 let 与 const 具备严格的块级作用域(Block Scope)。
  • 变量提升(Hoisting)与暂时性死区:var 存在提升机制,变量在声明前就能被读取,此时其值为 undefined,容易引发静默的逻辑缺陷。let 和 const 同样会发生声明提升,但在执行到声明语句之前,变量处于暂时性死区(Temporal Dead Zone, TDZ)中,任何提前访问都会直接抛出 ReferenceError,从而提前暴露代码书写顺序错误。
  • 重复声明保护:在同一作用域内,var 允许对同一个变量名反复声明而毫无警告,易发生意外覆盖;而 let 和 const 严禁重复声明同名变量。
JavaScript零基础入门:变量、数据类型与运算符详解
图 2:let 与 const 变量生命周期推导与暂时性死区(TDZ)工作机制

3. 变量命名与代码风格规范

编写清晰易读的代码离不开严谨的命名习惯:

  • 命名法:普通变量与函数统一使用小驼峰命名法(camelCase),如 userAccount、isActiveStatus。
  • 语义明确:变量名应明确表达其存储内容的含义,禁止使用无意义的单字母(除循环计数器 i、j 外)。
  • 合法字符规则:变量名必须以字母、下划线 _ 或美元符号 $ 开头,后续可包含数字;不能以数字开头,不能包含连字符 - 或空格,且绝不能使用 JavaScript 保留字(如 class、function、return 等)。

二、数据类型分类与内存模型:基本类型与引用类型

JavaScript 是一门弱类型(动态类型)语言,变量在声明时无需指定类型,数据的类型完全由其实际存储的值决定。JavaScript 中共有 8 种内置数据类型,划分为两大阵营:基本数据类型(Primitive Types) 与 引用数据类型(Reference Types)。

分类 数据类型 代表性取值示例 typeof 运算返回值 内存存储位置与特性
基本类型
(Primitive)
Number 42, 3.14, NaN, Infinity "number" 存储在栈内存(Stack)中。
占用固定大小空间,值不可变(Immutable),按值直接复制。
String "hello", 'JS', `模板` "string"
Boolean true, false "boolean"
Undefined undefined(声明未初始化) "undefined"
Null null(意图表示空对象指针) "object" (历史遗留缺陷)
Symbol Symbol("id")(全局唯一标识) "symbol"
BigInt 9007199254740993n(大整数) "bigint"
引用类型
(Reference)
Object
(含 Array, Function 等)
{ a: 1 }, [1, 2], function() {} "object"
(函数返回 "function")
实体存储在堆内存(Heap)中。
栈内存中仅保存指向堆中地址的指针,按引用地址传递。
JavaScript零基础入门:变量、数据类型与运算符详解
图 3:基本类型与引用类型的栈堆内存结构模型对比

1. 内存模型差异带来的关键行为区别

为什么区分基本类型和引用类型至关重要?核心原因在于变量赋值和修改时的物理表现完全不同:

  • 按值复制(基本类型): 当我们将一个基本类型变量赋值给另一个变量时,系统在栈内存中开辟一段全新的空间,并将数值完整复制一份。此后修改其中一个变量,对另一个变量毫无影响。
  • 按引用复制(引用类型): 当我们将一个对象或数组赋值给另一个变量时,复制的不是对象实体本身,而是栈中保存的堆内存地址指针。此时两个变量实际上指向堆内存中的同一个对象实体。通过任何一个变量修改对象的内部属性,另一个变量读取到的内容也会同步改变。
// 场景 1:基本类型的独立性
let originNum = 100;
let copyNum = originNum; // 栈内存复制值 100
copyNum = 200;
console.log(originNum);  // 输出 100,不受 copyNum 影响

// 场景 2:引用类型的共享指针
const userA = { name: "张三", age: 24 };
const userB = userA;     // 复制的是堆内存地址指针
userB.age = 25;          // 修改同一块堆内存中的属性
console.log(userA.age);  // 输出 25!userA 的属性同步被修改
避坑提醒:typeof 的历史遗留缺陷与精准类型判断

使用 typeof null 时,返回的结果是 "object"。这是 JavaScript 最初实现时的历史遗留设计缺陷(当时利用前三位判断类型,对象的类型标签是 000,而 null 指针全是 0),但在现代规范中为保证向后兼容性予以保留。
因此,判断一个变量是否为纯粹的普通对象时,务必先排除 null;判断数组时,应使用官方专门提供的 Array.isArray(val),或者使用通用的精准检测方式:Object.prototype.toString.call(val)。

三、运算符与表达式:计算逻辑与类型转换

运算符用于对一个或多个操作数进行处理并返回计算结果。掌握运算符不仅需要了解它们的语法,更要透彻理解在运算过程中发生的隐式类型转换(Type Coercion)。

1. 算术运算符与加号的双重语义

JavaScript 提供了常规的算术运算符:加法 +、减法 -、乘法 *、除法 /、取模(取余)% 以及指数 **。

其中,加号 + 具有双重语义:当任一操作数为字符串时,加号退化为字符串拼接运算符;只有当两个操作数均为数值(或可隐式转为数值的非字符串值)时,才执行数学加法。而减法、乘法、除法等运算符则始终严格尝试将两端转换为数值再执行运算。

const res1 = 5 + 10;     // 15 (数学加法)
const res2 = 5 + "10";   // "510" (字符串拼接:5 被隐式转为 "5")
const res3 = "20" - 5;   // 15 (数学减法:字符串 "20" 隐式转为数字 20)
const res4 = "abc" * 2;  // NaN ("abc" 无法转为有效数值,结果为 Not-a-Number)

2. 比较运算符:全等 === 与宽松比较 == 的本质区别

比较运算符用于对比两个操作数并返回布尔值(true 或 false)。初学者最容易踩坑的是宽松相等 == 与 全等(严格相等)=== 的区别。

  • 全等运算符(===):首先比较类型,类型不同直接判定为 false;类型相同时才进一步比较数值。绝不进行隐式转换,行为完全可预测。
  • 宽松相等(==):在比较前,若两端类型不一致,会按照一套复杂的 ECMAScript 规范将操作数强制隐式转换为同类再行比较,常常产生违背直觉的结果。
JavaScript零基础入门:变量、数据类型与运算符详解
图 4:全等比较(===)与宽松比较(==)的决策路径与隐式转换风险
工程实践硬性规范:始终使用 === 与 !==

宽松相等会带来诸如 0 == "" 返回 true、false == "0" 返回 true 以及 [] == false 返回 true 等严重违背业务常识的陷阱。现代前端工程规范(如 ESLint 规则 eqeqeq)要求全项目禁止出现 == 与 !=,必须一律使用 === 与 !==。

3. 逻辑运算符与短路求值(Short-circuit Evaluation)

逻辑运算符包括逻辑与 &&、逻辑或 || 和逻辑非 !。在 JavaScript 中,它们不仅用于布尔条件判断,还广泛利用短路求值特性来处理业务赋值:

  • 逻辑与 &&(遇假即止):从左往右求值。如果左侧表达式转换为布尔值为 false(即假值:false, 0, "", null, undefined, NaN),则直接返回左侧操作数的值;若左侧为真,则返回右侧操作数的值。常用于前置条件守卫。
  • 逻辑或 ||(遇真即止):从左往右求值。如果左侧为真值,则直接返回左侧操作数;若左侧为假值,则返回右侧操作数。常用于设置备选值。
  • 空值合并运算符 ??:由于 || 会将 0 和空字符串 "" 视作假值并替换,ES2020 引入了 ??。它仅当左侧操作数为 null 或 undefined 时才会返回右侧值,完美解决了对数值 0 的误伤问题。
// 1. 逻辑与 && 作为条件守卫
const userProfile = { isLogin: true, nickname: "小明" };
userProfile.isLogin && console.log("欢迎回来:" + userProfile.nickname);

// 2. || 与 ?? 在默认值场景下的关键差异
const userConfigScore = 0; // 用户实际得分为 0

const displayScore1 = userConfigScore || 60;
// 结果为 60!因为 0 被 || 误判为假值,导致合理的分数被错误覆盖

const displayScore2 = userConfigScore ?? 60;
// 结果为 0!正确保留了用户的有效输入,只有 null 或 undefined 才会退回 60

四、常见问题排查与知识体系总结

1. 初学者高频困惑排查

  • NaN 为什么不等于自身?
    根据 IEEE 754 浮点数标准,NaN(Not-a-Number)表示一个无法表示的无效数学运算结果。两个无效的计算结果不能被认定为相等,因此表达式 NaN === NaN 返回 false。排查变量是否为 NaN 时,切勿使用全等比较,必须调用 Number.isNaN(val)。
  • 0.1 + 0.2 为什么等于 0.30000000000000004?
    计算机底层采用二进制双精度浮点数(64位)存储数字,十进制的小数 0.1 和 0.2 转换为二进制时是无限循环小数,由于尾数位数有限导致截断舍入,相加后再转回十进制便产生了微小的精度误差。在货币或精确比对场景中,可将数值放大为整数(例如以“分”为单位)计算,或使用 Math.abs(a - b) < Number.EPSILON 确认两数是否在误差允许范围内相等。
  • undefined 与 null 的语义边界是什么?
    undefined 表示“缺少值”,即此处本该有值但尚未被定义或赋值(例如声明了未初始化的变量、函数未传参、对象不存在的属性);而 null 表示“无值”,是开发者主动赋予的语义标记,表示该变量有意被置空或表示不存在的对象引用。
JavaScript零基础入门:变量、数据类型与运算符详解
图 5:JavaScript 零基础核心语法知识体系全景思维模型

掌握变量的作用域与选型、理解基本类型与引用类型的栈堆物理内存分配,以及恪守全等运算与严格短路逻辑,构成了编写专业 JavaScript 代码不可或缺的底层基石。初学者在后续深入学习函数、异步编程与 DOM 交互时,这些核心认知将持续提供清晰的分析支点。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章