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 相关文章推荐
W3C Group的JavaScript1.8 新特性介绍
May 19 Javascript
JS遮罩层效果 兼容ie firefox jQuery遮罩层
Jul 26 Javascript
Jquery公告滚动+AJAX后台得到数据
Apr 14 Javascript
jQuery对表单元素的取值和赋值操作代码
May 19 Javascript
利用js读取动态网站从服务器端返回的数据
Feb 10 Javascript
通过js为元素添加多项样式,浏览器全兼容写法
Aug 30 Javascript
Jqprint实现页面打印
Jan 06 Javascript
如何快速上手Vuex
Feb 14 Javascript
webpack vue项目开发环境局域网访问方法
Mar 20 Javascript
JS实现的input选择图片本地预览功能示例
Aug 29 Javascript
vue中改变滚动条样式的方法
Mar 03 Javascript
vue添加自定义右键菜单的完整实例
Dec 08 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转换文件夹下所有文件编码的实现代码
2013/06/06 PHP
删除PHP数组中的重复元素的实现代码
2017/04/10 PHP
脚本收藏iframe
2006/07/21 Javascript
javascript读取RSS数据
2007/01/20 Javascript
通过修改referer下载文件的方法
2008/05/11 Javascript
Js 本页面传值实现代码
2009/05/17 Javascript
一个获取第n个元素节点的js函数
2014/09/02 Javascript
分享33个jQuery与CSS3实现的绚丽鼠标悬停效果
2014/12/15 Javascript
javascript多行字符串的简单实现方式
2015/05/04 Javascript
js中flexible.js实现淘宝弹性布局方案
2020/06/23 Javascript
VUEJS实战之构建基础并渲染出列表(1)
2016/06/13 Javascript
JS中的hasOwnProperty()、propertyIsEnumerable()和isPrototypeOf()
2016/08/11 Javascript
jquery根据td给相同tr下其他td赋值的实现方法
2016/10/05 Javascript
Angular2搜索和重置按钮过场动画
2017/05/24 Javascript
JavaScript该如何学习 怎样轻松学习JavaScript
2017/06/12 Javascript
jsTree事件和交互以及插件plugins详解
2017/08/29 Javascript
基于JavaScript表单脚本(详解)
2017/10/18 Javascript
Three.js基础学习教程
2017/11/16 Javascript
详解AngularJS之$window窗口对象
2018/01/17 Javascript
NodeJs 实现简单WebSocket即时通讯的示例代码
2019/08/05 NodeJs
简单使用webpack打包文件的实现
2019/10/29 Javascript
详解Python的Django框架中inclusion_tag的使用
2015/07/21 Python
Python基于回溯法子集树模板解决找零问题示例
2017/09/11 Python
pandas使用apply多列生成一列数据的实例
2018/11/28 Python
使用python绘制二元函数图像的实例
2019/02/12 Python
python高斯分布概率密度函数的使用详解
2019/07/10 Python
python根据时间获取周数代码实例
2019/09/30 Python
python pandas dataframe 去重函数的具体使用
2020/07/20 Python
python简单利用字典破解zip文件口令
2020/09/07 Python
浅谈html5 video 移动端填坑记
2018/01/15 HTML / CSS
如何写好升职自荐信
2014/01/06 职场文书
社团招新策划书
2014/02/04 职场文书
户外活动总结
2015/02/04 职场文书
无锡灵山大佛导游词
2015/02/09 职场文书
基层组织建设年活动总结
2015/05/09 职场文书
Python pyecharts案例超市4年数据可视化分析
2022/08/14 Python