JavaScript 数据类型浅析

概述

JavaScript有六种简单的数据类型和一种较复杂的数据类型。简单数据类型有:Undefined、Null、Boolean、Number、String、Symbol (ECMAScript 6 新定义),复杂类型Object,可进一步细分为Array、function、Date等。

Undefined

Undefined只有一个值,使用var声明变量但不给这个变量赋值,或者既没有声明也没有初始化,那么这个变量的类型就是Undefined,前者默认初始值是Undefined,后者没有默认初始值。

Null

Null是第二个只有一个值的类型,null值表示的是一个空对象指针,因此在使用typeof检测时会返回object。

Boolean

Boolean有两个字面值true、false,但这两个值不一定就等于1、0,JavaScript里面所有类型的值都有与Boolean值等价的值,调用Boolean()即可转化一个值为Boolean类型。转化规则如下:

transform

Number

Number用来表示整数和浮点数值,还有一种特殊数值:NaN(not a number非数值),js中任何数值除以0会返回NaN(但测试显示只有0/0为NaN,其它为Infinity无穷大),不会像其他语言那样报错停止代码执行。

NaN有两个重要的特点:任何涉及到NaN的操作都会返回NaN(eg:NaN/2返回NaN),NaN与任何值都不相等,包括与其本身,NaN==NaN 返回false。isNaN()可以判断值是否“不是数值”,他会尝试将测试值转变为数值:

isNaN(NaN);    //true    
isNaN(10);    //false(10是一个数值)    
isNaN("10");    //false(可能被转换为数值10)    
isNaN("blue");    //true(不能被转换为数值)    
isNaN(true);    //false(可能被转换为数值1)     

数值转换:Number()可用于任何类型转换为number;parseInt()、parseFloat()用于字符串转换为number;不能转换返回NaN。

parseInt()函数在转换字符串时,它会忽略字符串前面的空格,直至找到第一个非空格字符。如果第一个字符串不是数字字符或者负号,parseInt()会返回NaN;如果第一个字符是数字字符,praseInt()会继续解析第二个字符,直到解析完所有后续字符或者遇到了一个非数字字符。例如,"1234blue"会被转换为1234,”22.5“会被转换为22,因为小数点并不是有效的数字字符。 parseInt()也能够识别出各种整数格式(即十进制、八进制、十六进制)。可设置两个参数

 parseInt("解析值",2);//按二进制解析    

parseFloat()也是从第一个字符(位置0)开始解析每个字符,一直解析到字符串末尾或者解析到遇见一个无效的浮点数字字符为止。也就是说,字符串中的第一个小数点是有效的,而第二个小数点就是无效的了,它后面的字符串将被忽略。例如,”22.34.5“将会被转换成22.34。parseFloat()和parseInt()的另一个区别在于它始终都会忽略前导的零,且只解析十进制值,没有第二个参数。

parseInt("3.345");  //  3
parseInt("AF");       //56(八进制)
parseFloat("3.345");    //3.345   
parseFloat("0xA");        //0

String

String表示字符串,0个或多个字符组成,用''或""表示。可使用.length获取字符串长度。
将一个值转换成String类型有两个方法,toString()和String(),前者对Undefined、null类型不适用,后者均可用。

toString()一般不传参数,默认10,表示十进制,若果传递toString(2),表示二进制,以此类推。

Symbols符号类型

符号(Symbols)是ECMAScript 第6版新定义的。符号类型是唯一的并且是不可修改的, 并且也可以用来作为Object的key的值。 在某些语言当中也有类似的原子类型(Atoms),可以认为为它们是C里面的枚举类型。

Object

Object是一组数据和功能的集合。在计算机科学中,对象是指内存中的可以被标识符引用的一块区域。实例化对象的过程有两种,一是通过new操作符,二是通过对象字面量表示法。

第一种:使用new操作符后跟Object()构造函数,示例:

var person = new Object();
person.name = "Nicholas";
person.age = 29;

第二种:使用对象字面量表示法。对象字面量是对象定义的一种简写形式,目的在于简化创建包含大量属性的对象的过程,属性名也可以使用字符串"name":"nick"。这种语法要求的代码量少,而且能够给人封装数据的感觉,更推崇。例:

var person = {
    name : "Nicholas",
    age : 29
}

obj只是引用类型,是堆内存中一个对象的别称,本身并不占用内存。实例化对象地址存到栈内存中,然后通过地址访问堆内存。js中,函数的参数都是值传递的,而对于js内的引用类型,其值默认为栈内存中的地址。

Object的每个实例常见属性和方法:

  • constructor——保存着用于创建当前对象的函数
  • hasOwnProperty(propertyName)——用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例如:o.hasOwnProperty("name"))
  • isPrototypeOf(object)——用于检查传入的对象是否是另一个对象的原型
  • propertyIsEnumerable(propertyName)——用于检查给定的属性是否能够使用for-in语句来枚举
  • toString()——返回对象的字符串表示
  • valueOf()——返回对象的字符串、数值或布尔值表示。通常与toString()方法的返回值相同。

数据类型的判断

typeof

typeof是平常用的检测变量类型方法,但是arr, json, null, date, reg, error类型均会被检测为object类型,其他类型能够精确的检测。使用方法:typeof 变量名;输出类型。

var num = 3;       
typeof num; //number

instance

instanceof 运算符与 typeof 运算符相似,用于识别正在处理的对象的类型。与 typeof 方法不同的是,instanceof 方法要求开发者明确地确认对象为某特定类型。使用方法:变量名 instanceof 特定类型名。返回true、false。能检测出多层继承的关系。

function Person(){

}
function Student(){

}
Student.prototype = new Person();
var John = new Student();
console.log(John instanceof Student); // true
console.log(John instancdof Person);  // true   

普通声明num, str和bool不能检测出他的类型,只有以var num = new Number(123);这种方式声明的才可以检测出。此外,undefined和null是检测不成Object类型的,所以检测前需要先判断是否是undefined和null。

constructor

使用instanceof检测变量类型时,检测不到number, string, bool的类型。constructor本来是原型对象上的属性,指向构造函数。但是根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。除了undefined和null,其他类型的变量均能使用constructor判断出类型。 使用方法:变量名.constructor==特定类型名。返回true、false。

// undefined和null没有constructor属性
console.log(
    Tom.constructor==Person,
    num.constructor==Number,
    str.constructor==String,
    bool.constructor==Boolean,
    arr.constructor==Array,
    json.constructor==Object,
    func.constructor==Function,
    date.constructor==Date,
    reg.constructor==RegExp,
    error.constructor==Error
);
// 所有结果均为true

但constructor属性是可以被修改的,会导致检测出的结果不正确。

function Person(){

}
function Student(){

}
Student.prototype = new Person();
var John = new Student();
console.log(John.constructor==Student); // false
console.log(John.constructor==Person);  // true

Object.prototype.toString.call

Object.prototype.toString.call(变量)输出的是一个字符串,

console.log(
    Object.prototype.toString.call(num),// '[object Number]'
    Object.prototype.toString.call(str),// '[object String]'
    Object.prototype.toString.call(bool),// '[object Boolean]'
    Object.prototype.toString.call(arr),// '[object Array]'
    Object.prototype.toString.call(json),// '[object Object]'
    Object.prototype.toString.call(func),// '[object Function]'
    Object.prototype.toString.call(und),// '[object Undefined]'
    Object.prototype.toString.call(nul),// '[object Null]'
    Object.prototype.toString.call(date),// '[object Date]'
    Object.prototype.toString.call(reg),// '[object RegExp]'
    Object.prototype.toString.call(error)// '[object Error]'
);

字符串里有一个数组,第一个参数是Object,第二个参数就是这个变量的类型,而且,所有变量的类型都检测出来了,我们只需要取出第二个参数即可。或者可以使用Object.prototype.toString.call(arr)=="object Array"来检测变量arr是不是数组。

他是怎么检测变量类型的:

  1. 首先,取得对象的一个内部属性[[Class]],
  2. 然后依据这个属性,返回一个类似于”[object Array]”的字符串作为结果([[]]用来表示语言内部用到的、外部不可直接访问的属性,称为“内部属性”)。
  3. 利用这个方法,再配合call,我们可以取得任何对象的内部属性[[Class]],然后把类型检测转化为字符串比较,以达到我们的目的。

jquery中$.type

使用方法:$.type(变量名)。返回类型名,如:number string boolean。

$.type方法的实现,实质上就是综合typeof和Object.prototype.toString.call两种方式:

// 实例对象是能直接使用原型链上的方法的
var class2type = {};
var toString = class2type.toString;

// 省略部分代码...

type: function( obj ) {
    if ( obj == null ) {
    // 若传入的是null或undefined,则直接返回这个对象的字符串
    // 即若传入的对象obj是undefined,则返回"undefined"
        return obj + "";
    }
    
    // 若使用typeof检测出的obj类型是object或function,则返回class2type的值,否则返回typeof检测的类型
    return (typeof obj === "object" || typeof obj === "function") ?
        (class2type[ toString.call(obj) ] || "object") :
        typeof obj;
},

// 省略部分代码... 

// Populate the class2type map
jQuery.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) {
    class2type[ "[object " + name + "]" ] = name.toLowerCase();
});

区分 Undefined 和 Null

相似点

将一个变量赋值为undefined或null,几乎没区别。undefined和null在if语句中,都会被自动转为false,相等运算符甚至直接报告两者相等。他们都是完全不可变的,没有属性和方法,也不能给其属性赋值。使用相等操作符( == )比较这两个值和其他false值,他们并不等于除了自己:

null == 0; // false
undefined == ""; // false
null == false; // false
undefined == false; // false
null == undefined; // true
undefined === null; // false,类型不同

差异

null是一个表示"无"的对象,转为数值时为0;undefined是一个表示"无"的原始值,转为数值时都为NaN。换句话说,null表示"没有对象",即该处不应该有值。undefined表示"缺少值",就是此处应该有一个值,但是还没有定义。

null

通常用作一个空引用一个空对象的预期,就像一个占位符。

  • DOM,它是独立于语言的,不属于ECMAScript规范的范围。因为它是一个外部API,试图获取一个不存在的元素返回一个null值,而不是undefined。
  • 如果你需要给一个变量或属性指定一个不变值,将它传递给一个函数,或者从一个函数返回null,null几乎是最好的选择。
  • object= null,通过分配null值,有效地清除引用,并假设对象没有引用其他代码,指定垃圾收集,确保回收内存。

undefined

var i;
i // undefined

function f(x){console.log(x)}
f() // undefined

var  o = new Object();
o.p // undefined

var x = f();
x // undefined
  • 变量被声明了,但没有赋值时,就等于undefined。
  • 调用函数时,应该提供的参数没有提供,该参数等于undefined。
  • 对象没有赋值的属性,该属性的值为undefined。
  • 函数没有返回值时,默认返回undefined。
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,406评论 6 503
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,732评论 3 393
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,711评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,380评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,432评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,301评论 1 301
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,145评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,008评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,443评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,649评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,795评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,501评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,119评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,731评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,865评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,899评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,724评论 2 354

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,148评论 0 13
  • 第3章 基本概念 3.1 语法 3.2 关键字和保留字 3.3 变量 3.4 数据类型 5种简单数据类型:Unde...
    RickCole阅读 5,124评论 0 21
  • 第1章 JavaScript 简介 JavaScript 具备与浏览器窗口及其内容等几乎所有方面交互的能力。 欧洲...
    力气强阅读 1,129评论 0 0
  •   引用类型的值(对象)是引用类型的一个实例。   在 ECMAscript 中,引用类型是一种数据结构,用于将数...
    霜天晓阅读 1,054评论 0 1
  • 西伯利亚遥远的寒流, 让我不再树影婆娑, 曾经的涟漪, 而今 近乎干涸; 蜿蜒南下, 应该是命运的因果, 两岸的风...
    王呲花阅读 421评论 0 3