跳至主要内容

JavaScript从零开始——数据类型(1)

 了解了前面的入门内容,其实已经可以开始尝试上手写一些简单的JavaScript代码了,不过如果想要真正的不踩坑,所有开发语言都绕不过的几大专题都还是需要了解的,包括:

  • 数据类型
  • 运算符
  • 开发语法
  • 标准库
  • 面向对象编程

还有些JavaScript比较擅长或者是独有的专题,包括:

  • 异步操作
  • DOM
  • 事件
  • 浏览器模型

这里先从最最基础的数据类型开始了解。

1. 概述

JavaScript的所有值,都分别属于某一种数据类型,到ES 6为止,共有7种类型,包括有:

  • 数值(number):整数和小数(比如12.2
  • 字符串(string):文本(比如Everybody Loves Eileen)。
  • 布尔值(boolean):表示真伪的两个特殊值,即true(真)和false(假)
  • undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值
  • null:表示空值,即此处的值为空
  • 对象(object):各种值组成的集合
  • Symbol独一无二的值,可以保证不会与其他属性名产生冲突

其中,数值、字符串、布尔值以及ES 6新增加的Symbol被称为原始类型(primitive type)值,因为它们是最基本的数据类型无法再被细分;undefined和null属于特殊值。

对象则称为合成类型(complex type)值,因为一个对象往往是多个原始类型值的合成,更像是存放各种值的容器;它比较复杂,又可细分为三个子类型:

    • 狭义的对象(object):后文所有对象都特指该子类型;
    • 数组(array):与对象有不同的数据组合方式;
    • 函数(function):处理数据的方法,JavaScript把它也当作一种数据类型,可以赋值给变量,是函数式编程的基础。

2. 内置的类型识别方法

JavaScript有三种方法可以确定一个值究竟是什么类型:

  • typeof 运算符

通过该运算符,可以返回一个值的数据类型。

如下图:

由于typeof是可以判断一个变量是否未定义的,所以经常可以在判断语句当中是用来确认一个变量是否有效,如下:

if (typeof x !== 'undefined') {
  // ...代码
}

不过针对对象,它的用途就不明确了,如下图:

可以看出typeof是无法识别对象或者数组的,这种情况下,有必要使用其他的方式来区分对象和数组,可以考虑使用instanceof运算符。

同时也应该发现到null也被识别为了对象,这个是由于历史原因造成的,在最初版本设计之初,其实只设计了5中数据对象(对象、整数、浮点数、字符串和布尔值),并没有考虑过null,而是把它作为了对象的一种特殊值。尽管后来独立出来作为单独的数据类型,但是为了兼容以前的代码,typeof null的返回值object就无法更改了。

  • instanceof 运算符

instanceof是从Java引入的运算符,本质上就是用来判断一个实例是不是属于某种类型的,所以并不局限于对象,它是可以用来判断绝大多数的数据类型,不过因为它的返回值只有真伪两种,也就是说,开发者在使用它的时候需要先自己明确需要判断的类型,比如:

明确定义并进行判断

如果自己无法确定,就会出现上图的情况,一个数组x,它可以判断为数组,但也可以判断为对象,因为数组本身是对象的子类型;所以必须要明确地知道自己需要进行什么判断。

注:在实际使用过程中,由于语言规范中对于instanceof运算符的定义是需要含有一个HasInstance方法的,如果没有该方法则结果直接返回false,故此请勿使用它来对NumberStringBooleanundefined进行判断,因为它们都是不能够再进行细分的数据类型。

  • Object.prototype.toString.call() 方法

如果真的要判断某个对象值究竟属于那种类型,上述两种方法都各有弊端,那么有没有更靠谱一点的方法呢?

在不自己构建函数,比引用外部组件的情况下,最佳选择莫过于Object.prototype.toString.call()这个方法了,如:

这个方法,基本上所有的数据类型都可以分辨出来,至于ES 6新加入的Symbol,我们也可以看看测试结果:

所以基本都是没什么问题的;同时它还可以帮你检查出对象的更细节的类型,比如:日期时间类型(Date)、数学类(Math)、正则表达式(RegExp)等等这些特殊的对象,都可以正确的识别出来,可谓很强大了。

3. 特殊类型:null和undefined

看完了上面的如何分辨数据类型,我们会发现两个非常特殊的类型:nullundefined

虽然我们大概说明过了它们,但还是需要详细的了解,才能更好的避免踩坑。

3.1 历史

事实上在各类开发语言当中,你都很难见到undefined这个类型的身影,在表现形式上甚至使用上,undefinednull都非常的相似:

如上图,在使用==(相等运算符)比较两者时,结果甚至是相等的!

当然由于它们分别属于不同的数据类型,使用全等运算符===(也就是严格相等运算符)的时候,它们不同。

既然含义和用法都差不多,为什么会出现一个undefined类型,徒然增加了复杂程度呢?

这与历史原因有关。

1995年 JavaScript 诞生时,最初像 Java 一样,只设置了null表示"无"。根据 C 语言的传统,null可以自动转为0。
但是,JavaScript 的设计者 Brendan Eich,觉得这样做还不够。首先,第一版的 JavaScript 里面,null就像在 Java 里一样,被当成一个对象,Brendan Eich 觉得表示“无”的值最好不是对象。其次,那时的 JavaScript 不包括错误处理机制,Brendan Eich 觉得,如果null自动转为0,很不容易发现错误。
因此,他又设计了一个undefined。区别是这样的:null是一个表示“空”的对象,转为数值时为0;undefined是一个表示"此处无定义"的原始值,转为数值时为NaN(Not a Number ,非数字),如下图:

3.2 用法和含义

对于容易混淆的初学者,我个人建议这样理解:

null表示空值,和其他语言一样,它的出现不会造成运行错误,是一个真实存在的值。

undefined则表示未定义,它会造成运行错误,主要会出现在下列场景中:

// 变量声明了,但没有赋值
var i;
i // undefined

// 调用函数时,应该提供的参数没有提供,该参数等于 undefined
function f(x) {
  return x;
}
f() // undefined

// 对象没有赋值的属性
let o = new Object();
o.p // undefined

// 函数没有返回值时,默认返回 undefined
function f() {}
f() // undefined

评论

此博客中的热门博文

Node.js从零开始——事件、系统和流

毕竟不是一个真正的教程,这里主要还是以普及和介绍为主,所以这一部分就是 Node.js 的其他部分介绍了,主要也就是事件触发、操作系统以及流的知识。 1 事件触发器 因为我们之前在浏览器中使用 JavaScript ,所以知道 JS 通过事件处理了许多用户的交互:鼠标的单击、键盘按钮的按下、对鼠标移动的反应等等。 在后端, Node.js 也提供了使用 events 模块 构建类似系统的选项。 具体上,此模块提供了 EventEmitter 类,用于处理事件。 使用以下代码进行初始化: const EventEmitter = require ( 'events' ); const eventEmitter = new EventEmitter (); 该对象公开了 on 和 emit 方法: emit 用于触发事件 on 用于添加回调函数(会在事件被触发时执行) 例如,创建 start 事件,并提供一个示例,通过记录到控制台进行交互: eventEmitter . on ( 'start' , () => { console . log ( '开始' ); }); 当运行以下代码时: eventEmitter . emit ( 'start' ); 事件处理函数会被触发,且获得控制台日志。 可以通过将参数作为额外参数传给 emit() 来将参数传给事件处理程序: eventEmitter . on ( 'start' , number => { console . log ( `开始 ${ number } ` ); }); eventEmitter . emit ( 'start' , 23 ); 多个参数: eventEmitter . on ( 'start' , ( start , end ) => { console . log ( `从 ${ start } 到 ${ end } ` ); }); eventEmitter . emit ( 'start' ,

Node.js从零开始——HTTP 服务器

其实 Node.js 最初的目的,就是实现一个完全可以由 JavaScript 来进行开发的服务器端,所以归根到底,它的后端能力之一就是实现一个 HTTP 服务器,这里我们来看看它。 1 搭建 HTTP 服务器 其实前面我们已经看过了一个例子,不过这里再来看一个 HTTP web 服务器的例子: const http = require ( 'http' ); const port = 3000 ; const server = http . createServer (( req , res ) => { res . statusCode = 200 ; res . setHeader ( 'Content-Type' , 'text/plain' ); res . end ( '你好世界\n' ); }) server . listen ( port , () => { console . log ( `服务器运行在 http:// ${ hostname } : ${ port } /` ); }); 简要分析一下: 这里引入了 ref=" http:// nodejs.cn/api/http.html ">http 模块:使用该模块来创建 HTTP 服务器 服务器被设置为在指定的 3000 端口上进行监听, 当服务器就绪时,则 listen 回调函数会被调用 传入的回调函数会在每次接收到请求时被执行, 每当接收到新的请求时, "http://nodejs.cn/api/http.html#http_event_request">request 事件 会被调用,并提供两个对象:一个请求( http.IncomingMessage 对象)和一个响应( http.ServerResponse 对象) request 提供了请求的详细信息, 通过它可以访问请求头和请求的数据, response 用于构造要返回给客户端的数据;在此示例中: res . statusCode = 200 ; 设置 status

Web API从零开始——SVG

SVG 是我基本没有用过的知识块,所以这里也是边分享边学习,尽量在我自己理解的基础上来分享。 1 概念 SVG 是一种基于 XML 语法的图像格式,全称是可缩放矢量图(Scalable Vector Graphics);其他图像格式都是基于像素处理的, SVG 则是属于对图像的形状描述,所以它本质上是文本文件,体积较小,且不管放大多少倍都不会失真。 SVG 文件可以直接插入网页,成为 DOM 的一部分,然后用 JavaScript 和 CSS 进行操作。 上面是 SVG 代码直接插入网页的例子。 SVG 代码也可以写在一个独立文件中,然后用 、 、 、 等标签插入网页: < img src = "circle.svg" > < object id = "object" data = "circle.svg" type = "image/svg+xml" ></</span> object > < embed id = "embed" src = "icon.svg" type = "image/svg+xml" > < iframe id = "iframe" src = "icon.svg" ></</span> iframe > CSS 也可以使用 SVG 文件: . logo { background : url ( icon.svg ); } SVG 文件还可以转为 BASE64 编码,然后作为 Data URI 写入网页: < img src = "data:image/svg+xml;base64,[data]" > 2 语法 2.1 标签 我们可以把 SVG 代码都放在顶层标签 之中,下面是一个例子: < svg width = "100%" height = "100%" >