JavaScript中null和undefined的区别

JavaScript中null和undefined的区别

技术背景

在JavaScript中,nullundefined 都用于表示值的缺失,但它们有着不同的含义和用途。理解它们之间的区别对于编写高质量的JavaScript代码至关重要。

实现步骤

1. 理解undefined

undefined 表示变量已声明但尚未赋值,或者函数没有返回值,或者访问对象中不存在的属性。

1
2
3
4
5
6
7
8
9
10
11
12
// 变量声明但未赋值
var testVar;
console.log(testVar); // 输出: undefined
console.log(typeof testVar); // 输出: undefined

// 函数没有返回值
function noReturnValue() {}
console.log(noReturnValue()); // 输出: undefined

// 访问对象中不存在的属性
const obj = { name: 'John' };
console.log(obj.age); // 输出: undefined

2. 理解null

null 是一个赋值值,表示变量被有意设置为没有值。

1
2
3
var testVar = null;
console.log(testVar); // 输出: null
console.log(typeof testVar); // 输出: object

3. 比较nullundefined

虽然 nullundefined 在宽松相等比较(==)时返回 true,但它们是不同的类型,在严格相等比较(===)时返回 false

1
2
3
console.log(null === undefined); // 输出: false
console.log(null == undefined); // 输出: true
console.log(null === null); // 输出: true

核心代码

检查不同类型变量的表现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 未声明变量
// console.log(typeof undeclaredVar); // 输出: undefined
// console.log(undeclaredVar === undefined); // 报错: ReferenceError

// 声明但未赋值变量
var declaredButUnassigned;
console.log(typeof declaredButUnassigned); // 输出: undefined
console.log(declaredButUnassigned == null); // 输出: true
console.log(declaredButUnassigned == undefined); // 输出: true
console.log(declaredButUnassigned === null); // 输出: false
console.log(declaredButUnassigned === undefined); // 输出: true

// 赋值为undefined的变量
var assignedUndefined = undefined;
console.log(typeof assignedUndefined); // 输出: undefined
console.log(assignedUndefined == null); // 输出: true
console.log(assignedUndefined == undefined); // 输出: true
console.log(assignedUndefined === null); // 输出: false
console.log(assignedUndefined === undefined); // 输出: true

// 赋值为null的变量
var assignedNull = null;
console.log(typeof assignedNull); // 输出: object
console.log(assignedNull == null); // 输出: true
console.log(assignedNull == undefined); // 输出: true
console.log(assignedNull === null); // 输出: true
console.log(assignedNull === undefined); // 输出: false

自定义类型检查函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
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);
}
}

最佳实践

  • 使用null:当你明确知道某个变量或对象应该没有值时,使用 null。例如,初始化一个对象变量,但还没有实际的对象可以赋值时。
1
2
3
let myObject = null;
// 稍后赋值
myObject = { name: 'Example' };
  • 使用undefined:让JavaScript自动为未赋值的变量赋予 undefined 值,避免手动将变量设置为 undefined。在函数中,如果没有合适的返回值,自然返回 undefined

常见问题

1. nullundefined 在数值上下文中的表现不同

1
2
3
4
5
6
7
8
9
10
11
12
13
var a;
var b = null;

console.log(a === undefined); // 输出: true
console.log(b === null); // 输出: true
console.log(a == b); // 输出: true
console.log(a >= b); // 输出: false
console.log(a >= a); // 输出: false
console.log(isNaN(a)); // 输出: true
console.log(1 * a); // 输出: NaN
console.log(b >= b); // 输出: true
console.log(isNaN(b)); // 输出: false
console.log(1 * b); // 输出: 0

null 在算术表达式或数值比较中表现得像 0,而 undefined 会变成 NaN

2. undefined 可以被覆盖,而 null 是保留关键字

1
2
3
4
var undefined = 'foo';
console.log(undefined); // 输出: foo

// var null = 'foo'; // 报错: Uncaught SyntaxError: Unexpected token null

不建议覆盖 undefined,因为这会导致代码的可读性和可维护性变差。


JavaScript中null和undefined的区别
https://119291.xyz/posts/difference-between-null-and-undefined-in-javascript/
作者
ww
发布于
2025年5月27日
许可协议