黑马程序员技术交流社区

标题: [广州前端]类型转换 [打印本页]

作者: 黑黑黑黑黑黑    时间: 2018-4-12 14:28
标题: [广州前端]类型转换
类型转换发生在静态语言的编译阶段,强制类型转换发生在动态语言的运行期间。 在JavaScript中都统称为强制类型转换,分为显式强转和隐式强转。
JavaScript中的强转总是返回的是标量基本类型,如数字、字符串、布尔,不会返回对象或者函数类型。
var a = 1;var b = a + ''; // 隐式强转var c = new String( a ); // 显式强转抽象操作
抽象操作就是ES5规范中关于强制转换的一些基本规则。
1. toString
toString的抽象操作用来处理非字符强转为字符串。
首先是基本的规则: 1. null -> "null" 2. undefined -> "undefined" 3. true -> "true" 4. 5 -> "5" 如果是极大或者极小的数字返回的是指数形式的字符串。 5. [1,2,3] -> "1,2,3" 将所有单元字符串化后用","拼接 6. Object -> "[Object object]"
toString操作是可以被显式的调用的:
5..toString(); // "5"true.toString(); // "true"[1,2,3].toString(); // "1,2,3"Object.prototype.toString.call(5); // "[object Number]"
对于上述第6点的对象,如果重写了自己的toString()方法,就不会默认返回内部属性[[class]]。而是调用重写了的toString()方法返回结果。实际上对象的抽象操作还有toPrimitive的过程,后边会提到。
这一点像Java中定义一个实体类的时候重写toString()方法的效果。
2. JSON.stringify()
这是我们常用的一个工具方法,用来把Json对象序列化为字符串。
这一过程并不是严格意思上的强制类型转换,但是也用到了toString()。
对于简单值来说其效果和toString()相似,总是返回一个字符串:
JSON.stringify( 5 ); // "5"JSON.stringify( true ); // "true"JSON.stringify( null ); // "null"JSON.stringify( "null" ); // ""null"" 双引号哦JSON.stringify( [1, 4] ); // "[1,4]"
但是对于非JSON安全(不能够呈现有效JSON格式)的值,会被忽略,在数组中则返回null,以保证数组单元的位置不变。
一般非JSON安全的值指的是undefined、function、symbol、包含循环引用的对象等。
JSON.stringify( undefined ); // undefined 注意不是"undefined"JSON.stringify( function(){} ); // undefinedJSON.stringify( {a:'2', b: undefined, c: function(){}} ); // "{"a":"2"}"JSON.stringify( [1, function(){}, undefined, 4] ); // "[1,null,null,4]"
JSON对象也有类似toString()的方法可以重写,用来定义序列化输出的结果。==> toJSON
var a = {    name: 'tom',    age: 15}a.toJSON = function(){    return {        name: '就不输出tom',        age: '永远18'    }}JSON.stringify( a ); // "{"name":"就不输出tom","age":"永远18"}"
toJSON方法返回的应该是一个能够被序列化的JSON安全的值,比如对象或者数组。不要返回一个字符串,不然最后输出的是""{}""这样的结果。
JSON.stringify的其他黑科技3. toNumber
将非数字转为数字。 基本规则:
true --> 1false --> 0null --> 0undefined --> NaN
自己试试:
Number( true ); // 1Number( false ); // 0Number( undefined ); // NaNNumber( null ); // 0Number( "" ); // 0Number( " " ); // 0Number( "''" ); // NaNNumber( [] ); // 0...
对于对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,则遵循上面的规则强转为数字。
至于如何转换为基本类型呢,就会执行抽象操作toPrimitive。该操作会首先检查该对象是不是定义了valueOf()方法,有就首先调用,不然就判断有没有toString()方法,如果有就用其返回值用上面的规则进行类型强制转换的操作。valueOf的优先级更高。
如果使用的是String()方法强转,是直接调用的toString(),这个时候不会考虑valueOf了
// 如果定义了valueOf,就会用其返回值利用上面的规则进行转换var a = {    valueOf: function(){        return '42'    }}Number( a ); // 42// 如果同时有valueOf和toStringvar a = {    valueOf: function(){        return '42'    },    toString: function(){        return '43'    }}Number( a ); // 42 说明先调用的是valueOf// 数组var arr = [1,2,3]var arr1 = [1]Number( arr ); // NaNNumber( arr1 ); // 1arr.toString = function(){    return this.join('')}Number( arr ); // 1234. toBoolean
这里我们必须纠正一个错误的观点,相信大多数人都会认为1和0分别等同于true和false。 这个观点是错误的,虽然他们相互强转确实是那样的结果。
falsy
这个列表是掌握强转为布尔类型最重要也是最有效的,请记住:
上面的5种类型强制转换的结果为false。如果不在上述范围内,强转结果基本为true。 这里说基本,也是要纠正我们的一个错误观点,比如对象不在上述范围内,很多人认为对象强转为布尔类型是恒等于true的,这也是不准确的。
Boolean(undefined || null || NaN || 0 || ""); // false// 对象大多数情况是trueBoolean({} && [] && Object("") && function(){} && Object.create(null)); // true// 有一种对象,比如 document.all,我们常用来判断IE版本Boolean( document.all ); // false// 除了空字符串,其余的都是true,注意 "''" ==> trueBoolean('0' && 'false' && "''" && '  '); // true显式强制类型转换
显示转换为布尔类型的一般使用 Boolean() 或者 !!
隐式强制类型转换字符串和数字之间的隐式强转
最坑的地方来了。
我们首先看看 + 这个运算符,很多时候我们用它实现字符串拼接。但是我们需要真正的理解它的运算规则。
根据规范,+ 操作的基本规则是如果有字符串或者能够抽象为字符串的对象或者数组,采用的是字符串拼接;否则执行的是加法:
// 1. 数字 + 字符5 + ''; // '5'// 2. 数字 + 布尔5 + true; // 6// 3. 数字 + 对象5 + {}; // '5[object Object]'// 4. 数字 + 数组1 + [2,3]; // "12,3"// 5. 数字 + 函数5 + function(){}; // "5function (){}"// 6. 字符 + 布尔'5' + true; // "5true"// 7. 字符 + 对象'5' + {}; // "5[object Object]"'5' + function(){}; // "5function (){}"// 8. 对象 + 数字/对象/布尔{} + 5;  // 5{} + {}; // NaN{} + ''; // 0{} + []; // 0{} + true; // 1{} + function(){}; // NaN// 9. 数组 + 对象/布尔/函数[] + {}; // "[object Object]"[] + true; // "true"[] + function(){}; // "function (){}"[] + '5'; // "5"[] + 5; // "5"[] + []; // ""
总结:
如果要把字符串隐式的转换为数字可以使用 -
'5' - 0; // 55 - []; // 5== 与 ===
前者表示宽松相等,后者表示严格相等。 区别在于第一种允许比较的时候进行类型强制转换,第二种则不允许。
在比较对象的时候二者工作原理是一样的。只要指向的是同一个值就是相等的,不会进行强制转换。至于其他情况,在==比较不同类型值的时候进行强制转换的时候就有一些规律。
1. 字符串与数字的 == 比较var a = '42'var b = 42a==b; // truea===b; // false
字符串与数字比较,规则是 toNumber()操作之后再进行比较。
2. 字符串与布尔的 == 比较var a = '42';var b = true;a==b; // false
也是先把布尔值toNumber()之后得到1,再利用上面的规则比较。
3. null和undefined的 == 比较var a = null;var b = undefined;// == 比较的时候 null和undefined相等。a == b; // true
这一点非常有用,也就是说 null 在==判断的时候仅在==null或者==undefined的时候返回true。这一特性可以用于我们的分支判断中。
var a = doSomething();if(a == null){ // 很多人喜欢写 if(!a){...},这得确保你返回的不是一个falsy。...}4. 对象和非对象的 == 比较
规则是对象需要先 toPrimitive() 之后再按照上边提到的规则进行比较。
var a = 42;var b = [42]a == b; // true
你也可以设置valueOf或者toString来控制对象的ToPrimitive的值。
记住一些特殊的情况
var a = 'abc';var b = Object(a);a==b; // true// 但是var a = null;var b = Object(null);a == b; // falsevar a = undefined;var b = Object(undefined);a == b; // falsevar a = NaN;var b = Object(NaN);a == b; // false5. 其他的特殊案列// 1. 改变原型的valueOfNumber.prototype.valueOf = function(){    return 3;}new Number(2) == 3; // true
总结一下判断==结果的一些规则:
// 我们看看这些。"0" == null; // false -->上面的规则1"0" == undefined; // false --> 规则1"0" == false; // true --> 规则5("0" == 0) 、规则4"0" == 0; // true --> 规则4"0" == NaN; // false --> 规则4"0" == ""; // false --> 规则2false == null; // false --> 规则1false == undefined; // false --> 规则1false == NaN; // false --> 规则5(0 == NaN)false == 0; // true --> 规则5(0 == 0)false == ""; // true  --> 规则5(0 == ""),规则4(0 == 0)false == []; // true --> 规则5(0 == []),规则6(0 == "" --> 0 == 0)false == {}; // false --> 规则5(0 == {}),规则6( 0 == '[object Object]')"" == null; //false -->规则1"" == undefined; //false -->规则1"" == NaN; //false -->规则4( 0 == NaN)"" == {}; // false -->规则6("" == "[object Object]")"" == []; // true -->规则6("" == "")"" == 0; // true -->规则40 == null; // false --> 规则10 == undefined; // false --> 规则10 == NaN; // false0 == {}; // false -->规则6( 0 == '[object Object]')0 == [];// true -->规则6,规则4(0 == '' 然后 0 == 0)[] == ![]; //true -->先执行toBoolean(); ![] =》false;然后就变成了 [] == false;0 == [null]; // true --> 规则6(0 == ""),规则4(0 ==0)0 == [undefined]; // true --> 规则6(0 == ""),规则4(0 ==0)0 == "\n"; // true --> 规则4 (0 == 0), Number("\n") == 0;
上面的判断在实际代码中可能会产生大的bug!
if( a == ''){    ...}// 假如你这样写的话,传个参数 a = 0;那你就GG了。
抽象关系比较:
var a = 42;var b = ['043'];a < b; // truevar a = ['42'];var b = ['043'];a < b; // false  0的顺序大于4var a = { age: 42 };var b = { age: 43 };a > b; // false;a == b; // false;  对象比较,比较引用a < b; // falsea >= b; // truea <= b; // true
我们理解的 >= 其实就是 不小于。
所以 a >= b 其实就 !( a < b ),所以是 true。a <= b 同理就是 !( a > b )
点击查看更多精彩前端资源






欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2