JavaScript 中 undefined 和 not defined 的区别:彻底厘清易混淆的两个概念
一、开篇:JavaScript 初学者的 "噩梦"------ 分不清的 undefined 与 not defined
在 JavaScript 开发中,undefined 和 not defined 是两个高频出现的概念,也是初学者最容易混淆的 "坑"。二者都与 "变量不存在或未赋值" 相关,但本质上是完全不同的错误类型和状态,对应的场景、报错信息及解决方案也截然不同。
很多开发者在控制台看到 ReferenceError 或打印出 undefined 时,常常无从下手,甚至误将二者等同看待。本文将从核心定义、产生场景、报错类型、检测方式四个维度,结合实战示例深度拆解二者的区别,帮你彻底厘清这两个概念,避免在开发中踩坑。
二、基础认知:先明确两个概念的核心定义
1. undefined:变量已声明但未赋值的 "默认状态"
undefined 是 JavaScript 中的 ** 原始数据类型(Primitive Type)** 之一,同时也是一个全局常量(ES5 标准化后),它表示:
- 变量已被声明,但未赋予任何值;
- 属性 / 元素在对象 / 数组中不存在;
- 函数没有返回值时的默认返回结果;
- 函数参数未被传递时的默认值。
简单来说,undefined 是一种 "已声明但未初始化" 的合法状态,不会导致程序报错,只是表示数据的 "空缺"。
2. not defined:变量未声明的 "非法引用"
not defined 并非 JavaScript 的官方语法或数据类型,而是开发者对 "引用未声明变量" 时出现的错误状态的描述,它表示:
- 变量从未被声明(既没有用
var、let、const声明,也不是全局对象的属性); - 试图访问一个不存在的标识符(变量、函数、对象属性等,且该标识符未被声明)。
这种情况下,JavaScript 引擎会抛出 ReferenceError: xxx is not defined 错误,导致程序终止执行(除非被错误捕获)。
3. 核心区别一句话概括
undefined:变量已 "存在"(已声明),但没有值 ;not defined:变量根本 "不存在"(未声明),引用即报错。
三、深度拆解:从 5 个维度对比二者差异
| 对比维度 | undefined | not defined(ReferenceError) |
|---|---|---|
| 本质属性 | 原始数据类型 / 全局常量 | 错误状态描述(非语法 / 类型) |
| 变量状态 | 变量已声明,未赋值 | 变量未声明(或未被全局对象挂载) |
| 报错类型 | 不报错,仅返回 undefined 状态值 |
抛出 ReferenceError 错误,终止程序执行 |
| 存在范围 | 变量、函数参数、对象属性、数组元素均可出现 | 仅出现于引用未声明的标识符时 |
| 全局对象关联 | window.undefined 存在(浏览器环境) |
未声明变量不存在于全局对象中 |
四、实战场景:哪些情况会出现 undefined?
场景 1:变量已声明但未赋值
这是 undefined 最基础的场景,使用 var、let、const 声明变量后,未赋予初始值,变量默认值为 undefined。
javascript
运行
// 1. var 声明未赋值
var a;
console.log(a); // 输出:undefined
// 2. let 声明未赋值
let b;
console.log(b); // 输出:undefined
// 3. const 声明未赋值(特殊:会直接报错,因为 const 必须初始化)
const c; // 报错:SyntaxError: Missing initializer in const declaration
注意:const 声明的变量必须立即赋值,否则会抛出语法错误,不会出现 undefined 状态。
场景 2:访问对象不存在的属性
当试图访问对象中不存在的属性时,不会报错,而是返回 undefined。
javascript
运行
const user = { name: "张三", age: 20 };
// 访问不存在的属性
console.log(user.gender); // 输出:undefined
console.log(user.address.city); // 报错:TypeError: Cannot read properties of undefined (reading 'city')
注意:嵌套属性访问时,若外层属性为 undefined,继续访问内层属性会抛出 TypeError,而非 ReferenceError。
场景 3:数组不存在的索引
访问数组超出长度的索引或不存在的索引时,返回 undefined。
javascript
运行
const arr = [1, 2, 3];
// 访问超出长度的索引
console.log(arr[5]); // 输出:undefined
// 访问稀疏数组的空缺索引
const sparseArr = [1, , 3];
console.log(sparseArr[1]); // 输出:undefined
场景 4:函数无返回值时的默认返回
函数未显式写 return 语句,或 return 后未跟任何值,函数执行后默认返回 undefined。
javascript
运行
function fn1() {
// 无 return 语句
}
function fn2() {
return; // 无返回值
}
console.log(fn1()); // 输出:undefined
console.log(fn2()); // 输出:undefined
场景 5:函数参数未被传递
函数定义了参数,但调用时未传递对应参数,未传递的参数值为 undefined。
javascript
运行
function sum(a, b) {
console.log(a, b);
return a + b;
}
// 仅传递一个参数,b 未被传递
sum(10); // 输出:10 undefined,返回:NaN
场景 6:解构赋值时未匹配到值
解构赋值中,若右侧数据没有对应的匹配项,左侧变量会被赋值为 undefined。
javascript
运行
const { name, gender } = { name: "李四" };
const [x, y] = [10];
console.log(gender); // 输出:undefined
console.log(y); // 输出:undefined
五、实战场景:哪些情况会出现 not defined?
场景 1:引用从未声明的变量
这是 not defined 最常见的场景,变量既没有用 var/let/const 声明,也不是全局对象的属性,直接引用会抛出 ReferenceError。
javascript
运行
// 变量未声明,直接引用
console.log(unDeclaredVar); // 报错:ReferenceError: unDeclaredVar is not defined
// 函数未声明,直接调用
fn(); // 报错:ReferenceError: fn is not defined
场景 2:引用超出作用域的变量
变量在局部作用域(如函数、块级作用域)中声明,在作用域外引用,相当于引用未声明的变量,触发 not defined 错误。
javascript
运行
function test() {
let innerVar = 10; // 局部变量,仅在 test 函数内有效
}
test();
console.log(innerVar); // 报错:ReferenceError: innerVar is not defined
// 块级作用域变量,外部引用
if (true) {
const blockVar = 20;
}
console.log(blockVar); // 报错:ReferenceError: blockVar is not defined
场景 3:拼写错误导致的 "伪未声明"
变量已声明,但引用时拼写错误,相当于引用了一个未声明的新变量,触发 not defined 错误。
javascript
运行
let userName = "张三";
// 拼写错误:userName 写成了 userNam
console.log(userNam); // 报错:ReferenceError: userNam is not defined
场景 4:引用未导入的模块 / 变量
在模块化开发中,未导入的模块或变量,直接引用会触发 not defined 错误。
javascript
运行
// 未导入 lodash,直接引用
console.log(_.cloneDeep({ name: "张三" })); // 报错:ReferenceError: _ is not defined
// 仅导入部分变量,引用未导入的变量
import { useState } from "react";
console.log(useEffect); // 报错:ReferenceError: useEffect is not defined
六、关键补充:容易混淆的两个特殊场景
1. var 声明的变量提升 vs not defined
var 声明的变量会发生 "变量提升",即变量声明被提升到作用域顶部,赋值操作留在原地。此时变量已声明,未赋值时为 undefined,而非 not defined。
javascript
运行
console.log(varVar); // 输出:undefined(变量提升,已声明未赋值)
var varVar = 100;
// 对比:let/const 无变量提升(暂时性死区)
console.log(letVar); // 报错:ReferenceError: Cannot access 'letVar' before initialization
let letVar = 200;
注意:let/const 声明的变量存在 "暂时性死区",在声明前引用会抛出 ReferenceError,但这不是 not defined(变量已声明,只是处于不可访问状态)。
2. 全局变量 vs window 属性
在浏览器环境中,用 var 声明的全局变量会自动挂载到 window 对象上,而未声明的变量直接赋值会成为 window 的属性,此时引用不会触发 not defined。
javascript
运行
// 1. var 声明全局变量:挂载到 window
var globalVar = "全局变量";
console.log(window.globalVar); // 输出:全局变量
// 2. 未声明变量直接赋值:成为 window 属性
unDeclaredAssign = "隐式全局变量";
console.log(window.unDeclaredAssign); // 输出:隐式全局变量
console.log(unDeclaredAssign); // 输出:隐式全局变量(不报错)
// 3. 未声明也未赋值:引用报错
console.log(noneVar); // 报错:ReferenceError: noneVar is not defined
注意:隐式全局变量(未声明直接赋值)存在安全隐患,建议始终用 var/let/const 声明变量。
七、检测与规避:如何正确处理二者?
1. 检测 undefined 的正确方式
-
方式 1:严格相等
===检测(推荐,避免类型隐式转换)javascript
运行
let a; const obj = { name: "张三" }; console.log(a === undefined); // true console.log(obj.gender === undefined); // true -
方式 2:
typeof检测(返回字符串"undefined",即使变量未声明也不会报错)javascript
运行
let b; // 已声明变量 console.log(typeof b === "undefined"); // true // 未声明变量(typeof 检测不会报错) console.log(typeof unDeclaredVar === "undefined"); // true -
方式 3:
Object.prototype.hasOwnProperty()检测对象属性(避免原型链干扰)javascript
运行
const obj = { name: "张三" }; console.log(obj.hasOwnProperty("gender")); // false(不存在该属性,间接判断为 undefined)
2. 规避 not defined 错误的方法
-
方法 1:始终用
let/const声明变量(避免隐式全局变量,减少未声明引用); -
方法 2:模块化开发中,确保按需导入所有需要的模块 / 变量;
-
方法 3:引用变量前先通过
typeof检测(避免未声明变量报错);javascript
运行
if (typeof unDeclaredVar !== "undefined") { console.log(unDeclaredVar); } else { console.log("变量未声明"); } -
方法 4:使用
try/catch捕获可能的ReferenceError;javascript
运行
try { console.log(unDeclaredVar); } catch (e) { if (e instanceof ReferenceError) { console.log("捕获到未声明变量引用错误:", e.message); } }
八、总结:核心区别与避坑指南
1. 核心区别回顾
- 本质不同:
undefined是原始数据类型,not defined是未声明变量的错误状态; - 报错情况:
undefined不报错,not defined抛出ReferenceError; - 变量状态:
undefined是 "已声明未赋值",not defined是 "未声明"; - 处理方式:
undefined可直接检测,not defined需提前规避或捕获错误。
2. 避坑核心要点
- 变量声明:优先使用
let/const,避免隐式全局变量,杜绝未声明引用; - 属性访问:嵌套对象属性访问前,先判断外层属性是否存在(避免
TypeError); - 变量检测:用
===或typeof检测undefined,用typeof提前判断未声明变量; - 作用域:明确变量作用域,避免在作用域外引用局部变量。
最后用一句话总结:undefined 是 "变量已就位,只是没带值",not defined 是 "变量压根不存在,引用必报错"。厘清二者的区别,不仅能减少开发中的 bug,还能加深对 JavaScript 变量声明、作用域的理解,这是从初学者迈向中高级开发者的必经之路。