WdBly Blog

懂事、有趣、保持理智

WdBly Blog

懂事、有趣、保持理智

周维 | Jim

603927378@qq.com

javascrtip 隐式转换 和 运算符

javascrtip 隐式转换 和 运算符##

- * / 和 %

js在进行以上几种运算时,会将参与运算的双方都转化为Number类型,然后进行运算,那么,不同类型的值转换为Number类型的结果如何呢?

对于Number, String, Boolean, Undefined, Null这5种基本数据类型的转换为直接转换,然后进行计算。

Number(5) // 5 Number("5") // 5 Number("a") // NaN Number(true) // 1 Number(false) // 0 Number(undefined) // 0 Number(null) // 0

对于引用数据类型Object来说,转换规则复杂一点

object的隐式转换

当对象参与到上述运算中时,js启动隐式转换将对象转换为数字。
javascript对象原型上有valueOf和toString两个方法参与到隐式类型转换中。

var a = {}; a.valueOf() // {} a.toString() // "[object Object]" // 这两个方法都存在于a对象的构造函数也就是 Object中 Object.toString === a.constructor.toString // ture Object.valueOf === a.constructor.valueOf // ture

valueOf默认返回当前对象原始值,toString方法用于将当前对象以字符串的形式返回,返回"[object ObjectName]",其中 ObjectName 是对象类型的名称,如"[object object]", “[object NodeList]”

注意对于RegExp, Math, Date等对象的toString方法返回值不一,请私下查阅。

当有运算符参与时,valueOf和toString两个方法隐式类型转换的规则为:对象首先调用valueOf方法,若该方法返回了一个引用类型的值(非原始值)如{},[],则继续调用toString方法。若valueOf方法返回了一个原始值如:1,“a”,true等,则不再调用toString方法。

// 重写valueOf和toString方法 // 1: 若valueOf返回一个引用类型的值。 var a = { valueOf: function(){ console.log("valueOf") return {} }, toString: function(){ console.log("toString") return "box" } }; a + 1 // valueOf // toString // "box1" // 2: 若valueOf没有返回原始值。 var a = { valueOf: function(){ console.log("valueOf") return 1 }, toString: function(){ console.log("toString") return "box" } }; a + 1 // valueOf // 2 // 3: 若toString中返回了一个引用类型的值呢? var a = { valueOf: function(){ console.log("valueOf") return [] }, toString: function(){ console.log("toString") return {} } }; a + 1 // valueOf // toString // Uncaught TypeError: Cannot convert object to primitive value // 无法将对象转换为原始值

当上述过程调用完毕后,将返回值转换为Number再进行计算。

上述情况当toString返回了一个引用类型的值时你将得到一个错误。

若使用String(a)进行显示类型转换则先执行toString方法。

array的隐式转换

数组做为对象的一种,同样拥有valueOf和toString方法,同样满足对象隐式转换规则,首先调用valueOf返回自身,然后调用toString方法返回结果。

var a = []; a.valueOf === Array.prototype.valueOf //true a.constructor.valueOf === Array.prototype.valueOf //true a.constructor.valueOf === Object.valueOf //true // Array中的valueOf继承自Object Array.prototype.valueOf === Object.valueOf //true

数组的toString方法是将数组的每个元素转换为字符串,并将它们依次连接起来,两个元素之间用英文逗号作为分隔符进行拼接。

//这里再 [5] => "5"之间应该是[5]调用valueOf方法返回[5]的过程 //下方我们将省略此过程 [] => "" => Number("") => 0 [5] => "5" => Number("5") => 5 ["8"] => "8" => Number("8") => 8 ["a"] => "a" => Number("a") => NaN [{}] => "{}" => Number("{}") => NaN [undefined] => "" => Number("") => 0 [null] => "" => Number("") => 0 [[1]] => "1" => Number("1") => 1 [true] => "true" => Number("true") => NaN [1,2] => "1,2" => Number("1,2") => NaN [[1], [2]] => "1,2" => Number("1,2") => NaN

+ 运算符

在上面我们说了 - * / %的运算时的转换规则,接下来我们来看+运算符的一些规则。

在js中,+运算符除了表示加法运算外,还可以用于字符串的连接,具体规则如下:
若 A + B;
1: 将 A和B都转换为原始值,对象的转换规则如上,调用valueOf和toString方法。
2: 对比转换后的数据类型,若有一方为String类型,则将A,B都转换为String类型,然后执行 + 连接符,结束。
3: 否则将 A,B都转换为Number类型,然后执行加法操作,结束。

//转换为原始类型后有一方为String类型 1 + "1" // "11" true + "1" //"true1" ({} + 1) //"[object Object]1" [] + 1 => "" + 1 // "1" //否则 true + true // 2 1 + true // 2 1 + {valueOf:function(){return 1}} // 2

==, >=, <=, !=, >, <等比较运算符

[] == ![] ??

js的 == 号有隐式转换的作用,转换规则为将 == 号两边的值都转换为Number然后进行处理

1 == "1" => 1 == 1 // true 1 == true => 1 == 1 // true 2 == true => 2 == 1 // false [] == false => 0 == 0 // true [1] == 1 => 1 == 1 // true 2 == {valueOf:function(){return 2}} // true [] == ![] => 0 == 0 //true [1,2] == "1,2" => "1,2" == "1,2" // true // 说下 [] == ![]为true的过程 等号左侧: 1: [].valueOf() => [] 2: [].toString() => "" 3: Number("") => 0 等号右侧: 4: ![] => !Boolean([]) => false 5: Number(false) => 0 6: 0 == 0 //成立

&&, ||, !,等符号属于逻辑运算符,逻辑运算符会将对比值隐式转换为布尔值。

这里有个知识点, 在javascript中,只有 “”, +0, -0, null, undefined, false, NaN转换成布尔值为假, 所以 ![] === false

网上流传的一道有意思的题:

var a = ?; if(a == 1 && a == 2 && a == 3){ console.log(true) } // 问当a为何值时满足if中的条件 // 通过上面我们学到的隐式转换解决 // 我们知道若a为对象,每次的 == 都会执行一次隐式类型转换进而对比结果 a = { v: 1, valueOf: function(){ return this.v++; } }

有关JavaScript隐式转换的内容到此结束了,如果各位读者在阅读的过程中有任何疑问或者发现任何不当或错误之处请在评论区指出,万分感谢。