记不清在某处看见了这一比较,当时对强制转换这块理解的还没有特别清晰,故有此一文。以为我会以标题的表达式来展开?那你就错了,下面直接上[] == []是如何转换的:
两侧类型相同,直接返回0 === 0的结果true
- - -
本文旨在总结js中强制转换的规则及触发强制转换的几种场景。es6标准中定义了六种原始类型,分别是undefined,null,string,number,boolean,symbol。本文中的强制转换指的是在代码运行时,触发了数值的隐式转换,而不是代码显示的指定转换操作。
发生在原始类型之间的转换,以个人的理解是其他类型转换为string,number或者boolean类型。
其他原始类型转换为string类型通常发生在+两边存在字符串时,会将+另一边的值转换为string类型。
考虑如下代码:
var straddnum = "test" + 1; var numaddstr = 1 + "test"; var booladdstr = true + "test"; var undaddstr = undefined + ""; var nulladdstr = null + ""; console.log(straddnum); console.log(numaddstr); console.log(booladdstr); console.log(undaddstr); console.log(nulladdstr);
,以上代码的运行结果均为字符串。其他原始类型转换为string类型基本是其值的字符串形式,具体如下:
number转为字符串具体可参考es2018 7.1.12.1章节
注意:symbol类型无法转换为string类型。
转换为number类型的情况,+-*/%等运算中,除了+之外其他运算均会转换成number类型,+运算时需要满足两侧未出现string类型,该值才会被转换为number类型。+运算时情况较为复杂,后面会专门描述其相关转换规则。考虑如下代码:
var trueaddtrue = true + true; var trueaddfalse = true + false; var trueadda0 = true + 0; var nulladdtrue = null + true; var undefinedadd0 = undefined + 0; var stradd0 = "" + 0; console.log(trueaddtrue); console.log(trueaddfalse); console.log(trueadda0); console.log(nulladdtrue); console.log(undefinedadd0); console.log(stradd0);
,在运行代码之前可以先考虑下以上代码答打印的结果分别是什么?然后再运行,看是否符合你的预期。其他原始类型转换为number类型的具体如下:
注意:symbol类型同样无法转换为number类型。
转换为boolean类型的情况较为简单,除了以下情况转换为boolean类型会是false,其他情况均是true
es中将对象转换为原始类型的算法,大致可描述为三种情形:
上述三种情形中第一种情形优先级最高,第二三种情形优先级并列,具体需要根据使用场景判断是哪一种。其中的指定转换提示是es标准内部调用该算法时指定的。
第一种情形只有symbol对象和date对象内置了[symbol.toprimitive],且该属性的writeable为false,enumerable为false,configurable为true
对象转换为原始类型时发生的强制转换非特殊情况均为第二种,第三种情况较为少见。在正常编码工作中应该使用第二种情形就够用了,第三种情形几乎不会出现,要了解更多细节可查阅es标准。
var test = { [symbol.toprimitive]: function(hint) { console.log(hint) }, valueof: function() { console.log("valueof") }, tostring: function() { console.log("tostring") } } test + ""; //"default" test * 0; //"number" string(test); //"string"
上述代码指定了分别指定了test对象的[symbol.toprimitive],valueof和tostring函数,可以观察到并valueoof和tostring函数均未被调用,指定的[symbol.toprimitive]函数可以接受一个提示参数,这个参数就是强制转换时的强制转换提示。这样我们在函数中就可以根据转换场景的不同分别返回不同的值。
在开始描述这个问题之前,可以先思考一下,都有哪些场景会是强制的将原始类型转换为对象,其实这种场景几乎在js代码中随处可见,考虑如下代码:
var str = "teststring"; str.replace("test", "");
如上代码中定义的str的值并不是一个对象而是一个原始类型string,原始类型显然是没有方法可以调用的。
实际上这里的str在执行str.replace时str其值会被强制转换为对象,得到一个string类型的实例对象,而该实例的原型上定义了一系列方法,且该实例是无法被获取的,在执行完这行代码后,该实例就会被回收,所以这里的str依然是一个字符串。
考虑如下代码:
var a = 3; a.fn = function(){}; a.fn();
在js代码中会出现强制转换的场景通常有三种:
作为判断条件
做一元+运算时,均会被强制转为number类型,例如
var a = { [symbol.toprimitive]: function(hint) { console.log(hint); // number if(hint === "number") { return 2; } else { return 9; } } }; console.log(+a); // 2 var b = "3"; console.log(+b); // 3
二元+运算为几种强制转换中复杂度仅次于==比较的一种情形,个人总结其转换步骤如下:
var a = ""; var b = { [symbol.toprimitive]: function(hint) { console.log(hint); // "default" if(hint === "default") { return 2; } else { return 9; } } }; var c = a + b; //这里b转换为原始类型返回的是number类型2,由于a是"",所以b被转换为"2",后与""拼接返回"2" console.log(c); // "2" var d = 3; var e = { [symbol.toprimitive]: function(hint) { console.log(hint); // "default" if(hint === "default") { return 2; } else { return 9; } } }; var f = d + e; //这里e转换为原始类型返回的是number类型2,由于两侧均没有string类型,则至第3步,强制转换为number后返回两侧相加的结果5 console.log(f); // 5
var a = 8; var b = { [symbol.toprimitive]: function(hint) { console.log(hint); // "number" if(hint === "number") { return 2; } else { return 9; } } }; console.log(a-b); // 6 console.log(a/b); // 4 console.log(a*b); // 16 console.log(a%b); // 0 console.log(undefined * 0); //nan console.log(null * -1); // 0 console.log(false * -1); //0 console.log(true * -1); // -1 console.log("1" * -1); // -1
x === y,其具体比较步骤如下:
==比较的转换规则虽然稍微多一点,实际上也就几条规则,两侧的数值类型符合哪种就按哪种去转换,只不过有的可能需要转两次,具体如下:
下面列举一些可能有点违反直觉的比较
"0" == false; // true false == 0; // true false == ""; // true false == []; // true "" == 0; // true "" == []; // true 0 == []; // true [] == ![]; //true
这种情形到没有太多可说的,基本上就是,除了undefined,null,+0,-0,nan,""这六个值会被转为false,其他情况均为true;
出现将不是boolean类型的值强制转换的情况为
其实上面描述了这么多,日常开发环境中用到比较多的应该是作为判断条件,+,==这三种情况了,这三种中最常见的应该是判断条件的情况了,这种情况反而是最简单的一种了。
如对本文有疑问, 点击进行留言回复!!
轻松解决 org.apache.taglibs.standard.tlv.JstlCoreTLV 困惑
vert实践五——Json?Protocol Buffer?FlatBuffers?
[基于tensorflow的人脸检测] 基于神经网络的人脸检测8——验证训练好的神经网络
selenium + ajax抓取英雄联盟全部英雄的详细信息及多线程保存全部皮肤图片到本地
网友评论