前端JavaScript基础训练系列八十七:undefined 和 undeclared

变量在未持有值的时候为 undefined。此时 typeof 返回 “undefined”:

    var a;
     typeof a; // "undefined"
     var b = 42;
     var c;
// later
b = c;
     typeof b; // "undefined"
     typeof c; // "undefined"

大多数开发者倾向于将 undefined 等同于 undeclared(未声明),但在 JavaScript 中它们完全 是两回事。
已在作用域中声明但还没有赋值的变量,是 undefined 的。相反,还没有在作用域中声明 过的变量,是 undeclared 的。
例如:

var a;
     a; // undefined
     b; // ReferenceError: b is not defined

浏览器对这类情况的处理很让人抓狂。上例中,“b is not defined”容易让人误以为是“b is undefined”。这里再强调一遍,“undefined”和“is not defined”是两码事。此时如果浏览器 报错成“b is not found”或者“b is not declared”会更准确。
更让人抓狂的是 typeof 处理 undeclared 变量的方式。例如:

    var a;
     typeof a; // "undefined"
     typeof b; // "undefined"

对于 undeclared(或者 not defined)变量,typeof 照样返回 “undefined”。请注意虽然 b 是 一个undeclared变量,但typeof b并没有报错。这是因为typeof有一个特殊的安全防范 机制。
此时 typeof 如果能返回 undeclared(而非 undefined)的话,情况会好很多。 1.3.2 typeof Undeclared
该安全防范机制对在浏览器中运行的 JavaScript 代码来说还是很有帮助的,因为多个脚本 文件会在共享的全局命名空间中加载变量。
很多开发人员认为全局命名空间中不应该有变量存在,所有东西都应该被封 装到模块和私有 / 独立的命名空间中。理论上这样没错,却不切实际。然而 这仍不失为一个值得为之努力奋斗的目标。好在 ES6 中加入了对模块的支 持,这使我们又向目标迈近了一步。

举个简单的例子,在程序中使用全局变量 DEBUG 作为“调试模式”的开关。在输出调试信 息到控制台之前,我们会检查 DEBUG 变量是否已被声明。顶层的全局变量声明 var DEBUG = true 只在 debug.js 文件中才有,而该文件只在开发和测试时才被加载到浏览器,在生产环 境中不予加载。
问题是如何在程序中检查全局变量 DEBUG 才不会出现 ReferenceError 错误。这时 typeof 的 安全防范机制就成了我们的好帮手:

// 这样会抛出错误 if (DEBUG) {
         console.log( "Debugging is starting" );
     }
// 这样是安全的
if (typeof DEBUG !== "undefined") {
         console.log( "Debugging is starting" );
     }

这不仅对用户定义的变量(比如 DEBUG)有用,对内建的 API 也有帮助:

    if (typeof atob === "undefined") {
         atob = function() { /*..*/ };
}

如果要为某个缺失的功能写 polyfill(即衬垫代码或者补充代码,用来补充 当前运行环境中缺失的功能),一般不会用var atob来声明变量atob。如 果在if语句中使用var atob,声明会被提升(hoisted,参见《你不知道的 JavaScript(上卷)》1 中的“作用域和闭包”部分)到作用域(即当前脚本或 函数的作用域)的最顶层,即使 if 条件不成立也是如此(因为 atob 全局变 量已经存在)。在有些浏览器中,对于一些特殊的内建全局变量(通常称为
“宿主对象”,host object),这样的重复声明会报错。去掉 var 则可以防止声 明被提升。
还有一种不用通过 typeof 的安全防范机制的方法,就是检查所有全局变量是否是全局对象 的属性,浏览器中的全局对象是 window。所以前面的例子也可以这样来实现:

    if (window.DEBUG) {
         // ..
}
     if (!window.atob) {
         // ..
}

与 undeclared 变量不同,访问不存在的对象属性(甚至是在全局对象 window 上)不会产生 ReferenceError 错误。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值