繁体   English   中英

有什么理由在 JavaScript 中使用 null 而不是 undefined?

[英]What reason is there to use null instead of undefined in JavaScript?

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

我真的没有答案,但根据Nicholas C 的说法。 Zakas ,他的书Web 开发人员的专业 JavaScript的第 30 页:

当定义一个打算稍后保存 object 的变量时,建议将变量初始化为null而不是其他任何东西。 这样,您可以稍后显式检查值null以确定变量是否已填充 object 引用

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

也就是说,有一个主要区别 - 未初始化的变量(包括未传递参数的 function 参数等)始终未定义。

这就是为什么在我的代码中我从不使用 null 除非我无法控制的东西返回 null (例如正则表达式匹配)。 这样做的好处是它简化了很多事情。 我永远不必检查x === undefined || x === null x === undefined || x === null ,我可以检查x === undefined 如果你习惯使用==或者只是if(x)...之类的东西,请停止它。

!x对于空字符串0nullNaN将评估为 true - 即您可能不想要的东西。 如果您想编写不糟糕的 javascript,请始终使用三等号===并且永远不要使用null (改用undefined )。 它会让你的生活更轻松。

归根结底,因为nullundefined都强制转换为相同的值( Boolean(undefined) === false && Boolean(null) === false ),所以从技术上讲,您可以使用其中任何一个来完成工作。 但是,有正确的方法,IMO。

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

    undefined用于描述不指向引用的变量。 这是 JS 编译器会为您处理的事情。 在编译时,JS 引擎会将所有提升变量的值设置为undefined 当引擎逐步执行代码并且值变得可用时,引擎将为相应的变量分配相应的值。 对于那些没有找到值的变量,这些变量将继续保持对原语undefined的引用。

  2. 如果您明确想要将变量的值表示为“无值”,则仅使用 null。

    正如@com2gz 所说: null用于以编程方式定义一些空的东西。 undefined表示引用不存在。 null值定义了对“无”的引用。 如果您正在调用 object 的不存在属性,那么您将得到undefined 如果我故意使该属性为空,那么它必须是null所以你知道它是故意的。

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

我从来没有明确地将任何东西设置为未定义(我在与之交互的许多代码库中都没有遇到过这个)。 另外,我很少使用null 我使用null的唯一时间是当我想将 function 的参数值表示为没有值时,即:

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

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

undefined 是不存在事物概念的地方; 它没有类型,并且之前从未在 scope 中被引用过; null 是已知事物存在的地方,但没有任何价值。

每个人都有自己的编码方式和自己的内部语义,但多年来我发现这是我给问这个问题的人最直观的建议:当有疑问时,做 JavaScript 所做的事情

假设您正在使用 object 属性,例如 jQuery 插件的选项...问问自己 JavaScript 给出的属性尚未定义的值是什么——答案undefined 因此,在这种情况下,我将使用 'undefined' 初始化这些类型的事物,以与 JavaScript 一致(对于变量,您可以使用var myVar;而不是var myVar = undefined; )。

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

如果您使用 JSON,则需要进行特殊情况:对于未定义的属性值,您应该将它们设置为""null ,因为undefined的值不被认为是正确的 Z0ECD11C1D7A2877401DZ48A23 格式。

话虽如此,正如之前的海报所表达的那样,如果你发现你正在用nullundefined在蓝月亮中多次初始化,那么也许你应该重新考虑你如何 go 来编码你的应用程序。

您可能会采用此处建议的约定,但确实没有充分的理由这样做。 它的使用不够一致,没有足够的意义。

为了使约定有用,您首先必须知道被调用的 function 遵循约定。 然后你必须明确地测试返回的值并决定做什么。 如果你得到undefined ,你可以假设发生了某种被称为 function 知道的错误。 但是,如果发生错误,并且 function 知道它,并且将其发送到更广泛的环境中很有用,为什么不使用错误 object 呢? 即抛出错误?

因此,归根结底,除了简单环境中的非常小的程序之外,该约定实际上毫无用处。

一些人说可以将对象初始化为null 我只是想指出解构参数默认值不适用于null 例如:

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

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

这需要在调用 function之前执行null检查,这可能经常发生。

null中一个有用的属性undefined不符合条件:

> 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); });

不知道我是否应该使用这个属性的想法......

DOM 节点和元素不是未定义的,但可能是 null。

  • 元素的最后一个子元素的 nextSibling 是 null。

  • 第一个孩子的前一个兄弟姐妹是 null。

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

但在这些情况下,值都不是undefined 那里没有节点。

在 JavaScript 中,值null表示有意缺少任何 object 值。 null表示缺少标识,表示一个变量指向没有object。

全局undefined属性表示原始值undefined undefined是自动分配给变量的原始值。 undefined表示引用不存在。

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

Whole meaning of using null is just bind variable or property with object which is singleton and have meaning of emptiness,and also null usage have performance purposes. 这两个代码有不同的执行时间。

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. 任何旨在返回结果的 function 如果找不到结果,则应返回 null
  2. 任何不打算返回结果的 function 都会隐式返回 undefined。

对我来说,这个问题很重要,因为任何调用返回结果的 function 的人都应该毫无疑问是否测试未定义与 null。

此答案不尝试解决:

  1. null 与未定义的属性值
  2. 函数中的变量是 null 与未定义

在我看来,变量是您自己的事情,而不是您的 API 的一部分,并且任何 OO 系统中的属性都已定义,因此应使用与未定义时不同的值定义(null 表示已定义,未定义是您的get 访问不在您的对象中的东西)。

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

如果您的代码依赖于与undefined的比较,就好像它是一个关键字( if (foo == undefined) - 一个非常容易犯的错误),它只会起作用,因为没有人使用该名称定义变量。 所有这些代码都容易受到意外或恶意使用该名称定义全局变量的人的攻击。 当然,我们都知道在javascript中意外定义一个全局变量是完全不可能的……

只是想补充一点,使用某些 javascript 库,null 和 undefined 可能会产生意想不到的后果。

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

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收到 object 。
  2. 您引用server_object.errj 它告诉你它是undefined 这意味着它不知道那是什么。
  3. 现在您引用server_object.err 它告诉你它是null 这意味着您引用了一个正确的变量,但它是空的; 因此没有错误。

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

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

你当然可以确保你总是做var hello = null但大多数人不会乱扔他们的代码以确保在故意松散类型的语言中类型健全,当他们和! 运算符将undefinednull视为等效。

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

更不用说在 typescript 中使用它们意味着两件不同的事情。 使用:

interface Example {
    name?: string
}

表示名称可以是未定义的或字符串,但不能是 null。 如果你想要它 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在这里是等价的会破坏代码。 原因是null属于object类型,其中undefined属于undefined类型。 因此,这里的代码中断了,因为您无法在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);  
}

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

要编写简单的代码,您需要降低复杂性和变化。 当 object 上的变量或属性没有值时,它是未定义的,并且要为 null 分配一个 null 值。

未声明与 Null

null既是Object “类型”,又是称为null的 7 个唯一原始值类型之一

undefined既是称为undefined (window.undefined) 的全局 scope 属性,也是称为undefined的 7 个唯一原始值类型之一

它是我们用作我们感兴趣的值的原始类型

null的情况下,作为值类型,这意味着已将空值分配给变量。 这可能意味着一个变量有一个空值,但它仍然是一个值。 它还初始化变量,使其存在,而不是undefined

undefined是一个特例。 当您创建一个变量时,默认情况下它在赋值之前被赋值为undefined ,这意味着该变量不存在或存在但没有赋值。 null一样,它也是原始值类型 但与null不同,这意味着该变量不存在。 这就是为什么在检查值是null还是空之前,最好先检查变量是否存在并使用 undefined 分配了一个变量。 undefined表示编译中没有变量或 object 存在。 该变量要么没有被声明,要么被声明为缺少值,因此没有被初始化 所以undefined是避免许多类型错误并取代null的好方法。

这就是为什么我不会依赖nullundefined的“真实”检查真/假,即使它们会返回错误响应,因为undefined意味着缺少功能、object 或变量,而不仅仅是真/假检查。 它暗示了更多的东西。

我们先来看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
        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'

正如您所看到的,每种行为都不同,但两者都是原始值,您可以分配任何变量。 只需了解它们代表变量和对象的不同状态即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM