JavaScript 中 undefined 和 not defined 的区别

JavaScript 中 undefined 和 not defined 的区别:彻底厘清易混淆的两个概念

一、开篇:JavaScript 初学者的 "噩梦"------ 分不清的 undefined 与 not defined

在 JavaScript 开发中,undefinednot defined 是两个高频出现的概念,也是初学者最容易混淆的 "坑"。二者都与 "变量不存在或未赋值" 相关,但本质上是完全不同的错误类型和状态,对应的场景、报错信息及解决方案也截然不同。

很多开发者在控制台看到 ReferenceError 或打印出 undefined 时,常常无从下手,甚至误将二者等同看待。本文将从核心定义、产生场景、报错类型、检测方式四个维度,结合实战示例深度拆解二者的区别,帮你彻底厘清这两个概念,避免在开发中踩坑。

二、基础认知:先明确两个概念的核心定义

1. undefined:变量已声明但未赋值的 "默认状态"

undefined 是 JavaScript 中的 ** 原始数据类型(Primitive Type)** 之一,同时也是一个全局常量(ES5 标准化后),它表示:

  • 变量已被声明,但未赋予任何值;
  • 属性 / 元素在对象 / 数组中不存在;
  • 函数没有返回值时的默认返回结果;
  • 函数参数未被传递时的默认值。

简单来说,undefined 是一种 "已声明但未初始化" 的合法状态,不会导致程序报错,只是表示数据的 "空缺"。

2. not defined:变量未声明的 "非法引用"

not defined 并非 JavaScript 的官方语法或数据类型,而是开发者对 "引用未声明变量" 时出现的错误状态的描述,它表示:

  • 变量从未被声明(既没有用 varletconst 声明,也不是全局对象的属性);
  • 试图访问一个不存在的标识符(变量、函数、对象属性等,且该标识符未被声明)。

这种情况下,JavaScript 引擎会抛出 ReferenceError: xxx is not defined 错误,导致程序终止执行(除非被错误捕获)。

3. 核心区别一句话概括

undefined变量已 "存在"(已声明),但没有值not defined变量根本 "不存在"(未声明),引用即报错

三、深度拆解:从 5 个维度对比二者差异

对比维度 undefined not defined(ReferenceError)
本质属性 原始数据类型 / 全局常量 错误状态描述(非语法 / 类型)
变量状态 变量已声明,未赋值 变量未声明(或未被全局对象挂载)
报错类型 不报错,仅返回 undefined 状态值 抛出 ReferenceError 错误,终止程序执行
存在范围 变量、函数参数、对象属性、数组元素均可出现 仅出现于引用未声明的标识符时
全局对象关联 window.undefined 存在(浏览器环境) 未声明变量不存在于全局对象中

四、实战场景:哪些情况会出现 undefined?

场景 1:变量已声明但未赋值

这是 undefined 最基础的场景,使用 varletconst 声明变量后,未赋予初始值,变量默认值为 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. 核心区别回顾

  1. 本质不同:undefined 是原始数据类型,not defined 是未声明变量的错误状态;
  2. 报错情况:undefined 不报错,not defined 抛出 ReferenceError
  3. 变量状态:undefined 是 "已声明未赋值",not defined 是 "未声明";
  4. 处理方式:undefined 可直接检测,not defined 需提前规避或捕获错误。

2. 避坑核心要点

  1. 变量声明:优先使用 let/const,避免隐式全局变量,杜绝未声明引用;
  2. 属性访问:嵌套对象属性访问前,先判断外层属性是否存在(避免 TypeError);
  3. 变量检测:用 ===typeof 检测 undefined,用 typeof 提前判断未声明变量;
  4. 作用域:明确变量作用域,避免在作用域外引用局部变量。

最后用一句话总结:undefined 是 "变量已就位,只是没带值",not defined 是 "变量压根不存在,引用必报错"。厘清二者的区别,不仅能减少开发中的 bug,还能加深对 JavaScript 变量声明、作用域的理解,这是从初学者迈向中高级开发者的必经之路。

相关推荐
oh,huoyuyan2 小时前
【实用技巧】火语言RPA:界面『日期时间』控件,实现网页日期自动填写
前端·javascript·rpa
默|笙2 小时前
【Linux】进程(6)虚拟地址空间
linux·运维·服务器
Lisonseekpan2 小时前
Kafka、ActiveMQ、RabbitMQ、RocketMQ对比
java·后端·kafka·rabbitmq·rocketmq·activemq
重生之我在番茄自学网安拯救世界2 小时前
网络安全中级阶段学习笔记(十一):服务器解析漏洞全解析(原理、利用与防御)
运维·服务器·web安全·网络安全·渗透测试·服务器解析漏洞
我是华为OD~HR~栗栗呀2 小时前
(华为od)21届-Python面经
java·前端·c++·python·华为od·华为·面试
夕阳下的一片树叶9132 小时前
后端java遇到的问题
java·开发语言
CodeAmaz2 小时前
RocketMQ整体工作流程_详解
java·rocketmq·rocketmq整体流程
刘一说2 小时前
ES6+核心特性全面浅析
java·前端·es6
大学生资源网2 小时前
基于springboot的农村综合风貌展示平台设计与实现(源码+文档)
java·数据库·spring boot·后端·毕业设计·源码·springboot