JavaScript中的强制类型转换规则
JavaScript中的类型从来都不是在定义的时候就确定的,而是在运行期间确定的
JavaScript中的强制类型转换总是返回
基本类型值
JavaScript中常见的转换就是向数字、字符串、布尔值进行强制类型转换
向字符串转换
三种方法:
toString
、String()
、+ ''
总结来讲就是null
、undefined
、true
、false
都会转换成对应的原始字符串,数字的话,所有数字类型都会以原始值的形式转换为字符串,包括NaN
、Infinity
、-Infinity
,但是对于-0
的话,转换为字符串并不会保留它的符号,转换后值为'0'
至于Symbol
的话,如果你尝试将它转换成为一个字符串类型的话,那你将会得到一个类型报错:
var symbol = Symbol()symbol += ''// Uncaught TypeError: Cannot convert a Symbol value to a string
这里看到,Symbol类型值是不允许类型转换的
对于普通的对象{}
来讲,除非有自行定义的toString
函数,否则toString
返回的是内部属性[[Class]]
的值,就像这样子的 ‘[object object]’ ,对象类型在向字符串转换时,会自动调用其内的toString
方法,如果找不到内部自己定义的toString
方法,便会顺着原型链向上找,也就是说,在没有自己指定toString
的时候,将一个对象转换成字符串的操作,调用的是Object.prototype.toString
,这里看其实就特别熟悉了,这就是我们常常用来检测一个变量的真实类型的方法:
function checkType(value) {return Object.prototype.toString.apply(value).split(' ')[1].split('').join('').replace(']', '').toLowerCase()
}checkType(1) // 'number'
checkType('') // 'string'
checkType({}) // 'object'
checkType([]) // 'array'
下面是默认对象toString
和自定义toString
对象默认toString
const obj = { name: 'young' }console.log(obj.toString()) // '[object object]'console.log(obj + 'Hello') // '[object object]Hello'
自定义toString
const obj = {name: 'young',toString: function () {return JSON.stringify(this)}
}/** 对象在转为字符串时自动调用其内的toString方法*/console.log(obj + '') // '{"name":"young"}'
数组这个特殊的对象类型它也定义了自己的toString
:
[1, 2, {}].toString() // '1,2,[object object]'
可以看到,数组的toString
方法对数据内每一个单元调用其toString
方法且以逗号进行分隔后返回
使用JSON字符串化
JSON.stringify()
常常用来进行对象的序列化
JSON.stringify()
对于基本类型值的效果和toString
是相同的,但是某些结果可能会和直接的toString
不相同,例如下面利用它去处理一个字符串类型的数据:
JSON.stringify('Hello World') // '"Hello World"'
结果是一个带着双引号的字符串,可见,JSON.stringify()返回的结果总是字符串,即使原本就是字符串,它也会将这个字符串使用引号包起来再返回
又例如:
JSON.stringify(NaN) // 'null'
JSON.stringify(Infinity) // 'null'
遇到数字类型且为NaN
、Infinity
,JSON.stringify()
会将它们处理成'null'
安全的JSON值与不安全的JSON值
安全
- Number
- String
- Null
- Boolean
不安全
- undefined
- function
- symbol
- 包含循环引用的对象
这里分别输出一下用 JSON.strinify() 处理这四个不安全的值会得出什么结果:
- undefined
JSON.stringify(undefined) // undefined
处理undefined
后得到的结果并不是一个字符串,还是undefined
- function
JSON.stringify(function () {}) // undefined
JSON.stringify(() => {}) // undefined
处理函数得到的结果也是undefined
,并不是预期的字符串
- symbol
JSON.stringify(Symbol()) // undefined
处理Symbol值得到的结果也是undefined
,也不是预期的字符串
- 包含循环引用的对象
先提一嘴,啥是 包含循环引用的对象,就是“你中有我,我中有你”,无限循环,这种对象是展开不完的,具体形式长这个样子:
一篇文章
const article = {title: '物种起源'
}
一个作者
const author = {name: 'Darwin'
}
现在指定文章所属为author,作者的作品为article
article.belong = authorauthor.work = article
接下来看看它变成什么样子了,拿author
举例:
不难发现这个对象永远展开不完,这就是循环引用的对象,接下来使用JSON.stringify()
来处理它试试:
JSON.stringify(author)
这里就报错了,所以它无法处理包含循环引用的对象
这几种危险类型值还有特殊的情况,它们不仅仅会被转为undefined
,在数组和对象中,它们有不同的表现:
JSON.stringify([undefined, funtion () {}, Symbol()]) // '[null,null,null]'JSON.stringif({a: undefined, b: function () {}, c: Symbol()}) // '{}'
值 | 单独处理结果 | 数组中 | 对象中 |
---|---|---|---|
undefined | undefined | null | 丢失 |
function | undefined | null | 丢失 |
Symbol | undefined | null | 丢失 |
循环引用对象 | Error | Error | Error |
所以若对象包含这4种情况的话,最好不要用JSON.stringify()
处理,否则无法出现预期的结果,影响程序的执行
JSON.stringify的中间层toJSON
如果对象中定义了toJSON
方法,用JSON.stringify()处理这个对象时就会首先调用toJSON
方法,用它的返回值来进行处理,这里的用处就是:
- 此方法定义了哪些值该被序列化
- 如果要对含有非法JSON值的对象来做字符串序列化,或是对象中某些值无法进行序列化,那么需要定义一个
toJSON
方法来返回安全的JSON值
就接着刚才的循环引用对象来继续,上面说到,我们因为循环引用而让JSON.stringify()
方法报错了:
const article = {title: '物种起源'
}const author = {name: 'Darwin'
}article.belong = author
author.work = article
但是我实在是想处理它,怎么办呢,这里通过toJSON
方法来中转它:
author.toJSON = function () {// 这里返回安全的JSON值,可以手动去掉循环引用对象return {name: this.name}
}JSON.stringify(author) // '{"name":"Drawin"}'
结果并没有报错,我通过toJSON
方法返回了一个对象,其内只包含了author的名字Darwin,类型为字符串,是一个安全的JSON值,所以就能够得到正确的处理结果
JSON.stringify的其它参数
在MDN能够看到,JSON.stringify()
的参数不止一个
JSON.stringify(value[, replacer [, space]])
后两个参数replacer、space为可选参数,意义如下:
- replacer
- 类型:
Array | Function
- 含义:指定对象序列化过程中哪些属性应该被处理,哪些应该被排除掉
- 用法:
// 需要排除掉id属性,分别用数组格式的参数和函数格式的参数来做 const person = {name: 'young',age: 21,city: 'GuangZhou',id: '123456' }JSON.stringify(person, ['name', 'age', 'city']) // '{"name":"young","age":21,"city":"GuangZhou"}'JSON.stringify(person, function (key, value) {if (key !== 'id') return value }) // '{"name":"young","age":21,"city":"GuangZhou"}'
两者得到了相同的处理结果,用数组格式的
replacer
时,传入的是一个字符串数组,每个元素为需要进行处理的属性名,如果不需要处理某个属性名,不写它就好 了;用函数格式的replacer
时,这个函数接收两个参数:key
和value
,第一个参数key表示对象的属性名,第二个参数value表示对象的属性值,被序列化的值的每个属性都会经过此函数的转换和处理。 - 类型:
- space
- 类型:
Number | String
- 含义:指定输出的缩进格式
- 用法:在space为
Number
类型(正整数)时,它表示了每级缩进的字符数;在space为字符串类型时,表示每一级缩进使用的字符,最长支持10位
const tree = {branch1: 12,branch2: 10,branch3: '4' }// replacer为null时,与不传的行为相同,序列化所有字段 JSON.stringify(tree, null, 2) // '{\n "branch1": 12,\n "branch2": 10,\n "branch3": "4"\n}'JSON.stringify(tree, null, '**') // '{\n**"branch1": 12,\n**"branch2": 10,\n**"branch3": "4"\n}'
- 类型:
向数字转换
三种方式
- * / %
、parseInt \ parseFloat
、Number
值类型 | 转换后 |
---|---|
undefined | NaN |
null | 0 |
true | 1 |
false | 0 |
'' 空字符串
|
0 |
Symbol | TypeError |
Number
使用函数Number()
来转换数字:如果Number
中传递的值是一个字符串的的话,且这个字符串包含非数字字符,那么Number便会返回NaN
parseInt
执行机制
与Number不同,parseInt的专精就是将字符串数据转换为数字。parseInt将第一个参数转换为字符串,对这个字符串进行解析,直到遇到第一个不能转换为数字的字符,返回一个整数或者NaN
,如果第一个字符就无法转换为数字,那么程序将返回NaN
。
但是+
和-
这两个字符虽然无法转换为数字,但是parseInt
能够识别它们并作为返回结果的依据,仅限它们在第一个字符时。
parseInt('-123') // -123
parseInt('+123') // 123
还有一个字符无法转换为数字,' '
空格,和+ -
一样,它也必须在字符串的头部才可以被parseInt识别,parseInt会忽略掉开头的所有空格。
parseInt(' 123') // '123'
参数
parseInt(string, radix)
- 第一个参数
string
为要处理的数据 - 第二个参数代表了按照几进制处理数据,也就是处理结果整数的基数,类型为
整数
,值为2到36
经常可以看到,parseInt处理的结果都是十进制的数,但是它并不是默认去以10为基数来处理数据的。如果处理字符串由'0x'
或0X
开头(不传 radix 的情况下),parseInt会猜想你的radix是16
,接下来就会以16为基数来处理数据;如果字符串以0
开头,我一开始以为它是会以8为基数来处理数据的,但是事实告诉我并不是这样:
parseInt('012') // 12
并没有像十六进制数('0X11')
那样猜想我们是想以8为基数来处理当前字符串,转而给了我们一个十进制的处理结果,所以这里可以先这样理解:如果没有传radix
时,对于0X
或0x
开头的字符串,parseInt会将其作为16进制数来处理,其它情况,parseInt都会采用radix = 10
的情况来处理字符串,最好还是在parseInt
的时候由我们手动指定radix的值。
对于那些非字符串的数据,parseInt首先会将它们先字符串化,再去进行操作,
如parseInt(false),先将false
转换为字符串为'false'
,接下来parseInt开始解析,遇到第一个字符,十进制数中并没有'f'
这个字符,故无法转换为十进制数,返回NaN
而当我们指定了16
为处理基数时(radix = 16)——parseInt(false, 16),那么接下来的操作就是:先将false
转换为字符串'false'
,然后parseInt以16为基数开始计算,首先遇到f
字符,
JavaScript中的强制类型转换规则相关推荐
- 为什么要在JavaScript中使用静态类型? (使用Flow进行静态打字的4部分入门)
by Preethi Kasireddy 通过Preethi Kasireddy 为什么要在JavaScript中使用静态类型? (使用Flow进行静态打字的4部分入门) (Why use stati ...
- JavaScript中的强制多态 | Lynda教程 中文字幕
JavaScript中的强制多态 | Lynda教程 中文字幕 Coercion in JavaScript 课程ID: 604262 时长: 3.3小时 所属类别:Javascript 学习如何利用 ...
- javascript优缺点_为什么要在JavaScript中使用静态类型? 优缺点
javascript优缺点 by Preethi Kasireddy 通过Preethi Kasireddy 为什么要在JavaScript中使用静态类型? 优缺点 (Why use static t ...
- 创建健壮的isArray()函数(JavaScript中判断对象类型的种种方法)
我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...
- 解析JavaScript中的字符串类型与字符编码支持
JavaScript中的字符串也像Python那样支持反斜杠的转移,并且字符集方面默认为Unicode,下面就来详细解析JavaScript中的字符串类型与字符编码支持 定义 字符串就是零个或多个排在 ...
- 为什么要在JavaScript中使用静态类型? 我们是否应该使用它们?
by Preethi Kasireddy 通过Preethi Kasireddy 为什么要在JavaScript中使用静态类型? 我们是否应该使用它们? (Why use static types i ...
- javascript中对变量类型的判断
在JavaScript中,有5种基本数据类型和1种复杂数据类型,基本数据类型有:Undefined,Null,Boolean, Number和String:复杂数据类型是Object,Object中还 ...
- javascript中对变量类型的推断
本文正式地址:http://www.xiabingbao.com/javascript/2015/07/04/javascript-type 在JavaScript中,有5种基本数据类型和1种复杂数据 ...
- javascript中的Date类型
1.JavaScript中的Date表示日期时间. 2.new Date()返回日期对象,是本地时间 3.Date.parse()接受一个时间字符串返回时间戳.也是本地时间,所以Date.parse( ...
最新文章
- 全球最大智能模型“悟道”首次落地:数字人+终端AI助手,支持NVIDIA GTX单卡机运行百亿大模型
- linux命令之cpio
- 基于WINCE6.0+S3C6410通过USB下载stepldr
- 使用puppeteer爬 EXTJS
- Python--读取csv文件的整列
- 可用等式为:html+java=jsp表示jsp[8]._java jsp
- js中null和undefined
- 解决javax.servlet.jsp.JspException cannot be resolved to a type
- 力扣133. 克隆图
- 模拟赛 10-14考试再次翻车记
- 新发布AlbumOnNet 、dotnetCharting控件注册资料
- django 1366, “Incorrect string value: for column ‘‘ at row
- 网站并发cpu占用率_来,控制一下 goroutine 的并发数量
- 她学术造假导致导师自杀,后将这段学术经历出书贩卖,一年收入上百万...
- Win10 VS2019+QT/OpenCV/灰点相机/函数信号发生器 配置及其使用
- 3dmax渲染是用云渲染好还是自己电脑渲染好?
- Oracle 考试题 答案
- 关于Value ‘0000-00-00 00:00:00‘ can not be represented as java.sql.Timestamp错误
- 【vscode 插件】为 markdown 文章标题自动添加多级序号
- 第10章两个独立样本的t检验