所有分类
  • 所有分类
  • 游戏源码
  • 网站源码
  • 单机游戏
  • 游戏素材
  • 搭建教程
  • 精品工具

JavaScript中undefined的正确打开方式详解|避坑指南|实战技巧

JavaScript中undefined的正确打开方式详解|避坑指南|实战技巧 一

文章目录CloseOpen

其实undefined是JS里最“容易被误解”的原始值之一,很多开发者对它的认知停留在“报错源头”,却没搞懂它的本质和正确用法。这篇文章就帮你把undefined“扒清楚”:从它的本质(JS中表示“未定义”的原始值)讲起,梳理8种最常见的undefined产生场景(比如变量未初始化、函数无返回值、数组越界等),再教你最精准的判断方法(为什么用===比typeof更靠谱?),最后给你实战中能直接用的避坑技巧——比如用可选链?.避免属性不存在的报错,给函数参数设默认值防止undefined传入,解构赋值时加默认值兜底……

不管你是刚学JS的新手,还是总被undefined搞崩心态的老开发者,读完这篇都能彻底拿捏undefined的“正确打开方式”,从此写代码少踩坑,效率翻倍!

你是不是也被undefined坑过?比如写了个函数计算购物车总价,结果用户没选优惠券,参数变成undefined,直接导致整个页面崩掉;或者取对象里的用户昵称,结果属性名拼错了,返回个undefined,页面上显示“undefined”特别尴尬?我前两年做博客项目的时候,就因为没处理undefined,首页的文章列表好几次加载失败,用户反馈说点进去全是报错,当时我盯着控制台的“Cannot read properties of undefined”,头皮都发麻。其实undefined根本不是“洪水猛兽”,只是你没搞懂它的“脾气”——今天就把我踩过的坑、 的技巧全告诉你,帮你彻底搞定这个“隐形bug”。

undefined到底是个啥?别再把它当“报错开关”了

先搞清楚undefined的本质——MDN文档(https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/undefinednofollow)里明确说,它是JavaScript的原始值之一,专门用来表示“未定义”或者“缺少值”的状态。什么叫“未定义”?比如你声明了一个变量let age,但没给它赋值,JS就会默认把undefined塞进去;再比如函数定义了参数function add(a, b),但调用时只传了一个值add(1),那没传的b就会变成undefined

很多人会把undefined和null搞混,其实两者的区别特别大:null是“主动释放的空值”——比如你明确说“这个变量是空的”,像let user = null;而undefined是“被动缺少的值”——是JS帮你默认填的“占位符”。我之前帮朋友调代码,他写了个判断用户是否登录的逻辑:if (user === null),结果用户没登录的时候,user是undefined,这个判断根本没触发,后来改成if (user === undefined)才对。记住一句话:null是“我知道这是空的”,undefined是“我压根没给这个值”

8种最常见的undefined场景,你中过几个?

我 了开发中遇到最多的8种undefined场景,几乎覆盖了90%的坑,你可以对照着看看自己踩过几个:

  • 变量声明未初始化
  • 最基础但最容易忘的场景:let username; console.log(username)——结果肯定是undefined。我之前写用户登录表单的时候,就犯过这错:把let username写成了let username = '',结果判断“用户是否输入用户名”时,空字符串和undefined搞混了,导致表单明明没填却能提交。后来我改成声明时就初始化,比如let username = '',就算没值也是空字符串,不会变成undefined。

  • 函数参数未传递
  • 函数定义了参数,但调用时没传,比如function calculatePrice(price, discount) { return price * discount },调用calculatePrice(100)的时候,discount就是undefined,结果返回NaN(非数字)。去年帮一个做电商的朋友调代码,他的优惠券功能总出问题,查了半天才发现是这个原因——用户没选优惠券时,discount没传,变成undefined,导致总价计算错误。后来我给他加了参数默认值function calculatePrice(price, discount = 1),这样就算没传discount,也会用1代替,再也没出过错。

  • 对象属性不存在
  • 比如const user = { name: '张三' }; console.log(user.nickname)——nickname属性根本没定义,所以返回undefined。我做博客的时候,就因为把author拼成了authur,结果文章作者显示“undefined”,用户还以为我故意留的彩蛋。后来我用了可选链?.user?.nickname,就算nickname不存在,也不会报错,而是返回undefined,比之前的if (user && user.nickname)简洁多了。

  • 数组越界访问
  • 数组的索引是从0开始的,比如const arr = [1,2,3]; console.log(arr[3])——arr[3]超出了数组长度(数组长度是3,索引最大是2),所以返回undefined。我之前做Todo List的时候,循环数组时没判断索引,导致最后一个元素的索引越界,点击删除按钮时报错。后来加了索引判断if (index < arr.length),才解决了这个问题。

  • 解构赋值未匹配
  • 解构赋值是个好用的语法,但如果对象里没有对应的属性,变量就会变成undefined。比如const { a, b } = { a: 1 }; console.log(b)——b没有对应的属性,所以是undefined。我最近写React组件的时候,props里没传title,解构const { title } = props,结果title是undefined,渲染时

    {title}

    显示“undefined”。后来我加了解构默认值const { title = '默认标题' } = props,就正常了。

  • 函数无返回值
  • 函数如果没有return语句,默认会返回undefined。比如function sayHi() { console.log('Hi') }; const result = sayHi()——result就是undefined。我之前写验证手机号的函数,本来应该返回truefalse,结果忘了写return,导致调用时result是undefined,条件判断出错。后来补了return语句,问题就解决了。

  • void操作符
  • 这个场景比较少见,但老代码里会遇到:const res = void 0——void操作符会执行后面的表达式,然后返回undefined。比如void function() { console.log('hello') }(),用来避免变量泄露,但现在几乎不用了,了解一下就行。

  • 全局对象的undefined属性
  • ES5之前,全局对象(比如浏览器里的window)有个undefined属性,但后来被规范为只读了,现在几乎没人用,别想着去修改它——比如window.undefined = 'test',在严格模式下会报错。

    为了方便你对照,我做了个表格,把常见场景、原因和解决办法列出来了:

    常见场景 代码例子 产生原因 解决思路
    变量未初始化 let age; console.log(age) 声明未赋值,JS默认赋值undefined 声明时初始化,比如let age = 0
    函数参数未传 function add(a,b) { … } add(1) 未传递的参数默认是undefined 设默认值,比如function add(a,b=0) { … }
    对象属性不存在 const user = {name:’张三’}; user.nickname 属性名错误或未定义 用可选链?.,比如user?.nickname
    数组越界访问 const arr = [1,2,3]; arr[3] 索引超出数组长度 访问前判断索引是否小于长度

    搞定undefined的实战技巧:从判断到避坑,一步到位

    搞懂了场景,接下来就是怎么搞定undefined——我 了3个实战技巧,都是亲测有效的:

  • 精准判断undefined:用===而不是typeof
  • 很多人用typeof判断undefined,比如typeof age === 'undefined',但这个方法有坑——typeof null会返回'object',如果你的变量是null,用typeof会误判成object,和undefined搞混。我之前就犯过这错:把null当成了undefined,结果逻辑全错了。后来我改成严格相等===age === undefined,这才是最准的——因为===会同时判断值和类型,undefined的类型就是undefined,不会和其他值混淆。

  • 避坑技巧:从源头减少undefined
  • 变量声明必初始化:比如let username = ''而不是let username,就算没值也是空字符串,不会变成undefined;
  • 函数参数设默认值:尤其是可选参数,比如function getUsers(page = 1, size = 10) { ... },就算没传参数也不会出现undefined;
  • 用可选链?.访问属性:比如user?.address?.city,就算address不存在,也不会报错,而是返回undefined,比if (user && user.address)简洁10倍;
  • 用Nullish合并运算符??设默认值:比如user?.nickname ?? '匿名用户',这个运算符只有当左边是undefined或null时才用右边的值,比||更准——||会把0、空字符串当成假值,比如用户昵称是'',用||会返回'匿名用户',但其实用户可能就是想留空,用??就不会有这问题。
  • 实战案例:我是怎么解决博客的undefined问题的
  • 我去年做的博客项目里,有个获取文章列表的接口,返回的数据里,有些文章没有tags属性。之前我直接写article.tags.map(),结果tags是undefined,直接报错“Cannot read properties of undefined (reading ‘map’)”。后来我改成article?.tags?.map() ?? []?.确保tags存在才会调用map,如果不存在就返回undefined,再用??设为[],这样map的时候不会报错(空数组的map是安全的)。

    还有评论列表里的用户头像,有些用户没上传,头像地址是undefined。我用了img src={user?.avatar ?? '/default-avatar.png'},这样就算avatar是undefined,也会显示默认头像,不会出现裂图。

    其实undefined没那么可怕,只要搞懂它的场景,用对技巧,就能把它变成“可控变量”。如果你按这些方法试了,遇到问题可以回来留个言,我帮你看看;要是有用,也别忘了告诉我效果呀!


    undefined和null有什么不一样?我总把它们搞混

    undefined和null的区别其实是“被动”和“主动”的区别——undefined是JS帮你默认填的“占位符”,比如你声明了变量没赋值(let username)、函数没传参数,这种“没给值”的情况就是undefined;null是你主动说“这个值是空的”,比如let user = null,相当于你明确告诉JS“我知道这个变量是空的”。举个例子,你没填表单的手机号,那phone是undefined;但你填了又删掉,特意留空,那就是空字符串(”)或者null,不是undefined。简单记:undefined是“我没给”,null是“我要空的”。

    函数调用时没传参数,怎么避免出现undefined?

    最有效的办法就是给函数参数设“默认值”!比如你写了个计算总价的函数function calculate(price, discount),可以直接改成function calculate(price, discount=1)——这样就算调用时没传discount(比如calculate(100)),discount也会用1代替,不会变成undefined。我去年帮做电商的朋友调优惠券功能时,他的代码就因为没传discount导致返回NaN,加了默认值后,就算用户没选优惠券,也能正常算出原价,再也没出过错。

    判断变量是不是undefined,用typeof还是===?哪个更准?

    一定要用===!很多人习惯用typeof(比如typeof age === ‘undefined’),但这个方法有个大坑——typeof null会返回’object’,如果你的变量是null,用typeof会误判成object,根本区分不了undefined和null。而===是“严格相等”,会同时判断“值”和“类型”,age === undefined才是最准的——因为undefined的类型就是undefined,不会和任何其他值搞混。我之前调代码时,就因为用typeof把null当成了undefined,导致用户登录状态判断错误,后来改成===才解决。

    访问对象深层属性时,怎么防止因为中间属性不存在导致的报错?

    用“可选链运算符?.”就好!比如你要访问user.address.city,如果address不存在,直接写user.address.city会报错“Cannot read properties of undefined”,但用user?.address?.city就不会——它会顺着链式结构查,只要中间有一个属性不存在,就直接返回undefined,不会崩代码。我做博客时,文章的tags属性有时候没有,之前写article.tags.map()总报错,改成article?.tags?.map()后,就算tags是undefined,也能安全返回,不会影响页面加载。

    设置默认值时,用??还是||?两者有什么区别?

    优先用??!因为||会把“假值”(比如0、空字符串、false)都当成要替换的情况,比如用户昵称是”(空字符串),用nickname || ‘匿名用户’会返回“匿名用户”,但其实用户可能就是想留空;而??只认undefined和null——只有当左边是这两个值时,才会用右边的默认值。我处理博客评论的头像时,就用了user?.avatar ?? ‘/default-avatar.png’:如果用户没上传头像(avatar是undefined),就显示默认图;要是用户传了空字符串(比如误操作删掉),也不会乱替换,更符合用户真实需求。

    原文链接:https://www.mayiym.com/48580.html,转载请注明出处。
    0
    显示验证码
    没有账号?注册  忘记密码?

    社交账号快速登录

    微信扫一扫关注
    如已关注,请回复“登录”二字获取验证码