类型转换在各个语言中都存在,而在 JavaScript 中由于缺乏对其的了解而不慎在使用中经常造成bug被人诟病。为了避免某些场景下的意外,甚至推崇直接使用 Strict Equality( === )来代替 ==。这确实能避免很多bug,但更是一种对语言不理解的逃避(个人观点)。
先抛出在 You Don’t Know JavaScript (中) 看到的一个例子
[] == [] // false
[] == ![] // true
{} == !{} // false
{} == {} // false
是不是很奇怪?本文将从书中看到的知识与规范相结合,来详细说明一下JavaScript在类型转换时候发生的故事。
很多人喜欢说显示类型转换与隐式类型转换,但个人感觉只是说法上的不同,实质都在发生了类型转换而已,故不想去区分他们了(感觉一万个人有一万种说法)
仅在6大基本类型 null undefined number boolean string object 作讨论 symbol未考虑
var a = String(1)
var b = Number('1')
var c = 1 + ''
var d = +'1'
a,b直接调用了原生函数,发生了类型转换。c,d使用了+运算符的一些规则,发生了类型转换。这些是很简单的也是我们常用的。
其实真正起作用的,是语言内部对规范中抽象操作的实现,接下来我们所说的 ToString, ToNumber, ToBoolean等都是抽象操作,而不是JS里对应的内置函数
按照以下规则转化被传递的参数
Argument Type | Result |
---|---|
Undefined | “undefined” |
Null | “null” |
Boolean | true -> “true” false – > “false” |
Number | NaN -> “NaN” +0 -0 -> “0” -1 -> “-1” infinity -> “Infinity” 较大的数科学计数法 (详见规范9.8.1) |
String | 不转换 直接返回 |
Object | 1. 调用ToPrimitive抽象操作, hint 为 String 将返回值作为 value 2. 返回ToString(value) |
String(undefined) // "undefined"
String(null) // "null"
String(true) // "true"
ToPrimitive 抽象操作下面会提及
按照以下规则转换被传递参数
Argument Type | Result |
---|---|
Undefined | NaN |
Null | +0 |
Boolean | true -> 1 false -> +0 |
Number | 直接返回 |
String | 如果不是一个字符串型数字,则返回NaN(具体规则见规范9.3.1) |
Object | 1. 调用ToPrimitive抽象操作, hint 为 Number 将返回值作为 value 2. 返回ToNumber(value) |
按照以下规则转换被传递参数
Argument Type | Result |
---|---|
Undefined | false |
Null | false |
Boolean | 直接返回 |
Number | +0 -0 NaN -> false 其他为true |
String | 空字符串(length为0) -> false 其他为true |
Object | true |
顾名思义,该抽象操作定义了该如何将值转为基础类型(非对象),接受2个参数,第一个必填的要转换的值,第二个为可选的hint,暗示被转换的类型。
按照以下规则转换被传递参数
Argument Type | Result |
---|---|
Undefined | 直接返回 |
Null | 直接返回 |
Boolean | 直接返回 |
Number | 直接返回 |
String | 直接返回 |
Object | 返回一个对象的默认值。一个对象的默认值是通过调用该对象的内部方法[[DefaultValue]]来获取的,同时传递可选参数hint。 |
var a = {}
a.toString = function () {return 1}
a.valueOf = function () {return 2}
String(a) // "1"
Number(a) // 2
a + '' // "2" ???????
+a // 2
a.toString = null
String(a) // "2"
a.valueOf = null
String(a) // Uncaught TypeError: balabala
似乎我们发现了一个很不合规范的返回值,为什么 a + ''不应该返回”1″吗
基础概念已经了解了,那么在 == 中到底发生了什么样的类型转换,而导致了经常产生出乎意料的bug,导致了它臭名昭著。
x == y 判断规则如下:
[] == [] // false
// 1. 两遍类型都为 Object,比较引用地址,不同返回false 搞定
[] == ![] // true
// 1. ![]强制类型转换 变为 [] == false
// 2. 根据规范第7条,返回 [] == ToNumber(false), 即 [] == 0
// 3. 根据规范第9条,返回ToPromitive([]) == 0,数组的valueOf为本身,不是原始值,则返回toString()即 "" == 0
// 4. 根据规范第5条,返回ToNumber("") == 0, 即 0 == 0
// 5. 根据规范第1条,返回 true
// 下面的不赘述了,分析类似上面
{} == !{} // false
{} == {} // false
我们不难看出以下几点
引用 << 你不知道的JS(中) >> 中的2句话
如果两遍的值中有 true 或者 false , 千万不要使用 == (会被转为数字0,1来进行判断,会出现一些意外的情况)如果两遍的值中有[]、””或者0,尽量不要使用 ==
先来看看这个例子
var a = { b: 42 }
var b = { b: 43 }
a < b // false
a == b // false
a > b // false
a <= b // true
a >= b // true
是不是感觉到世界又崩塌了???
让我们来仔细分析一下
var a = { b: 42 }
var b = { b: 43 }
a < b // false
// 1. 两遍调用ToPrimitive, 返回[object Object] 两遍一致 返回 false
a == b // false
// 两遍不同的引用,返回false
a > b // false
// 同 a < b
a <= b // true
// 按规范其实是处理成 !(a > b) 所以为true
a >= b // true
所以在不相等比较的时候,我们最后还是进行手动的类型转换较为安全
深入了解类型转换的规则,我们就可以很容易取其精华去其糟粕,写出更安全也更简洁可读的代码
在JavaScript中存在这样两种原始类型:Null与Undefined。这两种类型常常会使JavaScript的开发人员产生疑惑,在什么时候是Null,什么时候又是Undefined?Undefined类型只有一个值,即undefined。当声明的变量还未被初始化时,变量的默认值为undefined。
主要介绍了JS中检测数据类型的几种方式,typeof运算符用于判断对象的类型,但是对于一些创建的对象,它们都会返回\'object\',有时我们需要判断该实例是否为某个对象的实例,那么这个时候需要用到instanceof运算符
对于object和number、string、boolean之间的转换关系,ToPrimitive是指转换为js内部的原始值,如果是非原始值则转为原始值,调用valueOf()和toString()来实现。
Undefined类型表示未定义,它的类型只有一个值为undefined。undefined和null有一定的表意差别。非整数的Number类型无法使用 == 或 === 来比较,因为 JS 是弱类型语言,所以类型转换发生非常频繁
近在做项目代码重构,其中有一个要求是为代码添加智能提示和类型检查。智能提示,英文为 IntelliSense,能为开发者提供代码智能补全、悬浮提示、跳转定义等功能,帮助其正确并且快速完成编码。
基本类型:按值访问,可以操作保存在变量中实际的值;引用类型数据存在堆内存,而引用存在栈区,也就是说引用类型同时保存在栈区和堆区,关于==的执行机制,ECMASript有规范,因为==前后的值交换顺序,返回的值也是一样的,所以在此对规范做出如下总结
JavaScript 是一种弱类型或者说动态类型语言。所以你不用提前声明变量的类型,在程序运行时,类型会被自动确定,你也可以使用同一个变量保存不同类型的数据。
js的值传递和引用(地址)传递:js的5种基本数据类型 number,string,null,undefined,boolean 在赋值传递时是值传递,js的引用数据类型(object,array,function)进行引用传递,其实底层都是对象。
JS中所有的值都可以转换成布尔类型 使用Boolean()或者 !!(两个感叹号),JS中所有的值都可以转换成数字类型,使用Number()或+。数字类型转换场景目的只有一个,用于计算,将后台传递的数据,从字符串转换为数字并参与计算
众所周知,JS在很多情况下会进行强制类型转换,其中,最常见两种是:1.使用非严格相等进行比较,对==左边的值进行类型转换2.在if判断时,括号内的值进行类型转换,转化为布尔值
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!