在 JavaScript 中使用 null 而不使用未定义的原因是什么?

我已经编写 JavaScript 很长时间了,从来没有理由使用 null。似乎 undefined总是更可取,并以编程方式服务于相同的目的。使用 null而不是 undefined有什么实际的原因吗?

60797 次浏览

UnDefinition 指的是不存在事物概念的地方; 它没有类型,而且以前从未在该作用域中引用过; null 指的是已知事物存在的地方,但它没有值。

我真的不知道答案,但根据 Nicholas C. Zakas,他的书 ”< em > 为 Web 开发人员提供的专业 JavaScript 的第30页:

当定义一个变量时 后来拿着一个物体,它是 建议初始化变量 到 null而不是其他任何东西。 这样,您可以显式检查值 null以确定 该变量已在稍后用对象引用填充

您可能会采用这里建议的惯例,但实际上没有充分的理由这样做。它的使用不够一致,不够有意义。

为了使约定有用,您首先必须知道被调用的函数遵循约定。然后,您必须显式地测试返回的值并决定要做什么。如果您得到 未定义,您可以假设某种类型的错误发生了 被调用函数所知道的。但是,如果发生了错误,而且函数知道这个错误,并且将它发送到更广泛的环境中是有用的,那么为什么不使用错误对象呢?即抛出一个错误?

所以说到底,除了简单环境中的非常小的程序之外,约定在其他任何情况下实际上都是无用的。

DOM 节点和元素并非未定义,但可能为空。

  • 元素最后一个子元素的 nextSibling 为空。

  • 第一个子女的前一个兄弟姐妹为空。

  • 如果文档中不存在元素,则 document.getElementById 引用为 null。

但是在所有这些情况下,值都不是 未定义; 只是没有节点。

nullundefined本质上是两个意思相同的不同值。唯一的区别是在 会议中如何在 你的系统中使用它们。正如一些人所提到的,有些人使用 null表示“没有对象”,在这种情况下,您有时可能会得到一个对象,而未定义意味着没有预期的对象(或者存在错误)。我的问题是,这完全是武断的,完全没有必要。

也就是说,有一个主要的差异-没有初始化的变量(包括没有传递参数的函数参数)是未定义的 一直都是

这就是为什么在我的代码中 永远不会使用 null,除非我不控制的东西返回 null (例如正则表达式匹配)。它的美妙之处在于,它大大简化了事情。我从来不需要检查 x === undefined || x === null,我可以只检查 x === undefined。如果你有使用 ==或者像 if(x) ... 这样简单的东西的习惯,停止它。

对于一个空字符串,0nullNaN-也就是你可能不想要的东西,!x的值将为 true。如果你想编写不那么糟糕的 javascript,那么一定要使用三重等于 ===,而不要使用 null(改用 undefined)。这会让你的生活轻松很多。

每个人都有自己的编码方式和自己的内部语义,但多年来,我发现这是我给问这个问题的人最直观的建议: 如果有疑问,就像 JavaScript 那样做

假设您正在处理诸如 jQuery 插件的选项之类的对象属性... ... 问问自己 JavaScript 给一个尚未定义的属性赋予了什么值——答案是 undefined。因此,在这个上下文中,我将使用“未定义”来初始化这些类型的内容,以便与 JavaScript 保持一致(对于变量,可以使用 var myVar;而不是 var myVar = undefined;)。

现在让我们假设您正在进行 DOM 操作... JavaScript 为不存在的元素赋予了什么值?答案是 null。如果要创建一个占位符变量,该变量稍后将保存对与 DOM 相关的元素、文档片段或类似内容的引用,那么我将使用这个值进行初始化。

如果使用的是 JSON,那么需要进行特殊处理: 对于未定义的属性值,应该将其设置为 ""null,因为 undefined的值不被认为是正确的 JSON 格式。

这么说吧,正如之前的海报所表达的,如果你发现你用 null或者 undefined初始化的东西不止一次,那么也许你应该重新考虑一下如何去编写你的应用程序。

我完全不同意使用 null 或未定义是不必要的。 未定义的东西是保持活的整个原型链接过程。 所以只有 null 的编译器不能检查这个属性是否等于 null,或者它在端点原型中没有定义。在其他动态类型语言(比如 Python)中,如果你想访问未定义的属性,它会抛出异常,但是对于基于原型的语言,编译器也应该检查父原型,这里是未定义最需要的地方。

使用 null 的全部意义就是将变量或属性与对象绑定在一起,对象是单一的,具有空的意义,使用 null 也具有性能的目的。这两个代码有不同的执行时间。

var p1 = function(){this.value = 1};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
p = new p1();
if(index > 50000000){
p.x = "some_string";
}


return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)


var p2 = function(){this.value = 1, p.x = null};
var big_array = new Array(100000000).fill(1).map((x, index)=>{
p = new p2();
if(index > 50000000){
p.x = "some_string";
}


return p;
});
big_array.reduce((sum, p)=> sum + p.value, 0)

我现在正在研究这个问题,并且考虑以下哲学:

  1. 任何用于返回结果的函数如果找不到结果应该返回 null
  2. 任何不打算隐式返回结果的函数都返回未定义的结果。

对我来说,这个问题非常重要,因为任何调用返回结果的函数的人都不应该对是否测试未定义还是 null 有任何疑问。

这个答案并不试图解决:

  1. 空与未定义的属性值
  2. 函数中的变量为空或未定义

在我看来,变量是你自己的事情,而不是你的 API 的一部分,任何面向对象系统中的属性都是定义的,因此它们的定义值应该不同于如果没有定义的话(对于已定义的,未定义的是当你访问不在你的对象中的东西时得到的值)。

无效中一个有用的属性,未定义没有限定:

> null + 3
3
> undefined + 3
NaN

当我想“关闭”一个数值时,我使用 null, 我最后一次使用是操作 css 转换:

const transforms = { perspective : null, rotateX : null };
// if already set, increase, if not, set to x
runTimeFunction((x) => { trasforms.perspective += x; });
// still useful, as setting perspective to 0 is different than turning it off
runTimeFunction2((x) => { transforms.perspective = null; });


// toCss will check for 'null' values and not set then at all
runTimeFunction3(() => { el.style.transform = toCss(transforms); });

不确定如果我 应该使用这个属性认为..。

原因是: var undefined = 1是合法的 javascript,但 var null = 1是一个语法错误。区别在于,null是一个语言关键字,而 undefined由于某种原因而不是。

如果您的代码依赖于与 undefined的比较,就好像它是一个关键字(if (foo == undefined)——一个很容易犯的错误) ,只有在没有人定义具有这个名称的变量时才有效。所有这些代码都很容易受到某人意外或恶意地用该名称定义全局变量的攻击。当然,我们都知道在 javascript 中意外地定义一个全局变量是完全不可能的..。

在一天结束的时候,因为 nullundefined都强制使用相同的值(Boolean(undefined) === false && Boolean(null) === false) ,所以从技术上讲,您可以使用其中任何一个来完成工作。然而,有正确的方式,我的意思是。

  1. undefined的使用留给 JavaScript 编译器。

    undefined用于描述不指向引用的变量。这是 JS 编译器会照顾你的东西。在编译时,JS 引擎将所有悬挂变量的值设置为 undefined。当引擎逐步完成代码并且值变得可用时,引擎将为各个变量分配相应的值。对于那些没有找到值的变量,这些变量将继续维护对基元 undefined的引用。

  2. 如果您显式希望将变量的值表示为“无值”,则仅使用 null。

    如@com2gz 所述: null用于定义程序上为空的内容。undefined的意思是说引用不存在。null值定义了对“无”的引用。如果调用对象的不存在属性,那么将得到 undefined。如果我故意使该属性为空,那么它必须是 null,这样你就知道它是故意的。

不要使用 undefined原语。当您声明没有赋值的变量时,或者当您试图访问没有引用的对象的属性时,JS 编译器将自动为您设置这个值。另一方面,当且仅当您有意使变量具有“无值”时,才使用 null


边栏 : 我个人避免显式地将任何东西设置为 undefined(我在与之交互的许多代码库/第三方库中都没有遇到过这种模式)。此外,我很少使用 null。我使用 null的唯一次数是当我想将一个参数的值表示为具有 没有价值的函数时,例如:

function printArguments(a,b) {
console.log(a,b);
}


printArguments(null, " hello") // logs: null hello

有些人说,把对象初始化到 null是可以的。我只是想指出,解构参数默认值不适用于 null。例如:

const test = ({ name } = {}) => {
console.log(name)
}


test() // logs undefined
test(null) // throws error

这需要执行 null检查 副院长来调用可能经常发生的函数。

只需要添加一些特定的 javascript 库,null 和 unDefinition 可以有意外后果。

例如,loash 的 get函数,它接受一个默认值作为第三个参数:

const user = {
address: {
block: null,
unit: undefined,
}
}
console.log(_.get(user, 'address.block', 'Default Value')) // prints null
console.log(_.get(user, 'address.unit', 'Default Value')) // prints 'Default Value'
console.log(_.get(user, 'address.postalCode', 'Default Value')) // prints 'Default Value'

另一个例子: 如果您在 React 中使用 defaultProps,如果一个属性被传递 null,则不使用默认道具,因为 Null 被解释为已定义的值。 例如:。

class MyComponent extends React.Component {
static defaultProps = {
callback: () => {console.log('COMPONENT MOUNTED')},
}
componentDidMount() {
this.props.callback();
}
}
//in some other component
<MyComponent />   // Console WILL print "COMPONENT MOUNTED"
<MyComponent callback={null}/>   // Console will NOT print "COMPONENT MOUNTED"
<MyComponent callback={undefined}/>   // Console WILL print "COMPONENT MOUNTED"

未知变量: undefined

已知变量但没有值: null

  1. 您从服务器接收到一个对象 server_object
  2. 你引用 server_object.errj。它告诉你它是 undefined。这意味着它不知道它是什么。
  3. 现在你引用 server_object.err。它告诉你它是 null。这意味着您正在引用一个正确的变量,但它是空的; 因此没有错误。

问题在于,当你声明一个没有值的变量名时(var hello) js 声明 undefined: 这个变量不存在; 而程序员通常的意思是: “我还没有给它一个值”,null的定义。

因此,程序员的默认行为ーー将没有值的变量声明为无值ーー与将其声明为不存在的 js 不一致。此外,!undefined!null都是 true,因此大多数程序员将它们视为等价的。

当然,您可以确保始终执行 var hello = null,但是当他们和 !操作符将 undefinednull视为等价时,大多数人不会像这样丢弃他们的代码,以确保在故意的松散类型语言中的类型健全。

在 JavaScript 中,值 null表示故意没有任何对象值。null表示缺乏标识,表示变量指向没有对象。

全局 undefined属性表示基元值 undefinedundefined是自动分配给变量的基元值。 undefined的意思是说引用不存在。

这里已经有一些不错的答案,但不是我要找的那个。nullundefined在“技术上”都做同样的事情,都是假的,但是当我通读代码时,我看到一个“ null”,那么我希望它是一个用户定义的 null,有些东西被明确设置为不包含任何值,如果我通读代码,看到“未定义”,那么我假设它的代码从来没有被初始化或任何东西分配。通过这种方式,代码可以告诉您某些事情是由未初始化的内容还是空值引起的。因此,您真的不应该手动分配“未定义”的东西,否则它会干扰您(或其他开发人员)阅读代码的方式。如果另一个开发人员看到“未定义”,他们不会凭直觉认为是你让它未定义,他们会认为它没有被初始化,而实际上它是。对我来说,这是最大的问题,当我阅读代码时,我想看看它告诉我什么,我不想猜测和弄清楚东西是否“实际上”已经初始化。

更不用说在打印文本中使用它们意味着两种不同的东西。使用:

interface Example {
name?: string
}

意味着名称可以是未定义的或字符串,但不能为空。如果你想要它为 null,你必须明确地使用:

interface Example {
name: string | null
}

即使这样,您也必须使用“ null”来初始化它。

当然,只有在 tsconfig.json中使用 "strictNullChecks": true时才会出现这种情况。

基于我们最近遇到的一个故障,下面的例子说明了为什么我更喜欢使用 undefined而不是 null,除非有特定的原因:

function myfunc (myArg) {
if (typeof myArg === 'string') {
console.log('a', myArg);
} else if (typeof abc === 'object') {
console.log('b', myArg);
if (myArg.id) {
console.log('myArg has an id');
} else {
console.log('myArg has an id');
}
} else {
console.log('no value');
}
}

下面的值可以很好地发挥作用:

'abc'
{}
undefined
{ id: 'xyz' }

另一方面,假设 nullundefined在这里是等价的,这就破坏了代码。原因是 nullobject的类型,而 undefinedundefined的类型。因此,这里的代码中断是因为您无法在 null上测试成员。

我见过大量类似外观代码的案例,其中 null只是在问问题:

if (typeof myvar === 'string') {
console.log(myvar);
} else if (typeof myvar === 'object') {
console.log(myvar.id);
}

这里的修复方法是显式地测试 null:

if (typeof myvar === 'string') {
console.log(myvar);
} else if (myvar !== null && typeof myvar === 'object') {
console.log(myvar.id);
}

我的态度是针对一种语言的弱点和该语言程序员的典型行为编写代码,因此这里采用“未定义”服从默认的哲学。

为了编写简单的代码,你需要降低复杂性和变化性。当对象上的变量或属性没有值时,它是未定义的,为了使值为空,你需要给它赋一个空值。

未声明诉无效

null既是 反对的“类型”,也是7种独特的 基元值类型之一,称为 null

undefined既是名为 未定义的全局范围属性和类型,也是名为 undefined的7个唯一 基元值类型之一(window.unDefinition)。

我们感兴趣的是使用 基本类型作为值。

null的例子中,作为一个值类型,它意味着一个空值已经被分配给一个变量,但是变量类型(Number、 String 等)仍然被定义。没有价值。这就是 null的意思。这意味着一个变量有一个空值,但它仍然是一个值。它也是 重新初始化变量,具有某种类型的值,但不是 undefined类型。

undefined是一个特例。当你声明一个变量(或者使用一个未声明的缺失值)时,它是 类型 undefined,因为浏览器还不知道分配给它的数据类型。如果声明了变量但是没有赋值,则默认情况下在赋值之前会赋值基元值 undefined,并且暗示变量不存在或者不存在但是没有赋值。

null一样,undefined也是 基元值类型基元值类型。但是与 null不同,它表示变量不存在,其中 null 表示值不存在。这就是为什么在检查变量是 null还是空值之前,最好先检查变量是否存在并且已经使用未定义的方式分配了一个变量。undefined意味着在编译过程中根本不存在任何变量或对象。这个变量要么不是 声明,要么声明时缺少一个值,所以不是 已初始化。因此,检查 undefined是避免 JavaScript 中许多类型错误并取代 null的一个非常好的方法。

这就是为什么我在使用 nullundefined时不会依赖“ truthy”检查 true/false,即使它们都会返回一个 false 响应,因为 undefined意味着缺少特性、对象或变量的额外步骤,而不仅仅是一个 true/false 检查。这意味着更多的东西。如果您有一个丢失的未声明变量,true 语句将触发一个 ERROR!

让我们先来看看 undefined:

        //var check1;// variable doesnt even exist so not assigned to "undefined"
var check2;// variable declared but not initialized so assigned "undefined"
var check3 = 'hello world';// variable has a value so not undefined


console.log('What is undefined?');


//console.log(check1 === undefined);// ERROR! check1 does not exist yet so not assigned undefined!
console.log(check2 === undefined);// True
console.log(check3 === undefined);// False
console.log(typeof check1 === 'undefined');// True - stops the ERROR!
console.log(typeof check2 === 'undefined');// True
console.log(typeof check3 === 'undefined');// False

正如您可以看到的 未申报变量,或者 声明但不是 已初始化,都被赋予 undefined类型。注意,未初始化的声明变量被赋值为 undefined,原始值类型但不存在的变量被赋值为 未定义类型

null与缺失的变量或尚未赋值的变量没有任何关系,因为 null仍然是一个值。所以任何带有 null的东西都已经是 声明已初始化了。还要注意分配 null值的变量实际上是 object类型,这与 未定义类型不同。比如说..。

        var check4 = null;
var check5 = 'hello world';


console.log('What is null?');


console.log(check4 === undefined);// False
console.log(check5 === undefined);// False
console.log(typeof check4 === 'undefined');// False
console.log(typeof check5 === 'undefined');// False
console.log(typeof check4);// return 'object'
console.log(typeof check5);// return 'string'


正如您可以看到每个行为不同,但都是基本值,您可以分配任何变量。只要理解它们代表了变量和对象的不同状态。