阅读 1328

你掌握了吗?——js数据类型隐式转换

js数据类型隐式转换

前言

众所周知javascript是一种弱类型语言。强类型和弱类型主要是站在变量类型处理的角度进行分类的。强类型是一旦指定数据类型,如果不经过强制转换,那么将永远是指定的这个类型。js中无法声明数据类型,变量类型是根据实际值决定的,由编译器自动调用转换函数进行转换,这种方式称之为隐式转换,今天我们就来谈谈数据类型是如何隐式转换的。

js数据类型

js数据类型共7种,包括6种基本数据类型,分别是Undefined、Null、String 、Number、Boolean、以及ES6新增的数据类型Symbol,一种复杂数据类型Object。

  • Undefined 只有一个值就是undefined,表示未经初始化的变量值
  • Null 只有一个值null,null值表示空对象指针
  • String 表示零个或多个16位的Unicode字符组成的字符序列
  • Number 包括整数和浮点数
  • Boolean 有两个字面值:true和false,表示一个逻辑实体
  • Symbol 每次创建的值都是唯一的,不能被强制转换
  • Object 复杂数据类型

js引擎内部实现类型转换的4个抽象操作

隐式类型转换是在一定场景下,js运行环境自动调用这几个方法,尝试转换成期望的数据类型

  • ToString(argument)
  • ToNumber(argument)
  • ToBoolean(argument)
  • ToPrimitive(input[ , PreferredType])

ToPrimitive(input[, PreferredType])

将input对象转成原始类型值,依赖valueOf()和toString()

PreferredType参数是Number,则ToPrimitive执行顺序:

  1. input本身是原始类型,返回input。
  2. 调用input.valueOf(),如果结果是原始类型,则返回这个结果。
  3. 调用input.toString(),如果结果是原始类型,则返回这个结果。
  4. 抛出TypeError异常。

PreferredType 参数是String,ToPrimitive执行顺序:

  1. input本身是原始类型,返回input。
  2. 调用input.toString(),如果结果是原始类型,则返回这个结果。
  3. 调用input.valueOf(),如果结果是原始类型,则返回这个结果。
  4. 抛出TypeError异常。

PreferredType没有传入参数

  • 如果input是内置的Date类型,PreferredType视为String
  • 否则PreferredType视为Number

ToBoolean(argument)

Argument Type Result
Undefined false
Null false
Boolean return argument
Number 仅当argument参数是 +0, -0, or NaN时,return false;否则return true
String 仅当argument参数是 空字符串时,return false;否则return true
Symbol true
Object true

ToNumber(argument)

Argument Type Result
Undefined NaN
Null +0
Boolean argument 为 true, return 1; argument 为 false, return 0
Number return argument参数
String 将字符串中的内容转化为数字(比如"23"->23),如果转化失败则返回NaN(比如"23a"->NaN)
Symbol 抛出 TypeError 异常
Object 先primValue = ToPrimitive(argument, Number),再对primValue使用ToNumber(primValue)

ToString(argument)

Argument Type Result
Undefined "undefined"
Null "null"
Boolean argument 为 true, return "true"; argument 为 false, return "false"
Number 用字符串表示数字
String 返回argument
Symbol 抛出 TypeError 异常
Object 先primValue = ToPrimitive(argument, Number),再对primValue使用ToString(primValue)

常见的隐式类型转换

转成String类型

  • 字符串连接符(+)转成字符串
var a = 123
var n = a + 'helloworld';
console.log(n)   // '123hellowold'

a = true
var m = a + 'helloworld'
console.log(m)   // 'truehelloworld'
复制代码

转成Number型

  • 自增自减运算符 ++/--
  • 加减乘除求余算数运算符 +-*/%
var a = '100'
var b = a--
var c = a/2
console.log(b) // 100
console.log(a) // 99
a+= ''
console.log(c) // 49.5

复制代码
  • 关系运算符 > < >= <= == != === !===
  1. 当关系运算符一边有字符串时,会将其数据类型使用Number转换,再做比较;
  2. 当两边都是字符串时,则都转成Number,注意:此时不是转成对应的数字,而是按照字符串对应的的unicode编码转成数字
  3. 多个字符从左往右进行比较
console.log('10' > 3) // true 先转成数字10再比较
console.log('3' > '10') // true

console.log('3'.charCodeAt()) // 51
console.log('10'.charCodeAt()) // 49

console.log('abc' > 'b') // false 先比较a和b,a和b不等,直接false
console.log('abc' > 'ade') // false,先比较aa,相等,继续比较db,得出结果
console.log('b'.charCodeAt()) // 98
console.log('d'.charCodeAt()) // 100

复制代码
  1. 特殊情况,没啥规则请记住以下结论
console.log(undefined == undefined) // true 
console.log(undefined === undefined) // true

console.log(undefined == null) // true undefined是从null派生出来的
console.log(undefined === null) // false

console.log(null == null) // true
console.log(null === null) // true

console.log(NaN == NaN) // false NaN与任何数据比较都是NaN

复制代码

转成Boolean型

数据在逻辑判断和逻辑运算之中会隐式转换为Boolean类型

  • Boolean转换参考上述ToBoolean(argument)说明, 以下这几种数据经过Boolean转换,会转成false,+0、-0、NaN、undefined、null、""、document.all(); 复杂数据类型经过Boolean转换后都是true,如:[]、{}
  • 逻辑非运算符! 逻辑非运算中,会将数据先做Boolean转换,然后取反
var a = undefined
console.log(!a) // true 先Boolean(a) => false; 再取反 !false => true

复制代码

进阶

字符串运算符与算术运算符

转换类型取决于,加号“+”两边的数据类型

  • 只要有一边是字符串则将非字符串的一边转成字符串
console.log(123 + 'true') // '123true'
复制代码
  • 符号两边有一边是Number型,此时+为算数运算符,则将令一边的数据转成Number型。此处注意空字符串、null以及布尔的false Number之后都是0
console.log(1 + true) // 2 先Number(true)=> 1,再做加计算,结果为2
console.log(1 + undefined) // 先Number(undefined) => NaN ,再计算,结果NaN
console.log(1 + null) // 先Number(null) => 0,再计算,结果为1

复制代码

复杂数据类型隐式转换

复杂数据类型隐式转换时会先调用自身的valueOf()和toString()两个函数,如果自身数据原型对象上没有相应的函数则会由原型链__proto__最终调用到Object.prototype对象对应的函数上,所有对象(除Null 和 undefined)都会继承这两个方法。

valueOf 返回这个对象逻辑上对应的原始类型的值,原始值是存储在栈(stack)中的简单数据段,原始类型就是前面说的基本数据类型。原始值是啥?请看这里原始值;valueOf是啥? 请看这里valueOf

toString 返回这个对象的字符串表示

  • 转换规则如前面所述,使用valueOf()获取原始值,如果原始值不是基本类型,则使用toString方法转成字符串
console.log([1,2] == '1,2') // true 解析如下

console.log([1,2].valueOf()) // [1,2],获取原始值
console.log([1,2].toString()) // '1,2',转成字符串,与右边数据相等

var a = {}
console.log(a == "[object Object]") // true

// 左边转换过程
console.log(a.valueOf()) // {}
console.log({}.toString()) // "[object Object]",再进行比较
复制代码

逻辑非隐式转换与关系运算符隐式转换

  • 逻辑非优先级高于关系符运算
console.log(![] == 0) // true 解析:空数组转换布尔型是true,取非后为falsefalse跟数字0比较,
布尔型被Number后为0,0 == 0

console.log([] == ![]) // true [].valueOf().toString()=>''; ![] => false 关系运算符将两边转成Number型进行比较,Number('') => 0; Number(false) => 0

console.log({} == !{}) // false 逻辑非优先级高,其实是{}和!{},这个逻辑表达式的比较,按照复杂类型隐式转换规则,需通过valueOf和toString转换后进行比较

复制代码
  • 引用数据类型的转化处理
    1. 引用数据类型,可称为对象类型,包括Object 、Array 、Function 、Date等;数据存在堆中,变量中存的是堆地址,我们只能操作存在栈内存的引用地址。
    2. var声明的一般是栈内存
    3. 6种基本数据类型的存储方式是值类型,存在于栈中
console.log([] == []) // false 数组为引用类型,在堆中存放的是两份不同的数据,所以比较结果不相等
console.log({} == {}) // false,同理,{}为引用类型,结果不相等

复制代码

总结

本文主要讲了以下几点:

  • 了解js数据类型和定义
  • 了解js内部数据类型转换操作
  • 关系运算符的转换
  • + 号连接操作数时的隐式转换规则
  • 复杂数据类型的转换,如何转成简单值
  • 逻辑非和引用数据类型的特殊类型转换

你掌握了js数据类型隐式转换的方法了吗

参考链接:

blog.csdn.net/itcast_cn/a… www.w3school.com.cn/js/pro_js_v… tc39.es/ecma262/

关于我们

快狗打车前端团队专注前端技术分享,定期推送高质量文章,欢迎关注点赞。

关注下面的标签,发现更多相似文章
评论