必读:
深入理解Javascript中的valueOf与toString
toString()
对象 | toString返回值 |
---|---|
Array | 以逗号分割的字符串,如[1,2]的toString返回值为"1,2",跳过null,undefined |
Boolean | "True" |
Date | 可读的时间字符串,如"Tue Oct 15 2019 12:20:56 GMT+0800 (中国标准时间)" |
Function | 声明函数的JS源代码字符串 |
Number | "数字值" |
Object | "[object Object]" |
String | "字符串" |
valueOf()
MDN对valueOf()的描述:
JavaScript调用valueOf
方法将对象转换为原始值。你很少需要自己调用valueOf
方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。
默认情况下,valueOf
方法由 Object
后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。如果对象没有原始值,则valueOf
将返回对象本身。
valueOf()
方法的返回值和返回值类型均可能不同。对象 | valueOf返回值 |
---|---|
Array | 数组本身 |
Boolean | 布尔值 |
Date | 返回毫秒形式的时间戳 |
Function | 函数本身 |
Number | 数字值 |
Object | 对象本身 |
String | 字符串值 |
// Array:返回数组对象本身 var array = ["ABC", true, 12, -5]; console.log(array.valueOf() === array); // true // Date:当前时间距1970年1月1日午夜的毫秒数 var date = new Date(2013, 7, 18, 23, 11, 59, 230); console.log(date.valueOf()); // 1376838719230 // Number:返回数字值 var num = 15.26540; console.log(num.valueOf()); // 15.2654 // 布尔:返回布尔值true或false var bool = true; console.log(bool.valueOf() === bool); // true // new一个Boolean对象 var newBool = new Boolean(true); // valueOf()返回的是true,两者的值相等 console.log(newBool.valueOf() == newBool); // true // 但是不全等,两者类型不相等,前者是boolean类型,后者是object类型 console.log(newBool.valueOf() === newBool); // false // Function:返回函数本身 function foo(){} console.log( foo.valueOf() === foo ); // true var foo2 = new Function("x", "y", "return x + y;"); console.log( foo2.valueOf() ); /* ƒ anonymous(x,y) {return x + y;} */ // Object:返回对象本身 var obj = {name: "张三", age: 18}; console.log( obj.valueOf() === obj ); // true // String:返回字符串值 var str = "http://www.xyz.com"; console.log( str.valueOf() === str ); // true // new一个字符串对象 var str2 = new String("http://www.xyz.com"); // 两者的值相等,但不全等,因为类型不同,前者为string类型,后者为object类型 console.log( str2.valueOf() === str2 ); // false
直接转换为true(包装类型也一样),不调用valueOf和toString
对象转换为数字
对象转换为数字会依次调用valueOf和toString方法,具体规则如下:
-
如果对象具有
valueOf
方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为数字(转换失败会返回NaN),并返回这个数字 -
如果对象具有
toString
方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为数字(转换失败会返回NaN),并返回这个数字 -
转换失败,抛出TypeError
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日志 Object.prototype.valueOf = function () { console.log('valueOf'); return valueOf.call(this); }; // 添加toString日志 Object.prototype.toString = function () { console.log('toString'); return toString.call(this); }; var a = {}; console.log(++a); // valueOf toString NaN
-
valueOf方法返回的是对象本身,不是原始值,继续执行
-
toString方法返回的是"[object Object]",是原始值(字符串),将字符串转换为数字NaN
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日志 Object.prototype.valueOf = function () { console.log('valueOf'); return "1"; // 强制返回原始值 }; // 添加toString日志 Object.prototype.toString = function () { console.log('toString'); return toString.call(this); }; var a = {}; console.log(++a); // valueOf 2
分析:
对象转换为字符串
对象转换为数字会依次调用toString和valueOf方法,具体规则如下:
-
如果对象具有
toString
方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为字符串,并返回该字符串 -
如果对象具有
valueOf
方法且返回原始值(string、number、boolean、undefined、null),则将该原始值转换为字符串,并返回该字符串 -
转换失败,抛出TypeError
// 保存原始的valueOf var valueOf = Object.prototype.valueOf; var toString = Object.prototype.toString; // 添加valueOf日志 Object.prototype.valueOf = function () { console.log('valueOf'); return valueOf.call(this); }; // 添加toString日志 Object.prototype.toString = function () { console.log('toString'); return toString.call(this); // '[object Object]' toString方法先调用 ,如果返回结果是字符串,则停止调用 valueOf,不是字符串,那么就调用 valueOf }; var a = {}; console.log(a.toString()); // valueOf toString [object Object]str // alert(a) // alert主动调用toString方法,返回了字符串"[object Object]",对象最终转换为该字符串
加强记忆
demo1:
var colors = ["red", "blue", "green"]; // 创建一个包含3 个字符串的数组 console.log('原数组:', colors); // ["red", "blue", "green"] // valueOf 返回本身 console.log(colors.valueOf()); // ["red", "blue", "green"] // toString 返回字符串 console.log(colors.toString()); // red,blue,green colors.valueOf = function () { return '改写了Array的valueOf' } colors.toString = function () { return '改写了Array的toString' } console.log(colors.valueOf()); // 改写了Array的valueOf console.log(colors.toString()); // 改写了Array的toString
demo2:
var colors = { name: 'red' }; colors.valueOf = function () { console.log('改写了colors的valueOf') return [] } colors.toString = function () { console.log('改写了colors的toString') return 2 } console.log(Number(colors)); /* 改写了colors的valueOf 改写了colors的toString 2 */
number相关
将非number类型的值转换为number类型
-
-
一种是显示转换-调用
Number()、parseInt()、parseFloat()
方法转换
Number():
-
如果是boolean值,true和false将分别被替换为1和0
-
如果是数字值,只是简单的传入和返回
-
如果是null值,返回0
-
如果是undefined,返回NaN
-
如果是字符串,遵循下列规则:
-
如果字符串中只包含数字,则将其转换为十进制数值,即”1“会变成1,”123“会变成123,而”011“会变成11(前导的0被忽略)
-
如果字符串中包含有效的浮点格式,如”1.1“,则将其转换为对应的浮点数(同样,也会忽略前导0)
-
如果字符串中包含有效的十六进制格式,例如”0xf“,则将其转换为相同大小的十进制整数值
-
如果字符串是空的,则将其转换为0
-
如果字符串中包含除了上述格式之外的字符,则将其转换为
NaN
-
-
如果是对象,则调用对象的valueOf()方法,再调用对象的toString()方法,然后再依次按照前面的规则转换返回的字符串值。
parseInt():
常常用于将其它类型值转化为整形。parseInt转换与Number()有区别,具体规则如下:
-
parseInt(value,radius)有两个参数,第一个参数是需要转换的值,第二个参数是转换进制(该值介于 2 ~ 36 之间。如果该参数小于 2 或者大于 36,则 parseInt() 将返回 NaN。),如果不传(或值为0),默认以10为基数(如果value以 “0x” 或 “0X” 开头,将以 16 为基数)
-
注意在第二个参数默认的情况下,如果需要转换的string值以0开头,如'070',有一些环境中,会自动转化为8进制56,有一些环境中会自动转化为10进制70。所以为了统一效果,我们在转换为10进制时,会将第二个参数传10
console.log(parseInt('')) //NaN console.log(parseInt('a')) //NaN console.log(parseInt('1234blue')) //1234 console.log(parseInt(true)) //NaN console.log(parseInt('070')) //70,但是有一些环境中会自动转换为8进制56 console.log(parseInt('070', 8)) //56 console.log(parseInt('001.1')) //1 console.log(parseInt('0xf')) //15,16进制 console.log(parseInt('AF', 16)) //175,16进制 console.log(parseInt('AF')) //NaN console.log(parseInt('000xf')) //0 var a = {} console.log(parseInt(a)) //NaN a.toString = function () { return 2 } // 重写valueOf()方法 console.log(parseInt(a)) //2 a.valueOf = function () { return 1 } // 重写valueOf()方法 console.log(parseInt(a)) //2
parseFloat():
parseFloat()
转换规则基本与parseInt()
一致,只有如下不同点
-
parseFloat()遇到浮动数据时,浮点有效(但是只有第一个.有效),如"10.1"会被转为10.1;'10.1.1'会被转为10.1
-
console.log(parseFloat('1234blue')) //1234 console.log(parseFloat('1234blue', 2)) //1234 console.log(parseFloat('0xA')) //0 console.log(parseFloat('10.1')) //10.1 console.log(parseFloat('10.1.1')) //10.1 console.log(parseFloat('010')) //10
由于Number()函数在转换字符串时比较复杂而且不够合理,因此在处理整数的时候更常用的是parseInt()函数-需注意最好第二个参数传10,处理浮点数时更常用parseFloat()
var a = 10.2 var b = 10.1 console.log(a - b === 0.1) //false console.log(a - 10.1 === 0.1) //false,实际是0.09999999999999964 console.log(a - 0.1 === 10.1) //true
字符串
要把一个值转换为一个字符串有三种方式。
-
第一种是使用几乎每个值都有的
toString(基数)
方法(除去null和undefined
没有)——当需要toString
的值为number
时,参数可以生效。 -
第二种是隐式转换,+ 号:要转换的值为对象时,回调用对象的valueOf属性。
-
第三种是通过转换函数
String()
,转换规则如下 -
如果值有
toString()
方法,则调用该方法(没有参数)并返回相应的结果,(注意不会调用valueOf()
方法) -
如果值是
null
,则返回null,
如果值是undefined
,则返回undefined
var c = {}; console.log(c);//[object Object] console.log(c + '1');//[object Object]1 console.log(String(c));//[object Object] c.valueOf = function () { return '重写c的valueOf方法' }; console.log(c);// {valueOf: ƒ} valueOf重写 console.log(c + '1');// 重写c的valueOf方法1 隐式转换时,valueOf起作用了 console.log(String(c));// [object Object] c.toString = function () { return '重写c的toString方法' }; console.log(c);// {valueOf: ƒ, toString: ƒ} toString起作用了 console.log(String(c)); // 重写c的toString方法 console.log(String(null));// null,null和undefined可以String()输出 console.log(String(undefined));// undefined ,null和undefined可以String()输出 // console.log(null.toString());//报错,null和undefined不能toString let d = {} d.valueOf = function () { console.log('valueOf 执行了') return 'valueOf' }; d.toString = function () { console.log('toString 执行了') return 'toString' }; console.log(d + '1') // 隐式转换 valueOf(转换为原始值) 执行了 console.log(String(d)) // String toString(获得该值的字符串表示法) 执行了
/* 1.先调用对象的toString方法 2.判断该方法的返回值是否为基础数据类型(Number,String,Boolean,Undefined,ull) 3.若返回值为基础数据类型,则转换规则按照相应数据类型的转换规则对其进行转换 4.若返回值不为基础数据类型,则在该返回值的基础上继续调用valueOf方法 5.判断valueOf的返回值是否为基础数据类型 6.判断是否为基础数据类型,若是基础数据类型则进行操作3 7.若仍旧不为基础数据类型则报错 */ let b = {name: 'houfee'} console.log(String(b)); // [object Object] let c = [] console.log(String(c)); // 空字符串 let d = {} console.log(String(d)); // [object Object]
String与Number的区别则在于
-
Number是先调用valueOf()再调用toString ()
-
而String是先调用toString()再调用valueOf()
Number()先转换为原始类型,再转化为字符串形式
String()先转换为字符串形式,再转化为原始类型
function isArray(value) { return Object.prototype.toString.call(value) == "[object Array]" } function isFunction(value) { return Object.prototype.toString.call(value) == "[object Function]" } function isRegExp(value) { return Object.prototype.toString.call(value) == "[object RegExp]" }
console.log(Number({})); // NaN、 console.log(String({})); // [object Object] console.log(Boolean({})); // true console.log(Number([])); // 0 console.log(String([])); // 空字符串 console.log(Boolean([])); // true console.log({} + {}) // [object Object][object Object] console.log({} + []) // [object Object] console.log([] + {}) // [object Object] console.log([] + []) // 空字符串