Undefined
Undefined 是 js 的基本数据类型之一。undefined 的字面意思就是:未定义的值 。这个值的语义是,希望表示一个变量最原始的状态,而非人为操作的结果 。 这种原始状态会在以下 4 种场景中出现:
-
声明一个变量,但是没有赋值
1
2var foo;
console.log(foo); // undefined访问 foo,返回了 undefined,表示这个变量自从声明了以后,就从来没有定义过任何有效的值。
-
访问对象上不存在的属性或者未定义的变量
1
2console.log(Object.foo); // undefined
console.log(typeof demo); // undefined访问 Object 对象上的 foo 属性,返回 undefined , 表示Object 上不存在或者没有定义名为 foo 的属性;对未声明的变量执行typeof操作符返回了undefined值。
-
函数定义了形参,但没有传递实参
1
2
3
4
5//函数定义了形参 a
function fn(a) {
console.log(a); // undefined
}
fn(); //未传递实参函数 fn 定义了形参 a,但 fn 被调用时没有传递参数,因此,fn 运行时的参数 a 就是一个原始的、未被赋值的变量。
-
使用void对表达式求值
1
2
3
4
5void 0 ; // undefined
void false; // undefined
void []; // undefined
void null; // undefined
void function fn(){} ; // undefinedECMAScript 明确规定 void 操作符 对任何表达式求值都返回 undefined ,这和函数执行操作后没有返回值的作用是一样的,JavaScript 中的函数都有返回值,当没有 return 操作时,就默认返回一个原始的状态值,这个值就是 undefined,表明函数的返回值未被定义。
NUll
null 的字面意思是:空值 。这个值的语义是,希望表示一个对象被人为的重置为空对象,而非一个变量最原始的状态 。 在内存里的表示就是,栈中的变量没有指向堆中的内存对象。
一般在以下两种情况下我们会将变量赋值为null
- 如果定义的变量在将来用于保存对象,那么最好将该变量初始化为null,而不是其他值。换句话说,只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存null值,这样有助于进一步区分null和undefined。
- 当一个数据不再需要使用时,我们最好通过将其值设置为null来释放其引用,这个做法叫做解除引用。不过解除一个值的引用并不意味着自动回收改值所占用的内存。解除引用的真正作用是让值脱离执行环境,以便垃圾收集器在下次运行时将其回收。解除引用还有助于消除有可能出现的循环引用的情况。这一做法适用于大多数全局变量和全局对象的属性,局部变量会在它们离开执行环境时(函数执行完时)自动被解除引用。
Undefined 与 Null 的一些奇怪现象
-
undefined
undefined不是一个关键字,可以作为一个变量来使用,也就是说在一定条件下你可以随意更改它。
-
全局属性 window.undefined
- chrome 77.0.3865.75 环境
结果是undefined,也就是在新版的谷歌浏览器里面的全局作用域下面是无法更改undefined的
1
2
3//这次改用const
const undefined = 2; //Identifier 'undefined' has already been declared
console.log(undefined);用const则会报错,已经declared了,let也同样
1
2var undefined = 2;
console.log(undefined); //undefined这样的结果还是undefined,所以在ie11的全局作用域下面也不能替换
- 直到ie8版本的浏览器发生了变化
1
2var undefined = 2;
console.log(undefined); //2竟然改变了,ie8的全局作用域下是可以改变undefined的
-
函数作用域
在谷歌浏览器77.0.3865.75 版本下,我们试试在函数作用域下
1
2
3
4(function () {
var undefined = 2
console.log(undefined); //2
})()发现这样就改变了undefined
1
2
3
4(function () {
const undefined = 2
console.log(undefined); //2
})()const同样可行,并且在ie的11,10,9,8几个版本中,无一例外的,undefined都被覆盖了
原因
在全局作用域下,全局变量会变成 window上面的一个属性,相当于 window.undefined ,这时候我们查看这个属性
1
2
3// chrome 77.0.3865.75
console.log(Object.getOwnPropertyDescriptor(window, undefined));
//{value: undefined, writable: false, enumerable: false, configurable: false}(chrome 77.0.3865.75环境)这时候拿到数据属性可以看到,不可重写,不可枚举,不可改变特征值或者被删除,所以在全局作用域下面是不可以被重写的.
ie8环境下:
1
2console.log(Object.getOwnPropertyDescriptor(window, undefined));
//{configurable: false, enumerable: false, value: undefined, writable: true}ie8同样,不可枚举,不可删除或修改特征值,但是!!可以被重写!!所以ie8的全局作用域上面是可以被重写的!!
-
-
null
typeof null 的结果是object
1
2var data = null;
console.log(typeof data); // "object"typeof null 的结果为什么不是 null:
在 javascript 的最初版本中,使用的 32 位系统,并且底层都表示为2进制,为了性能考虑使用低位存储了变量的类型信息:
- 000:对象
- 1:整数
- 010:浮点数
- 100:字符串
- 110:布尔
- 全部为0: null
所以typeof就是利用这一机制去判断的,所以null全部为0就复合了对象的000,所以被判断为object
并且还有个注意点
1
2null == undefined
//true null和undefined用==比较结果是true,并且没有发生隐式转换,就是true
Undefined、Null 类型判断
判断 Undefined
判断一个变量是否为 undefined 有两种方法。
-
使用严格相等符
===
或不相等操作符!==
来决定一个变量是否拥有值,这里不使用标准相等操作符==
,是因为标准相等符还会会检查变量是不是为null,但是严格相等操作符不会检查。1
2
3
4
5
6var data;
if (data === undefined) { // true
// do sth
}
undefined == null; //true
undefined === null; // false -
使用typeof操作符,这种方式我们在上面已经使用过了,对未定义的变量检测时只能使用这种方式,要不然会出现报错。
1
2
3
4var data;
if (typeof data === "undefined") { // true
// do sth
}
void 0
上面我们提到过了,undefined作为局部变量使用是可以被重写的,那么如果我们使用下面这种判断方式,是有风险的。
1 | if(data === undefined){ |
官方文档对 void 运算符的解释如下:
The void operator evaluates the given expression and then returns undefined.
void 运算符 对给定的表达式进行求值,然后返回 undefined
使用void对后面的表达式求值,无论结果是多少,都会返回原始值undefined。因此我们可以用void 0
来代替undefined进行判断,因为void 0
始终返回的都是原始值undefined。
1 | var data; |
判断 Null
null的判断可以使用严格相等符===
或不相等操作符!==
判断,不使用标准相等符的原因是因为undefined会影响判断结果。和undefined不一样,不能使用typeof来判断一个值是否为null,原因上边已经讲了,使用typeof来检测null会返回"object",这样的话我们是没办法判断的。
1 | if(data === null){ |
Undefined 与 Null 的区别
用一句话总结两者的区别就是:undefined 表示一个变量自然的、最原始的状态值,而 null 则表示一个变量被人为的设置为空对象,而不是原始状态。所以,在实际使用过程中,为了保证变量所代表的语义,不要对一个变量显式的赋值 undefined,当需要释放一个对象时,直接赋值为 null 即可。
参考