从 javascript 函数返回 `undefined` 或 `null` 更好吗?
Posted
技术标签:
【中文标题】从 javascript 函数返回 `undefined` 或 `null` 更好吗?【英文标题】:Is it better to return `undefined` or `null` from a javascript function? 【发布时间】:2016-10-25 03:14:19 【问题描述】:我写了一个函数,基本上是这样的:
function getNextCard(searchTerms)
// Setup Some Variables
// Do a bunch of logic to pick the next card based on termed passed through what I'll call here as 'searchTerms' all of this logic is omitted because it's not important for my question.
// ...
// If we find a next card to give, than give it
if (nextCardFound)
return nextCardFound;
// Otherwise - I'm returning undefined
return undefined;
问题:这里返回“null”会更好吗?
我可以将任何我想要的东西传回去 - 显然......我只是不确定什么是最好的使用。
调用此函数的代码知道如何处理 undefined(除非出现可怕的错误,否则它实际上永远不会真正发生)
我问这个问题的原因是我在某个地方听到了一些听起来像“不要将未定义的变量分配给变量”之类的东西 - 这会使调试变得更加困难。因此,我可以看到 null
被传回的事实告诉我返回正在工作 - 但基本上功能类似于 undefined
。
文档:
Mozilla Docs 没有回答我的问题...谷歌也没有:\
This SO Question - 对于我在这里想要弄清楚的内容来说太宽泛了。
【问题讨论】:
这不是SO Question 的答案吗? 在我看来,返回null
。将 undefined
留给 javascript 本身。但是,没有“更好”,所以这是一个见仁见智的问题。
@warkentien2 谢谢,这很有帮助 - 但我仍然不清楚从 getter 函数返回的约定是什么。
我将null
读作“你所要求的东西没有合适的价值”,undefined
读作“我无法计算出你所要求的东西”。跨度>
@warkentien2 那个问题和我在回答中链接的那个问题是相关的,但两者似乎都在问 what 是它们之间的区别而不是 when 使用一个或另一个作为返回值。
【参考方案1】:
未定义通常是指尚未(尚未)分配值的事物。 Null 指的是绝对没有价值的东西。在这种情况下,我建议返回 null。请注意,没有指定返回值的函数会隐式返回 undefined。
来自 ECMAScript2015 规范
4.3.10 未定义值
变量未赋值时使用的原始值
4.3.12 空值
表示 故意缺少任何对象值
http://www.ecma-international.org/ecma-262/6.0/#sec-terms-and-definitions-undefined-type
进一步阅读:
When is null or undefined used in JavaScript?
【讨论】:
是的,undefined 是未为变量赋值时使用的值。为什么这意味着您不应该在函数中返回 undefined? @Oriol,在我看来,由于 void 函数返回未定义,这是该类型函数的保留值,因此在处理函数的返回值时,null 告诉我它决定return null,而 undefined 告诉我它要么决定返回 undefined,要么决定不返回任何东西,但我不确定是哪个。此外,如果我在做var x=someFunc();
,我故意为 x 赋值,并且宁愿它不通过任何表明它没有(或可能没有)被赋值的测试。恕我直言
这应该是公认的答案。这就是它打算在规范中使用的方式
我不这么看。我将其解读为:如果您定义了一个变量但不对其进行初始化,那么它将具有未定义的初始值。程序员应该使用 Null 来有意地指示变量为空。恕我直言,程序员永远不应将 undefined 分配给变量,将其留给 js 引擎使用它。术语“对象”值具有误导性,因为在 JS 中,由于自动装箱,甚至原语在很大程度上都表现得像对象
是的,这是有道理的。公平地说,我不介意使用一个而不是另一个(虽然我更习惯null
),只要你坚持使用一个,但有2个值表示没有价值(无论“类型”)总是令人困惑【参考方案2】:
我会告诉你我个人在两者之间的选择方式。
我的简单问题是:是否可以将给定另一个输入/状态/上下文的值定义为某个东西?
如果答案是肯定的,则使用null
,否则使用undefined
。更一般地,当预期对象不存在时,任何返回对象的函数都应返回null
。因为它可能存在给定另一个输入/状态/上下文。
null
表示给定输入/状态/上下文的价值缺失。它隐含地意味着值本身的 concept 存在于您的应用程序的上下文中,但可能不存在。
在您的示例中,存在下一张卡片的概念,但卡片本身可能不存在。应该使用null
。
undefined
隐含地表示该值在您的应用程序上下文中没有意义。例如,如果我使用一组给定的属性操作user
对象,并尝试访问属性pikatchu
。此属性的值应设置为undefined
,因为在我的上下文中,拥有这样的属性没有任何意义。
【讨论】:
这对我来说听起来很真实。当像函数式程序员一样思考时,IMO 纯函数应该返回null
,而具有副作用的函数应该返回 undefined
。【参考方案3】:
我认为没有最好的方法,甚至标准函数有时也会选择其中一种。
例如:
[[原型]]
普通对象有一个 [[Prototype]] 内部槽,它决定了它们从哪个其他对象继承。当然,必须有一种方法可以说一个对象不继承自任何其他对象。在这种情况下,“没有这样的对象”使用null
表示。
Object.getOwnPropertyDescriptor
期望返回一个属性描述符,即描述属性(例如值、可写性、可枚举性和可配置性)的对象。但是,该属性可能不存在。在这种情况下,“没有这样的属性”使用undefined
表示。
document.getElementById
应该返回具有给定 ID 的元素。但是,可能没有具有该 ID 的元素。在这种情况下,“没有这样的元素”使用null
表示。
因此,只需选择您喜欢或认为对您的具体情况更有意义的任何内容。
【讨论】:
在reading this 之后,我决定向这个答案的未来观众推荐void 0
技术。我还添加了一些代码来尝试使您的观点更清楚。谢谢你的回答!【参考方案4】:
取决于你需要对返回值做什么。
typeof null 返回一个对象。该对象的值为 undefined
typeof undefined 返回 undefined
【讨论】:
我个人通常使用null。 “那个对象的值是 undefined” 不,它不是,它不是一个对象,它是 Null。typeof
不一定返回值的真实数据类型,它有一个映射,将数据类型映射到标签并返回对应的标签。
不要相信typeof
,尽管它的名字并不能说明值的类型。【参考方案5】:
undefined
不是你应该分配的东西。您可能要考虑返回 undefined
以外的其他内容。在您的情况下,即使您根本不返回任何内容,结果也将是undefined
。所以,我建议改用null
。
考虑这个示例,
function getSomething()
// .. do something
return undefined;
function doSomething()
// .. I'm not gonna return anything.
var a = getSomething();
var b = doSomething();
上面的示例结果为a === b
,即undefined
。不同之处在于您节省了 1 条语句执行。
【讨论】:
@Oriol 我的意思是,undefined
不必分配。所有声明的没有值的变量已经是undefined
。
@JeremyIglehart 该代码实际上没有返回任何内容。否则,它会在我的 chrome 和 firefox 控制台上提供undefined
。
好吧,我不明白你的意思。是的,如果你没有显式返回任何东西, undefined 将被隐式返回。但这有什么关系呢?
@Oriol,我认为@choz 想说的是(正如其他一些人在这个问题上也提到的),如果我想返回undefined
,如果其他东西没有更早返回 - 我不需要,因为如果您不返回任何内容,该函数的默认行为是返回 undefined - 他们只是说这不是必需的。此外......我喜欢你所说的关于返回 null 的内置 getter 函数。请张贴您的答案,我会接受。
我仍然更喜欢明确地返回undefined
,因为它记录了代码的意图。否则,当我看到一个不返回任何内容的函数时,我不得不问自己编写它的开发人员是否忘记了返回一些内容。【参考方案6】:
这是一个例子,其中undefined
比null
更有意义:
我使用JSON.parse
的包装函数将其异常转换为undefined
:
// parses s as JSON if possible and returns undefined otherwise
// return undefined iff s is not a string or not parseable as JSON; undefined is not a valid JSON value https://***.com/a/14946821/524504
function JSON_parse_or_undefined(s)
if ("string" !== typeof s) return undefined
try
const p = JSON.parse(s)
return p
catch (x)
return undefined
请注意,null
在 JSON 中有效,而 undefined
则无效。
【讨论】:
我明白你在那儿做了什么——我不能说你错了——因为从某种意义上说,我认为你可以在这里做到这一点,这很好。我有一个不同的模式用来做这个我更喜欢的操作,因为我之后做了一个“验证”步骤。我觉得这是将验证与返回值混合在一起。这就是我所做的:let getStringOrJSON = value => try value = JSON.parse(value); catch(e) return value; return value; ;
。现在,我确信这两个回报可能会被不同地处理,并且可能不会赢得 JS 高尔夫比赛。它有效。【参考方案7】:
我认为在这种情况下,应该返回null
。
如果您从理论计算机科学的角度考虑问题,则 undefined 用于表示非终止/不可计算性 (即partial functionf
的未定义点x
的占位符,通常写成f(x) = ⊥
)。
getNextCard
然而似乎能够计算下一张卡片(如果它存在的话),并且如果没有下一张卡片也能够计算。换句话说,函数是total,因为它对每个输入都终止。
话虽如此,需要一个 特殊值 表示终止而没有有意义的结果(即“我无法为该输入返回任何卡”),这对我来说是 null
而不是 undefined
.
注意事项:
您可以在其他一些类型化语言中看到对该参数的一些支持,其中使用option type(有时也称为可空类型)表示没有有意义结果的终止。 Haskell 中的 Maybe 就是一个例子。
另一方面,我们当然不知道 JavaScript 中的 undefined
真正应该是什么意思。因此,与 undefined 的类比有点勉强。此外,由于我们总是希望使用全部函数,这相当于说“永远不要从函数返回undefined
”。这似乎有点严格,因为它会将undefined
的使用限制为尚未设置的属性/变量。
最后,我个人的偏好是永远不要返回 undefined
,我可以返回 null
,我还认为这是更好的编码约定(因为除其他外,x !== null
比 typeof x !== 'undefined'
短)。
【讨论】:
【参考方案8】:第一个答案是正确的。它们在理论上具有不同的含义。但是,并不总是很清楚该选择哪个。
我倾向于在我的开发中使用 null,尽管我认为这完全是主观的事情。
我使用它主要是因为:
未定义的变量可能会在旧浏览器中被覆盖,因此返回它有点复杂。同样的问题迫使您在获取函数结果时使用typeof var === 'undefined'
。 link
其他语言倾向于广泛使用 null,其中很多甚至没有 undefined(例如 php)。在语言之间快速切换时,这给了我一种一致性。
【讨论】:
【参考方案9】:我认为使用什么是非常值得商榷的。我更喜欢语义上尽可能准确的代码,所以我认为undefined
在这种情况下是合适的。
我认为null
assignments 的意思是“一个变量设置为空”。这与 undefined
相反,意思是“这东西根本不存在”
正如之前的回答所指出的,返回 undefined
有问题,这完全取决于您是否会打扰您。它不会打扰我。
【讨论】:
但是document.getElementById('iDoNotExist')
返回null
,尽管意思更接近于“这东西根本不存在”。如果标准方法可以做到,为什么不是 OP?
@Oriol 实际上我最喜欢你的推理。请发布此效果的答案,我会接受。 (如果需要,我什至可能会添加一些编辑)
是的@Oriol,这就是我真正喜欢辩论的原因,即使在问答网站上也是如此。获得反例真的很好。而且你提供了一个很好的。
另一方面,如果数组不包含搜索值,array.find()
将返回 undefined
。这不一致,我同意。以上是关于从 javascript 函数返回 `undefined` 或 `null` 更好吗?的主要内容,如果未能解决你的问题,请参考以下文章
从使用 wkwebview 返回值的 javascript 调用 swift 函数