JavaScript 数据类型详解


Posted in Javascript onMarch 13, 2017

一,数据类型

以下内容基于ES5(ES6引入了一种新的原始数据类型Symbol,表示独一无二的值。它是JavaScript语言的第七种数据类型。)

JavaScript是一种弱类型动态语言,定义变量时无需指定类型,看似简单,但背后有繁琐的转换逻辑。让我们一起来看下js常见的数据类型和背后的隐式转换逻辑。

ES5中有5种简单的数据类型(也叫基本数据类型):number,string,boolean,null,undefined(null和undefined是两种特殊的基本数据类型,下面会讲到);还有一种复杂数据类型——Object(函数是一种特殊的对象,后面会讲到)

Undefined类型:

Undefined类型只有一个值,即特殊的undefined。在使用var声明变量但未对其加以初始化时,这个变量的值就是undefined,例如:

var message;
alert(message == undefined);//true

这个例子只声明了变量message,但未对其进行初始化。比较这个变量与undefined字面量,结果表明它们是相等的。这个例子与下面的例子是等价的:

var message = undefined;
alert(message == undefined);//true

这个例子是用undefined值显示初始化了变量message.但我们没有必要这么做,因为未经初始化的值默认都会取得undefined值。

(一般而言,不存在需要显示地把一个变量设置为undefined值的情况。字面值undefined的主要目的是用于比较,而ECMA-262第3版之前的版本中并没有规定这个值。第3版引入这个值是为了正式区分空对象指针与未经初始化的变量。)

不过,包含undefined值的变量与尚未定义的变量还是不一样的。请看下面的例子:

var message;//这个变量声明之后默认取得了undefined值
//下面这个变量并没有声明
//var age
alert(message);//'undefined'
alert(age);//产生错误 Uncaught ReferenceError: age is not defined(…)

运行以上代码,第一个警告框会显示变量message的值,即'undefined'。而第二个警告框由于传递给alert()函数的是尚未声明的变量age,则会导致一个错误。对于尚未声明过的变量,只能执行一项操作,即使用typeof操作符检测其数据类型。

然而,令人困惑的是:对未初始化的变量执行typeof操作符会返回undefined值,而对未声明的变量执行typeof操作符同样也会返回undefined值。来看下面的例子:

var message;//这个变量声明之后默认取得了undefined值
//下面这个变量并没有声明
//var age
alert(typeof message);//'undefined'
alert(typeof age);//'undefined'

结果表明,对未初始化和未声明的变量执行typeof操作符都返回了undefined值,这个结果有其逻辑上的合理性,因为虽然这两种变量从技术角度看有本质区别,但实际上无论对哪种变量也不可能执行真正的操作。

(即使未初始化的变量会自动被赋予undefined值,但我们仍然建议读者养成显式初始化变量-即在声明变量的同时给变量赋值的习惯。如果能够做到这一点,那么当typeof操作符返回undefined值时,我们就知道被检测的变量是还没有被声明的,而不是尚未初始化的了。)

Null类型

Null类型是第二个只有一个值的数据类型,这个特殊的值就是null。从逻辑角度来看,null值表示一个空对象指针,而这也正是typeof操作符检测null值会返回'Object'的原因,如下面的例子所示:

var car = null;
alert(typeof car);//'object'

如果定义的变量准备在将来用于保存对象,那么最好将该变量初始化为null而不是其他值。这样一来,只要直接检查null值就可以知道相应的变量是否已经保存了一个对象的引用了,如下面的例子所示:

if(car != null){
 //对car执行某些操作
}

实际上,undefined值是派生自null值的,因此ECMA-262规定对它们的相等性测试要返回true;

alert(null == undefined);//'true'

这里,位于null和undefined之间的相等操作符(==)总是返回true,不过要注意的是,这个操作符出于比较的目的会转换其操作数(后面会详细介绍相关内容)。

尽管null和udefined有这样的关系,但它们的用途完全不同。如前所述,无论在什么情况下,都没有必要把一个变量的值显式地设置为undefined,可是同样的规则对null却不适用。换句话说,只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存null值。这样做不仅可以体现null作为空对象指针的惯例,而且也有助于进一步区分null和undefined。

二,隐式转换

+和-

在js中,虽然我们不需要显式地定义变量的类型,但在实际的处理中,会根据不同的类型,会有不同的处理。先看几个例子:

var x = 'The answer is ' + 42;//"The answer is 42" 这里的'+'会理解为字符串拼接
var y = 42 + ' is the answer';//"42 is the answer" 这里的'+'会理解为字符串拼接
'37' + 7;//"377" 这里的'+'会理解为字符串拼接
'37' - 7;//30 这里的'-'会理解为减法运算

我们也可以巧用类型转换,去做一些事情,比如想把一个变量num转换为数字类型,非常简单的办法就是减去数字‘0',如果想把一个变量num变为字符串类型,那么可以加上一个空字符串''。

var num;
num = num - 0;
alert(typeof num);//"number"
num = num + '';
alert(typeof num);//"string"

===

严格等于a===b,首先会判断等号两边的类型,如果两边的类型不同,直接返回false,不再往下进行,如果类型相同,判断值是否想等。需注意NaN和任何东西比较都不想等,包括和自己比较也不想等。另外,JavaScript中的对象的比较是用引用去比较,而不是用值去比较,所以比较两个对象也不相等,因为不是两个完全相同的对象。可以定义变量x(不区分类型),让x和x比较,返回true。

'1.23' === '1.23';//true
null === null;//true
undefined == undefined;//true
null === undefined;//false
NaN === NaN;//false NaN属于number值,和任何东西比较都不想等,包括和自己比较也不想等
NaN == NaN;//false NaN属于number值,和任何东西比较都不想等,包括和自己比较也不想等
[1,2] == [1,2];//false 由于js中对象的比较是用引用去比较,虽然两边都是数组,而且长度一样、相同的值、相同的顺序,也是不等的,因为不是完全相同的对象。
new Object() == new Object();//false 引用比较,两个空对象是不同的两个对象,不相等。
var x;
x === x;//true 定义变量x,,让x和x比较 返回true

==

如果类型相同,比较方法同'===',如果类型不同,会尝试类型转换和比较:

null == undefined //相等
number == string //尝试把string转换成number再去比较
1.0 == '1.0';//true
boolean == ? //无论右边是什么,会先把boolean先转换成数字,true转换成1,false转换成0,然后再去和右边的比较 
true == 1; //true.
object == number | string //会尝试把对象转换为基本类型再去比较 其他的情况是false.
new String('hi') == 'hi';//true
new Boolean(false) == 0;//true

三,包装对象

number,string,boolean这三种基本类型都有对应的包装类型,先看一个例子:

JavaScript 数据类型详解

从上面的例子可以看出,js中当把一个基本类型(比如string类型)尝试以对象的方式去使用的时候,比如访问它的length属性,或者增加一些属性的时候,js会很智能地把被操作的基本类型转换成对应的包装类型对象,(相当于new String()),这个临时包装对象的内容和基本类型的值是一样的,当完成访问或者属性设置的时候,这个临时包装对象会被销毁掉,所以再去访问已经设置的属性,是访问不到的。number和boolean基本类型转换成包装类型对象的原理都是一样的。

var a = 'string';//定义变量a,赋值基本类型'string'
alert(a.length);//"6" 创建对应的临时包装对象,访问临时包装对象的length属性,得到结果6
a.t = 3;//3,设置成功后,临时对象被销毁,所以下面alert值是undefined
alert(a.t);//"undefined"
var b = 123;
b.toString();//"123" 调用对应临时包装对象Number()上的toString()方法,转换成字符串

四,类型检测

1,最常见的是用typeof操作符,会返回一个字符串,适合函数对象和基本类型的判断,遇到null失效,会返回Object。

typeof 100 //"number" 数值
typeof NaN; //"number" 数值
typeof Infinity;//"number" 数值
typeof true //"Boolean" 布尔值
typeof(undefined); //"undefined" 表示这个值未定义
typeof new Object(); //"object" 对象
typeof [1, 2]; //"object" 数组是对象,没有特殊处理
typeof null; //"object" null值表示一个空对象指针,所以返回Object
typeof function //"function" 从技术角度讲,函数在ECMAScript中是对象,不是一种数据类型,然而,函数也确实有一些特殊的属性,因此通过typeof操作符来区分函数和其他对象是有必要的

2,如果要判断对象类型,常用的是instanceof,适合自定义对象,也可以用来检测原生对象,在不同iframe和window间检测时失效,是基于原型链去判断,instanceof原理: 判断obj对象的原型链上是否有右边的构造函数的prototype属性,关于原型链,详见后面篇章。

obj instanceof Object(obj:必须是对象,如果是基本类型,直接会返回false;  Object:必须是函数对象,或者函数构造器,如果不是,就会抛出TypeError异常。)

看下简单的例子

new Object() instanceof Array === false //true
[1, 2] instanceof Array === true //true
[] instanceof Array===true//true

我们知道,任何一个构造函数,都有一个prototype对象属性,这个对象属性将用作使用new构造函数这种方式构造出的对象的原型。比如Person这个函数,函数有prototype属性. 我们用new Person()去创建Person实例的时候,这个对象实例就会有一个原型指向Person.prototype这个对象。我们用var bosn=new Student(),创建一个Student实例bosn,bosn的原型会指向它的构造器Student的prototype对象属性。检测bosn instanceof Person时,bosn.__proto__=Student.prototype,然后原型链会继续往上查找,bosn.__proto__.__proto__=person.prototype.就会返回true。注意,不同window或iframe间的对象类型检测不能使用instanceof!

JavaScript 数据类型详解

3,Object.prototype.toString()判断类型,适合内置对象和基本类型,遇到null和undefined失效,IE6/IE7/IE8返回'[object Object]'

Object.prototype.toString.apply([]);==='[object Array]';
Object.prototype.toString.apply(function(){});==='[object Function]';
Object.prototype.toString.apply(null);==='[object Null]';//IE6/IE7/IE8返回'[object Object]'
Object.prototype.toString.apply(undefined);==='[object Undefined]';//IE6/IE7/IE8返回'[object Object]'
Object.prototype.toString.apply('123');==="[object String]";
Object.prototype.toString.apply(123);==="[object Number]";
Object.prototype.toString.apply(true);==="[object Boolean]";
Object.prototype.toString.apply(String);==="[object Function]";
Object.prototype.toString.apply(Boolean);==="[object Function]"

4,constructor检测类型

任何一个对象都有一个constructor属性,继承自原型,会执向构造这个对象的构造函数, constructor可以被改写,使用时要小心。

5,duck type检测类型

比如我们不知道一个对象是否是数组,我们可以判断这个对象的length是否是数字,是否有join,push等数组的函数方法,通过特征判断对象是否属于某些类型,有时也会用到。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持三水点靠木!

Javascript 相关文章推荐
js中设置元素class的三种方法小结
Aug 28 Javascript
JS回调函数的应用简单实例
Sep 17 Javascript
仿淘宝TAB切换搜索框搜索切换的相关内容
Sep 21 Javascript
javascript相关事件的几个概念
May 21 Javascript
js性能优化技巧
Nov 29 Javascript
JS实现的跨浏览器解析XML文件实例
Jun 21 Javascript
jQuery多文件异步上传带进度条实例代码
Aug 16 Javascript
详解JSON Web Token 入门教程
Jul 30 Javascript
Vue中遍历数组的新方法实例详解
Jul 21 Javascript
js实现橱窗展示效果
Jan 11 Javascript
js实现简单的轮播图效果
Dec 13 Javascript
vue选项卡切换的实现案例
Apr 11 Vue.js
Java与JavaScript中判断两字符串是否相等的区别
Mar 13 #Javascript
Javascript中字符串相关常用的使用方法总结
Mar 13 #Javascript
利用Javascript裁剪图片并存储的简单实现
Mar 13 #Javascript
js实现手机发送验证码功能
Mar 13 #Javascript
Javascript封装id、class与元素选择器方法示例
Mar 13 #Javascript
原生js实现吸顶效果
Mar 13 #Javascript
vue2.0嵌套路由实现豆瓣电影分页功能(附demo)
Mar 13 #Javascript
You might like
php 代码优化之经典示例
2011/03/24 PHP
基于在生产环境中使用php性能测试工具xhprof的详解
2013/06/03 PHP
php使用qr生成二维码的示例分享
2014/01/20 PHP
使用Modello编写JavaScript类
2006/12/22 Javascript
鼠标移动到图片名上,显示图片的简单实例
2013/07/14 Javascript
js渐变显示渐变消失示例代码
2013/08/01 Javascript
JavaScript加强之自定义callback示例
2013/09/21 Javascript
jQuery探测位置的提示弹窗(toolTip box)详细解析
2013/11/14 Javascript
javascript框架设计读书笔记之模块加载系统
2014/12/02 Javascript
jquery.map()方法的使用详解
2015/07/09 Javascript
js和jQuery设置Opacity半透明 兼容IE6
2016/05/24 Javascript
简洁实用的BootStrap jQuery手风琴插件
2016/08/31 Javascript
bootstrap laydate日期组件使用详解
2017/01/04 Javascript
JS实现的简单图片切换功能示例【测试可用】
2017/02/14 Javascript
vue.js内部自定义指令与全局自定义指令的实现详解(利用directive)
2017/07/11 Javascript
bootstrap datetimepicker控件位置异常的解决方法
2017/11/23 Javascript
angularJS开发注意事项
2018/05/26 Javascript
微信小程序tabBar设置实例解析
2019/11/14 Javascript
vue使用nprogress实现进度条
2019/12/09 Javascript
[31:01]2014 DOTA2国际邀请赛中国区预选赛5.21 CNB VS Orenda
2014/05/23 DOTA
[41:11]完美世界DOTA2联赛PWL S2 Inki vs Magma 第一场 11.22
2020/11/24 DOTA
详解Python中的strftime()方法的使用
2015/05/22 Python
Python语言实现获取主机名根据端口杀死进程
2016/03/31 Python
批量将ppt转换为pdf的Python代码 只要27行!
2018/02/26 Python
pygame实现成语填空游戏
2019/10/29 Python
Python和Anaconda和Pycharm安装教程图文详解
2020/02/04 Python
Biblibili视频投稿接口分析并以Python实现自动投稿功能
2021/02/05 Python
台湾时尚彩瞳专门店:imeime
2019/08/16 全球购物
数学系毕业生的自我评价
2014/01/10 职场文书
大学优秀班主任事迹材料
2014/05/02 职场文书
大学生万能检讨书范例
2014/10/04 职场文书
2015年教师自我评价范文
2015/03/04 职场文书
2016年小学生新年寄语
2015/08/18 职场文书
MYSQL(电话号码,身份证)数据脱敏的实现
2021/05/28 MySQL
船舶调度指挥系统——助力智慧海事
2022/02/18 无线电
SQL bool盲注和时间盲注详解
2022/07/23 SQL Server