JS数据类型和转换

一、初识数据类型

1. 概要

JavaScript 语言的每一个值,都属于某一种数据类型。JavaScript 的数据类型,共有七种。

数值(number):整数和小数(比如1和3.14);

字符串(string):文本(比如Hello World);

布尔值(boolean):表示真伪的两个特殊值,即true(真)和false(假);

undefined:表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值;

null:表示空值,即此处的值为空;

对象(object):各种值组成的集合;

Symbol类型 :不介绍。

对象是最复杂的数据类型,又可以分成三个子类型。

狭义的对象(object)

数组(array)

函数(function)

2. typeof 运算符

由于ECMAScript是松散型,JavaScript 有三种方法,可以确定一个值到底是什么类型。

typeof运算符;

instanceof运算符;

Object.prototype.toString方法。

用typeof检测变量可能返回以下某个字符串。

image

null开始为Object类型的一个数据,后来独立为一种数据类型,为了兼容以前的代码,typeof null返回object就没法改变了。


二、数据类型详解

1. null 和 undefined

1.1 概述

null表示‘空值’,undefined表示‘未定义’。

1.2 用法和含义

null表示‘空值’,调用函数时,某个参数未设置任何值,这时就可以传入null,表示该参数为空。比如,某个函数接受引擎抛出的错误作为参数,如果运行过程中未出错,那么这个参数就会传入null,表示未发生错误。

undefined表示“未定义”,下面是返回undefined的典型场景。

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

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

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

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

2. 布尔值

布尔值代表“真”和“假”两个状态。“真”用关键字true表示,“假”用关键字false表示。

3. 数值

3.1 概述

i. 浮点数

JavaScript 语言的底层没有整数,所有数字都是以64位浮点数形式储存;所以,1与1.0是同一个数;某些运算只有整数才能完成,此时 JavaScript 会自动把64位浮点数,转成32位整数,然后再进行运算。

由于浮点数不是精确的值,所以涉及小数的比较和运算要特别小心。

0.1 + 0.2 === 0.3
// false

0.3 / 0.1
// 2.9999999999999996

(0.3 - 0.2) === (0.2 - 0.1)
// false

ii. 数值精度

根据国际标准 IEEE 754,JavaScript 浮点数的64个二进制位,从最左边开始,是这样组成的。

第1位:符号位,0表示正数,1表示负数;

第2位到第12位(共11位):指数部分;

第13位到第64位(共52位):小数部分(即有效数字)。

简单的法则就是,JavaScript 对15位的十进制数都可以精确处理。

iii. 数值范围

JavaScript 能够表示的数值范围为(21024,2-1023),超出这个范围的数无法表示。

如果一个数大于等于2的1024次方,那么就会发生“正向溢出”,即 JavaScript 无法表示这么大的数,这时就会返回Infinity。

如果一个数小于等于2的-1075次方(指数部分最小值-1023,再加上小数部分的52位),那么就会发生为“负向溢出”,即 JavaScript 无法表示这么小的数,这时会直接返回0。

var x = 0.5;

for(var i = 0; i < 25; i++) {
  x = x * x;
}

x // 0

3.2 普通数值

i. 普通数值的表示法有进制表示和科学计数

  • 科学计数法允许字母e或E的后面,跟着一个整数,表示这个数值的指数部分。
  • 进制表示有二进制、八进制、十进制、十六进制数值,前缀分别0B、0O、无前缀、0X,例如:0B10000、0O20、16、0X10为分别使用二、八、十、十六进制表示同一数值。

ii. 普通数值的自动转换

JavaScript 会自动将数值转为科学计数法表示。

  • 小数点后的零多于5个;
  • 小数点前的数字多于21位。

JavaScript 内部会自动将八进制、十六进制、二进制转为十进制,数字或字母不匹配进制将会报错。

ES5普通模式,在有前导0的数值会被视为八进制,但是如果前导0后面有数字8和9,则该数值被视为十进制。

3.3 特殊数值

i.正零和负零

正零和负零都会被当作正常的0,唯一有区别的场合是当+0或-0作为分母,如1 / +0,1 / -0,0 / 0 返回的值,分别得到+Infinity,-Infinity,NaN。

ii. NaN

  • 含义:NaN是数据类型属于Number的非数值;
  • 运算规则:NaN不等于任何值,包括它本身,NaN与任何数(包括它自己)的运算,得到的都是NaN。

iii. Infinity

由于数值正向溢出(overflow)、负向溢出(underflow)和被0除,JavaScript都不报错,而是返回Infinity,所以单纯的数学运算几乎没有可能抛出错误。

Infinity + Infinity // Infinity
Infinity * Infinity // Infinity
Infinity - Infinity // NaN
Infinity / Infinity // NaN

0 * Infinity // NaN
0 / Infinity // 0
Infinity / 0 // Infinity

null * Infinity // NaN
null / Infinity // 0
Infinity / null // Infinity

undefined + Infinity // NaN
undefined - Infinity // NaN
undefined * Infinity // NaN
undefined / Infinity // NaN
Infinity / undefined // NaN

Infinity大于一切数值(除了NaN),-Infinity小于一切数值(除了NaN),Infinity与NaN比较,总是返回false。

3.4 特殊数值判断方法

i. isNaN()

isNaN方法可以用来判断一个值是否为NaN,只对数值有效,如果传入其他值,会被Number函数先转成数值。

ii. isFinite()

除了Infinity、-Infinity、NaN和undefined这几个值会返回false,isFinite对于其他的数值都会返回true。

4. 字符串

4.1 概述

字符串就是零个或多个排在一起的字符,放在单引号或双引号之中,默认只能写在一行内,ES6中可使用反引号(``)替代单双引号,让字符串写在多行。

JavaScript 的单位字符长度固定为16位长度,只能以2个字节的UTF-16格式储存,所以处理的时候,JavaScript 返回的字符串长度可能是不正确的。

4.2 转义

需要用反斜杠转义的特殊字符,主要有下面这些,若前面加反斜杠没有特殊含义,反斜杠会被自动省略。

  • \0 :null(\u0000)
  • \b :后退键(\u0008)
  • \f :换页符(\u000C)
  • \n :换行符(\u000A)
  • \r :回车键(\u000D)
  • \t :制表符(\u0009)
  • \v :垂直制表符(\u000B)
  • \' :单引号(\u0027)
  • \" :双引号(\u0022)
  • \\ :反斜杠(\u005C)
  • \HHH (三个八进制数)
  • \xHH (两个十六进制数)
  • \uXXXX (四个八进制数)
console.log('1\n2')
// 1
// 2

'\a'
// "a"

'\172' === 'z' // true
'\x7A' === 'z' // true
'\u007A' === 'z' // true

4.2 字符串方法

  • 使用数组的方括号运算符,用来返回某个位置的字符(位置编号从0开始)
  • length属性返回字符串的长度
var s = 'hello';
s[0] // "h"

// 直接对字符串使用方括号运算符
'hello'[1] // "e"

s.length // 5

4.3 Base64 转码

文本里面包含一些不可打印的符号,比如 ASCII 码0到31的符号都无法打印出来,这时可以使用 Base64 编码,将它们转成可以打印的字符。另一个场景是,有时需要以文本格式传递二进制数据,那么也可以使用 Base64 编码。

所谓 Base64 就是一种编码方法,可以将任意值转成0~9、A~Z、a-z、+和/这64个字符组成的可打印字符。使用它的主要目的,不是为了加密,而是为了不出现特殊字符,简化程序的处理。

i. JavaScript 原生提供两个 Base64 相关的方法。

  • btoa():ASCII码字符转为 Base64 编码;
  • atob():Base64 编码转为原来的值。

ii. 非ASCII码字符转为Base64编码,必须中间插入一个转码环节。

function b64Encode(str) {
  return btoa(encodeURIComponent(str));
}

function b64Decode(str) {
  return decodeURIComponent(atob(str));
}

b64Encode('你好') // "JUU0JUJEJUEwJUU1JUE1JUJE"
b64Decode('JUU0JUJEJUEwJUU1JUE1JUJE') // "你好"

5. 对象

5.1 概述

通常,数值、字符串、布尔值这三种类型,合称为不能再细分的原始类型,对象类型往往是由多个原始类型的值的组成,可称为合成类型。

对象类型的组成部分的本质是无序键值对,‘键名’都是字符串,也称为属性,当为合法标识符时,则字符串引号可省略;‘键值’可以是任何数据类型,也可为函数。

5.2 表达式还是语句

如果没有圆括号,eval将其理解为一个代码块;加上圆括号以后,就理解成一个对象。

eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}

5.3 对象的引用

如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。

5.4 属性操作

i. 读取属性

  • 点运算符和方括号运算符读取对象属性,若方括号运算符内标识符无引号,则标识符表示一变量,而非字符串;

  • 查看一个对象本身的所有属性,可以使用Object.keys方法;

var obj = {
  key1: 1,
  key2: 2
};

Object.keys(obj);
// ['key1', 'key2']
  • for...in循环用来遍历一个对象的全部属性。

它遍历的是对象所有可遍历(enumerable)的属性,会跳过不可遍历的属性。

它不仅遍历对象自身的属性,还遍历继承的属性。

var obj = {a: 1, b: 2, c: 3};

for (var i in obj) {
  console.log(obj[i]);
}
// 1
// 2
// 3
  • in运算符,用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true,否则返回false。

ii. 增加属性

允许属性的“后绑定”,使用点运算符和方括号运算符来读取“后绑定”对象属性。

iii. 删除属性

delete命令用于删除对象的属性,删除成功后返回true。


三、数据转换

1. 强制转换

1.1 Number()、parseInt()、parseFloat()

i. 原始类型值

对于Number(),数值和字符串整体转换为数值,基本上只要有一个字符无法转成数值,整个字符串就会被转为NaN。布尔值true和false转换为1和0,undefined和null转换为NaN和0,

对于parseInt(),将参数(不能识别符合科学计数法字符串)转为字符串,返回字符串有效位的整数,无有效位返回NaN。

parseInt(字符串,进制)

  • 字符串的进制由进制参数和字符串首位决定,进制参数会被自动转为一个整数(2到36之间),进制参数是0、undefined和null,则直接忽略,返回该值对应的十进制数,字符串首位是OX,则默认进制参数为十六进制,O为首字符串参数,0将会被忽略,则默认进制参数为十进制;
  • 如果字符串包含对于指定进制无意义的字符,则从最高位开始,只返回可以转换的数值。如果最高位无法转换,则直接返回NaN;

对于parseFloat(),将参数(能识别符合科学计数法字符串)转为字符串,返回字符串有效位的小数,无有效位返回NaN;

parseInt,parseFloat和Number函数都会自动过滤一个字符串前导和后缀的空格。

parseInt('\t\v\r12.34\n') // 12
Number('\t\v\r12.34\n') // 12.34

对于布尔值、null和undefined的转换值区别如下。

数值转换 true false null undefined
Number() 1 0 0 NaN
parseInt() NaN NaN NaN NaN
parseFloat() NaN NAN NaN NaN

ii. 对象

Number()、parseInt()、parseFloat()会将对象转换为原始数据类型,再使用Number函数将原始数据类型转为数值。

对象转换为原始数据类型过程具体为先调用对象自身的valueOf方法,使对象能返回原始类型的值,否则改为调用对象自身的toString方法,返回原始类型的值,如果toString方法返回的还是对象,就报错。

1.2 String()、toString()

i. 原始类型的值

String()函数和toString()方法功能范围:

  • 数值:转为相应的字符串,额外地,toString()方法可传入二、八、十六数值或字符串的进制参数;

  • 字符串:转换后还是原来的值;

  • 布尔值:true转为字符串"true",false转为字符串"false";

  • undefined:String()函数转为字符串"undefined",但无toString()方法;

  • null:String()函数转为字符串"null",但无toString()方法。

ii. 对象

String()会将对象转换为原始类型的值,和Number()相反,String()先调用toString,后调用valueOf。

String({a: 1}) // "[object Object]"
String([1, 2, 3]) // "1,2,3"

1.3 Boolean()

除了undefined,null,false,0,NaN,""或''(空字符串)六个值被转为false,其他都是true,包括空数组([])和空对象({})。

2. 自动转换

自动转换的规则是:预期是布尔值、数值、字符串的地方,会分别自动调用Boolean、Number和String函数进行转换。

2.1 自动转换为布尔值

i. 下列运算符会返回布尔值;

两元逻辑运算符: && (And),|| (Or);

前置逻辑运算符: ! (Not),!!(等价Boolean());

相等运算符:===,!==,==,!=;

比较运算符:>,>=,<,<=。

ii. 程序流程的控制里,判断条件会自动会返回布尔值。

if ([]) {
  console.log('true');
}
// true

if ({}) {
  console.log('true');
}
// true

2.2 自动转换为字符串

主要发生在字符串的加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。

2.3 自动转换为数值

除了加法运算符(+)有可能把运算子转为字符串,其他运算符都会把两侧运算子自动转成数值。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,948评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,371评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,490评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,521评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,627评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,842评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,997评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,741评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,203评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,534评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,673评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,339评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,955评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,770评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,000评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,394评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,562评论 2 349

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,132评论 0 13
  • 运算符是处理数据的基本方法,用来从现有的值得到新的值。JavaScript 提供了多种运算符,本章逐一介绍这些运算...
    许先生__阅读 598评论 0 3
  • 教程 https://wangdoc.com/javascript/types/general.html 1 概述...
    智勇双全的小六阅读 572评论 0 0
  • 运算符是处理数据的基本方法,用来从现有的值得到新的值。JavaScript 提供了多种运算符,本章逐一介绍这些运算...
    徵羽kid阅读 667评论 0 0
  • Git "C:\Program Files\Git\etc\bash.bashrc"中添加export LESSC...
    Giru阅读 326评论 0 0