当讨论JavaScript中的原始数据类型时,大多数人都知道的基本知识,从String,Number到Boolean。这些原始类型相当简单,行为符合常识。但是,本文将更多聚焦独特的原始数据类型Null和Undefined,是什么让他们如此相似,却又似是而非。

理解Null和Undefined

在JavaScript中,null是字面量同时也是语言中的关键字,用来表示无法识别的对象值。换句话说,这用来表示“无值(no value)”。虽然相似,undefined实际上代表了不存在的值(non-existence of a value)。都是完全不可变的,没有属性和方法,也不能给其属性赋值。事实上,试图访问或定义一个属性将会引发一个类型错误(TypeError)。正如他们的名字暗示的那样,他们是完全无效的值。

没有值代表的布尔值是false,这意味着他们在条件上下文中会被被计算为false,如if语句。使用相等操作符(= =)比较这两个值和其他false值,他们并不等于除了自己:

null == 0; // false
undefined == ""; // false
null == false; // false
undefined == false; // false
null == undefined; // true

尽管如此,和其他相似之处,但null和undefined并不是等价的。每个作为其独特的类型的唯一成员,undefined是Undefined类型和null是Null类型。使用全等操作符(===)比较这两个值,这要求类型和值都相等,下面证明这一点:

undefined === null; // false
这是一个重要的区别,服务于不同的目的和理由。区分这两个值,你可以认为undefined代表一个意想不到的没有值而null作为预期没有值的代表。

产生Undefined

有许多的方法产生一个undefined值的代码。它通常遇到当试图访问一个不存在的值时。在这种情况下,在JavaScript这种动态的弱类型语言中,只会默认返回一个undefined值,而不是上升为一个错误。
任何声明变量时没有提供一个初始值,都会有一个为undefined的默认值:
 
var foo; // 默认值为 undefined

当试图访问一个不存在的对象属性或数组项时,返回一个undefined值:

var array = [1, 2, 3];
var foo = array.foo; // foo 属性不存在, 返回 undefined
var item = array[5]; // 数组中没有索引为5的项,返回 undefined

如果省略了函数的返回语句,返回undefined:

var value = (function(){})(); // 返回 undefined

函数调用时未提供的值结果将为undefined参数值:

(function(undefined){
// 参数是 undefined
})();

void操作符也可以返回一个undefined值。像Underscore的库使用它作为一个防御式的类型检查,因为它是不可变的,可以在任何上下文依赖返回undefined:

function isUndefined(obj){
return obj === void 0;
}

最后,undefined是一个预定义的全局变量(不像null关键字)初始化为undefined值:

'undefined' in window; // true

ECMAScript 5中,这个变量是只读的,以前并非如此。

Null的用例

null的用例是使他与众不同的主要方面,因为不像undefined,null被认为是更有用。这正是为什么typeof操作符作用于null值时返回“object”。最初的理由是,现在仍然是,通常用作一个空引用一个空对象的预期,就像一个占位符。typeof的这种行为已经被确认为一个错误,虽然提出了修正,出于后兼容的目的,这一点已经保持不变。
这就是为什么JavaScript环境从来没有设置一个值为null;它必须以编程方式完成。正如文档MDN所说:
在api中,null是经常检索对象的地方可以预期,但没有相关的对象。
这适用于DOM,它是独立于语言的,不属于ECMAScript规范的范围。因为它是一个外部API,试图获取一个不存在的元素返回一个null值,而不是undefined。
一般来说,如果你需要给一个变量或属性指定一个不变值,将它传递给一个函数,或者从一个函数返回null,null几乎总是最好的选择。简而言之,JavaScript使用undefined并且程序员应该使用null。
null的另一个可行的用例,也被认为是良好的实践是一个显式指定变量为无效(object= null)当一个引用不再是必需的。通过分配null值,有效地清除引用,并假设对象没有引用其他代码,指定垃圾收集,确保回收内存。

深入挖掘

使null和undefined像黑洞的不只是他们的行为,而是在他们在JavaScript环境的内部的处理方式。他们似乎通常并不具有同样的关联特征与其他原生或内置对象。
在ES5中,Object.prototype.toString方法,已经成为实际的类型检查标准,这在null和undefined中被证明是一致的:
Object.prototype.toString.call(null); // [object Null]
Object.prototype.toString.call(undefined); // [object Undefined]

然而,Object.prototype.toString方法实际上并不是检索null的内部[[Class]]属性或undefined的公开构造函数。根据文档,以下步骤发生在被调用过程中:

  1. 如果值是undefined,返回“[object Undefined]”。
  2. 如果这个值为null,则返回“[object Null]”。
  3. 让O作为调用ToObject同时传递this值作为参数的结果值。
  4. 让class是O的内部属性[[Class]]的值。
  5. 返回的结果连接三个字符串“[object ”,class,和“]”的结果的字符串值。

该方法执行一个简单的字符串返回值,如果它检测到null或undefined和其他对象统一的功能。在整个规范中这是很常见的,因为当遇到null和undefined值时大多数方法包含一个简单的捕捉并返回。事实上,没有迹象表明他们包含与任何原生对象相关联的内部属性。就好像他们不是对象。我很想知道如果一个JavaScript的原生环境内部实际存在的显式方案会怎样?也许有人更熟悉一个可以参与的实现。

结论

无论这些原生对象多么不寻常,理解null和undefined之间的差异,和他们在JavaScript的语言基础中截然不同的角色。它可能不能使你的应用程序有所突破,但是一般来说,它仅被证明在开发和调试中长期有益。

译者注

本文问翻译文章,原文为“Exploring the Abyss of Null and Undefined in JavaScript

本文较难以理解,可参照原文便于理解。

 支持我继续翻译吧。

更多文章请访问的我的博客

 关注我的微博吧

探索JavaScript中Null和Undefined的深渊的更多相关文章

  1. JavaScript中Null和Undefined的深渊

    探索JavaScript中Null和Undefined的深渊 当讨论JavaScript中的原始数据类型时,大多数人都知道的基本知识,从String,Number到Boolean.这些原始类型相当简单 ...

  2. JavaScript中null和undefined的总结

    先说null,它表示一个特殊值,常用来描述“空值”.对null执行typeof运算,结果返回字符串“object”,也就是说,可以将null认为是一个特殊的对象值,含义是“非对象”(感觉怪怪的).实际 ...

  3. JavaScript中null和undefined

    JavaScript的数据类型大体分为两类:原始类型和对象类型.其中,原始类型包括数字.字符串和布尔值.此外,JavaScript中还有两个特殊的原始值:null(空)和undefined(未定义), ...

  4. JavaScript中Null和Undefined的区别

    Null: null是js中的关键字,表示空值,null可以看作是object的一个特殊的值,如果一个object值为空,表示这个对象不是有效对象. Undefined: undefined不是js中 ...

  5. Javascript 中 null和undefined的区别

    null表示"没有对象",即该处不应该有值.典型用法是: (1) 作为函数的参数,表示该函数的参数不是对象. (2) 作为对象原型链的终点. Object.getPrototype ...

  6. javascript中null与undefined的区别

    1.null null是一个对象,表示一个空对象指针,typeof(null)返回object,null参与运算时会转化为0,将对象初始化为null,可以知道变量是否保存了对象的引用 2.undefi ...

  7. JavaScript typeof, null, 和 undefined

    typeof 操作符 你可以使用 typeof 操作符来检测变量的数据类型. 实例 typeof "John"                // 返回 string typeof ...

  8. JavaScript中调皮的undefined

    JavaScript中调皮的undefined 在JavaScript中undefined只是一个标识符,不是关键字,这个很不靠谱的标识符还不能像其他符号一样随意使用,一方面是需要它的原始值保持不变, ...

  9. JavaScript中 null 的 typeof是object

    JavaScript中  null 的 typeof是object

随机推荐

  1. 柳叶刀重磅出击!全外显子测序在胎儿结构异常的评估Whole-exome sequencing in the evaluation of fetal structural anomalies: a prospective cohort study

    柳叶刀发表的文献解读:Whole-exome sequencing in the evaluation of fetal structural anomalies: a prospective coh ...

  2. Kubenetes 资源清单定义入门

    Kubernetes 常用资源 资源  对象 工作负载型资源对象(workload): Pod  Replicaset  ReplicationController  Deployments Stat ...

  3. saltstack主机管理项目:编写插件基类-获取主机列表-提取yaml配置文件(四)

    一.编写插件基类 1.目录结构 1.我是如何获知我有多少种系统? 当客户端第一连接过来的时候,我就已经把这些文件存下来了 ,存在到哪里了?存到数据库了 每次对主机发送命令的动作时,我从库里把数据取出来 ...

  4. EF CodeFirst系列(8)--- FluentApi配置单个实体

    我们已经知道了在OnModelCreating()方法中可以通过FluentApi对所有的实体类进行配置,然而当实体类很多时,我们把所有的配置都放在OnModelCreating()方法中很难维护.E ...

  5. 迅为iTOP-4418开发板-Android5.1系统编译补充

    基于iTOP-4418开发板-Android5.1系统编译补充 5.6 编译-20181225 日期之后的源码 本文档补充介绍 4418 编译网盘目录 “J:\局域网共享_阮\iTOP4418 开发板 ...

  6. Codeforces Round #501 (Div. 3) D. Walking Between Houses

    题目链接 题意:给你三个数n,k,sn,k,sn,k,s,让你构造一个长度为k的数列,使得相邻两项差值的绝对值之和为sss, ∑i=1n∣a[i]−a[i−1]∣,a[0]=1\sum_{i=1}^n ...

  7. day 17 - 2 递归函数练习

    1.斐波那契   问第n个斐波那契数是多少 #这个效率是低的,最好不要使用双递归 def fib(n): if n == 1 or n == 2: return 1 return fib(n-1) + ...

  8. Go 环境配置

    1.下载SDK 官网:https://golang.google.cn/ go中文在线文档:https://studygolang.com/pkgdoc 2.配置环境变量 windows使用.msi一 ...

  9. Django 反向解析

    #1,定义: #随着功能的增加会出现更多的视图,可能之前配置的正则表达式不够准确,于是就要修改正则表达式,但是正则表达式一旦修改了,之前所有对应的超链接都要修改,真是一件麻烦的事情,而且可能还会漏掉一 ...

  10. 获取搜索结果的真实URL、描述、标题

    1.场景 爬虫练手代码 2.代码 Python2: #!/usr/bin/python # -*- coding:utf-8 -*- import requests from lxml import ...