我想知道JavaScript中null和undefined之间的区别。


当前回答

null和undefined是两种不同的对象类型,它们具有以下共同点:

两者都只能保存一个值,分别为null和undefined;两者都没有财产或方法,尝试读取其中一个的任何财产都会导致运行时错误(对于所有其他对象,如果尝试读取不存在的属性,则会得到未定义的值);通过==和!=,值null和undefined被视为彼此相等,其他值都不相等操作员。

然而,相似之处到此为止。这一次,在实现关键字null和undefined的方式上有一个根本的区别。这并不明显,但请考虑以下示例:

var undefined = "foo";
WScript.Echo(undefined); // This will print: foo

undefined、NaN和Infinity只是预初始化的“超级全局”变量的名称-它们在运行时被初始化,可以被具有相同名称的普通全局或局部变量覆盖。

现在,让我们对null做同样的尝试:

var null = "foo"; // This will cause a compile-time error
WScript.Echo(null);

哎呀!null、true和false是保留关键字-编译器不允许将它们用作变量或属性名称

另一个区别是undefined是一种基本类型,而null是一种对象类型(表示没有对象引用)。考虑以下事项:

WScript.Echo(typeof false); // Will print: boolean
WScript.Echo(typeof 0); // Will print: number
WScript.Echo(typeof ""); // Will print: string
WScript.Echo(typeof {}); // Will print: object
WScript.Echo(typeof undefined); // Will print: undefined
WScript.Echo(typeof null); // (!!!) Will print: object

此外,在数字上下文中处理null和undefined的方式也有一个重要的区别:

var a; // declared but uninitialized variables hold the value undefined
WScript.Echo(a === undefined); // Prints: -1

var b = null; // the value null must be explicitly assigned 
WScript.Echo(b === null); // Prints: -1

WScript.Echo(a == b); // Prints: -1 (as expected)
WScript.Echo(a >= b); // Prints: 0 (WTF!?)

WScript.Echo(a >= a); // Prints: 0 (!!!???)
WScript.Echo(isNaN(a)); // Prints: -1 (a evaluates to NaN!)
WScript.Echo(1*a); // Prints: -1.#IND (in Echo output this means NaN)

WScript.Echo(b >= b); // Prints: -1 (as expected)
WScript.Echo(isNaN(b)); // Prints: 0 (b evaluates to a valid number)
WScript.Echo(1*b); // Prints: 0 (b evaluates to 0)

WScript.Echo(a >= 0 && a <= 0); // Prints: 0 (as expected)
WScript.Echo(a == 0); // Prints: 0 (as expected)
WScript.Echo(b >= 0 && b <= 0); // Prints: -1 (as expected)
WScript.Echo(b == 0); // Prints: 0 (!!!)

当在算术表达式或数字比较中使用null时,null变为0-与false类似,它基本上只是一种特殊的“零”。另一方面,undefined是一个真正的“无”,当您尝试在数字上下文中使用它时,它会变成NaN(“非数字”)。

注意,null和undefined从==和!=接收特殊处理运算符,但可以使用表达式(a>=b&&a<=b)测试a和b的真正数值相等性。

其他回答

请仔细阅读以下内容。它应该可以消除您对JavaScript中null和undefined之间区别的所有疑虑。此外,您可以在答案末尾使用效用函数来获取更具体的变量类型。

在JavaScript中,我们可以有以下类型的变量:

未声明的变量已声明但未分配的变量未定义文字赋值的变量赋值为文本null的变量变量分配了除未定义或null以外的任何值

以下逐一解释了每种情况:

未声明的变量只能使用返回字符串“undefined”的typeof运算符进行检查不能用松散相等运算符(==undefined)检查,更不用说严格相等运算符(===undefineed),以及if语句和三元运算符(?:)-这些抛出引用错误已声明但未分配的变量typeof返回字符串“undefined”==检查null返回true==未定义的检查返回true==检查null返回false==未定义的检查返回trueif语句和三元运算符(?:)是否错误未定义文字赋值的变量这些变量与已声明但未分配的变量完全相同。赋值为文本null的变量typeof返回字符串“object”==检查null返回true==未定义的检查返回true==检查null返回true==检查未定义返回falseif语句和三元运算符(?:)是否错误变量分配了除未定义或null以外的任何值typeof返回以下字符串之一:“bigint”、“boolean”、“function”、“number”、“object”、“string”、“symbol”

以下提供了正确检查变量类型的算法:

获取变量的类型,如果它不是“object”,则返回它检查null,因为typeof null也返回“object”使用switch语句对Object.protype.toString.call(o)求值,以返回更精确的值。Object的toString方法为本机/主机对象返回类似“[Object ConstructorName]”的字符串。对于所有其他对象(用户定义的对象),它始终返回“[object object]”如果最后一部分是这种情况(变量的字符串化版本为“[objectObject]”),并且参数returnConstructorBoolean为真,则它将尝试通过对其进行字符串化并从中提取名称来获取构造函数的名称。如果无法访问构造函数,将照常返回“object”。如果字符串不包含其名称,则返回“匿名”

(支持ECMAScript 2020之前的所有类型)

function TypeOf(o, returnConstructorBoolean) {
  const type = typeof o

  if (type !== 'object') return type
  if (o === null)        return 'null'

  const toString = Object.prototype.toString.call(o)

  switch (toString) {
    // Value types: 6
    case '[object BigInt]':            return 'bigint'
    case '[object Boolean]':           return 'boolean'
    case '[object Date]':              return 'date'
    case '[object Number]':            return 'number'
    case '[object String]':            return 'string'
    case '[object Symbol]':            return 'symbol'

    // Error types: 7
    case '[object Error]':             return 'error'
    case '[object EvalError]':         return 'evalerror'
    case '[object RangeError]':        return 'rangeerror'
    case '[object ReferenceError]':    return 'referenceerror'
    case '[object SyntaxError]':       return 'syntaxerror'
    case '[object TypeError]':         return 'typeerror'
    case '[object URIError]':          return 'urierror'

    // Indexed Collection and Helper types: 13
    case '[object Array]':             return 'array'
    case '[object Int8Array]':         return 'int8array'
    case '[object Uint8Array]':        return 'uint8array'
    case '[object Uint8ClampedArray]': return 'uint8clampedarray'
    case '[object Int16Array]':        return 'int16array'
    case '[object Uint16Array]':       return 'uint16array'
    case '[object Int32Array]':        return 'int32array'
    case '[object Uint32Array]':       return 'uint32array'
    case '[object Float32Array]':      return 'float32array'
    case '[object Float64Array]':      return 'float64array'
    case '[object ArrayBuffer]':       return 'arraybuffer'
    case '[object SharedArrayBuffer]': return 'sharedarraybuffer'
    case '[object DataView]':          return 'dataview'

    // Keyed Collection types: 2
    case '[object Map]':               return 'map'
    case '[object WeakMap]':           return 'weakmap'

    // Set types: 2
    case '[object Set]':               return 'set'
    case '[object WeakSet]':           return 'weakset'

    // Operation types: 3
    case '[object RegExp]':            return 'regexp'
    case '[object Proxy]':             return 'proxy'
    case '[object Promise]':           return 'promise'

    // Plain objects
    case '[object Object]':
      if (!returnConstructorBoolean)
        return type

      const _prototype = Object.getPrototypeOf(o)
      if (!_prototype)              
        return type

      const _constructor = _prototype.constructor
      if (!_constructor)            
        return type

      const matches = Function.prototype.toString.call(_constructor).match(/^function\s*([^\s(]+)/)
        return matches ? matches[1] : 'anonymous'

    default: return toString.split(' ')[1].slice(0, -1)
  }
}

undefined表示变量已声明但尚未赋值:

var测试var;console.log(testVar)//显示未定义console.log(testVar类型)//显示未定义

null是赋值。它可以作为无值表示分配给变量:

var testVar=空;console.log(testVar)//显示nullconsole.log(testVar类型)//显示对象

从前面的示例中可以清楚地看到,undefined和null是两种不同的类型:undefineed是类型本身(undefine),而null是对象。

证明:

console.log(null==未定义)//false(类型不同)console.log(null==undefined)//true(但为“相同值”)console.log(null==null)//true(类型和值相同)

and

null = 'value' // Uncaught SyntaxError: invalid assignment left-hand side
undefined = 'value' // 'value'

在Javascript中,null是一个空值或不存在的值,必须赋值。但Undefined表示已声明变量,但未定义值。

let a = null;  
console.log(a);    // null
let b;         
console.log(b);    // undefined

在JS中,null和undefined都是原始值。您还可以查看以下代码行

console.log(typeof null); //Object
console.log(typeof undefined); //undefined
console.log(10+null); // 10
console.log(10+undefined); //NaN

在javascript中,所有变量都存储为键值对。每个变量存储为variable_name:variable_value/reference。

undefined表示在内存中给了变量一个空间,但没有给它赋值。作为最佳实践,不应将此类型用作赋值。

在这种情况下,如何表示何时希望变量在代码中的稍后时间没有值?您可以使用类型null,这也是一种用于定义相同事物的类型,缺少值,但它与undefined不同,因为在本例中,内存中实际上有值。该值为空

两者相似,但用法和含义不同。

我从这里选的

未定义的值是当变量没有已分配值。空值是表示空的、空的和空的原始值,或不存在的引用。

当您通过var声明一个变量而不给它赋值时,它将具有未定义的值。就其本身而言,如果您尝试WScript.Echo()或alert()此值,您将看不到任何内容。但是,如果您在其中附加一个空白字符串,那么它会突然出现:

var s;
WScript.Echo(s);
WScript.Echo("" + s);

您可以声明一个变量,将其设置为null,行为是相同的,只是您将看到“null”与“undefined”打印出来。这确实是一个小差异。

您甚至可以将未定义的变量与null进行比较,反之亦然,条件将为true:

undefined == null
null == undefined

然而,它们被认为是两种不同的类型。虽然undefined是一种类型,但null被认为是一个特殊的对象值。通过使用typeof()可以看到这一点,它返回一个表示变量的常规类型的字符串:

var a;
WScript.Echo(typeof(a));
var b = null;
WScript.Echo(typeof(b));

运行上述脚本将产生以下输出:

undefined
object

无论它们是不同的类型,如果您尝试访问其中一个的成员,它们的行为仍然相同,例如,它们将抛出异常。使用WSH,你会看到可怕的“'varname'为空或不是对象”,如果你幸运的话(但这是另一篇文章的主题)。

您可以明确地将变量设置为未定义,但我强烈建议您不要这样做。我建议您只将变量设置成null,并将忘记设置的值保留为未定义。同时,我真的鼓励你总是设置每个变量。JavaScript的作用域链不同于C风格语言,即使是资深程序员也很容易混淆,将变量设置为null是防止基于它的错误的最佳方法。

另一个例子是使用delete运算符时,您将看到未定义的弹出窗口。我们这些来自C世界的人可能会错误地将此解释为破坏对象,但事实并非如此。此操作所做的是从数组中移除下标或从对象中移除成员。对于数组,它不影响长度,但现在认为下标未定义。

var a = [ 'a', 'b', 'c' ];
delete a[1];
for (var i = 0; i < a.length; i++)
WScript.Echo((i+".) "+a[i]);

上述脚本的结果是:

0.) a
1.) undefined
2.) c

在读取从未存在的下标或成员时,也会返回undefined。

null和undefined之间的区别是:JavaScript永远不会将任何东西设置为null,这通常是我们所做的。虽然我们可以将变量设置为undefineed,但我们更喜欢null,因为这不是我们曾经做过的事情。当您调试时,这意味着任何设置为null的事情都是您自己做的,而不是JavaScript。除此之外,这两个特殊值几乎相等。