js隐式转换

js数据类型

  1. 基本类型(原始值):Undefined Null String Number Boolean Symbol
  2. 引用类型(对象值):object (数组Array; 函数Function; 正则RegEXP; 日期Date)

来源

  1. +:运算符既可以是数字相加,也可以是字符串相加
  2. ==:==不同于===有多不同情况的隐式转换(以前我看一本书书尽量还是多用==,多拥抱js的隐式转换少用===,但是当我用了===,我就回不去了)
  3. - * / : 这一些运算符就比较友好了,他们只针对number类型,因而转化的结果只能转换成number类型

转化的方法

  1. 将值转为原始值,ToPrimitive()

http://www.ecma-international.org/ecma-262/#sec-toprimitive 7.1.1 中有介绍

  1. 将值转为数字,ToNumber()
  2. 将值转为字符串,ToString()

通过ToNumber将值转为数字

参数结果

undefined

 NaN 

unll

+0

Boolean

true转换为1; false转换为0

Number

无需转换

String

由js中的内置对象Number来处理

Object

1.先进行 ToPrimitive(obj, Number)转换得到原始值,

2.在进行ToNumber转换为数字 

 通过ToString将值转换为字符串

参数

结果

undefined

'undefined'   // '1' + undefined  = "1undefined"

null

'null'

Boolean

'true'或'false'

Number数字转字符串 // (123).toString() => '123'
String字符串无需转换
Object

1.先进行 ToPrimitive(obj, String)转换得到原始值,

2.在进行ToString转换为字符串

通过ToPrimitive将值转换为原始值

ToPrimitive(input, PreferredType?)

input:是要转换的值

PreferredType:(默认值为Number)是可选参数,可以是Number或String类型。他只是一个转换标志,转化后的结果并不一定是这个参数所值的类型,但是转换结果一定是一个原始值(或者报错)。

当标志为Number的时候,ToPrimitive方法的操作流程为

  1. 如果输入的值已经是一个原始值,则直接返回它
  2. 否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。 // valueOf 方法下面会说
  3. 否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
  4. 否则,抛出TypeError异常。

当标志为String的时候,ToPrimitive方法的操作流程为

  1. 如果输入的值已经是一个原始值,则直接返回它
  2. 否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
  3. 否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
  4. 否则,抛出TypeError异常。

valueOf方法和toSting方法解析

valueOf

对转化Number,Boolear,String这三种构造函数生成的基础值的对象形式,通过valueOf转化后变成相应原始值

运行结果

var num = new Number('123')

num.valueOf()

123

var str = new String('12df')

str.valueOf()

'12df'

var bool = new Boolean('fd')

bool.valueOf();

true

var a = new Date();

a.valueOf(); 

// 1515143895500

也是除了 w Date().getTime(); 和 Date.parse( new Date()); 另一种获取时间戳的方法

 var a = new Array();

 a.valueOf() === a;

 // true

var b = new Object({});

 b.valueOf() === b; 

// true

toString

用Number,Boolean,String,Array,Date,RegExp,Function这几种构造函数生成的对象,通过toString转化后变成相应的字符串形式,因为这一些构造函数都封装了自己的toString方法

Number.prototype.hasOwnProperty('toString'); // true
Boolean.prototype.hasOwnProperty('toString'); // true
String.prototype.hasOwnProperty('toString'); // true
Array.prototype.hasOwnProperty('toString'); // true
Date.prototype.hasOwnProperty('toString'); // true
RegExp.prototype.hasOwnProperty('toString'); // true
Function.prototype.hasOwnProperty('toString'); // true

var num = new Number('123sd'); // Number {NaN}

num.toString(); 

 'NaN'

var str = new String('12df');

str.toString(); 

'12df'

var bool = new Boolean('fd');

bool.toString(); 

 'true'

var arr = new Array(1,2);

arr.toString();

'1,2'

var d = new Date();

d.toString();

"Wed Oct 11 2017 08:00:00 GMT+0800 (中国标准时间)"

var func = function () {}

func.toString(); 

"function () {}"

除了以上的对象啊和实例化对象,其他的对象返回的都是改对象的类型,都是基础Object.prototype.toString方法

var obj = new Object({});

obj.toString(); // "[object Object]

Math.toString(); // "[object Math]"

判断数据类型

export const getType = x => /^\[object (.*)\]$/.exec(Object.prototype.toString.call(x))[1]

区别 

valueOf函数会将

  • Number,String,Boolean基本类型转换成相对于的类型,
  • Data类型转换为毫秒数,
  • 其他返回对象本身

toString方法会将

  • 所有对象转为字符串

ToPrimitive默认参数的原因

因为valueOf函数会将Number、String、Boolean基础类型的对象类型值转换成 基础类型,Date类型转换为毫秒数,其它的返回对象本身,而toString方法会将所有对象转换为字符串。显然对于大部分对象转换,valueOf转换更合理些,因为并没有规定转换类型,应该尽可能保持原有值,而不应该想toString方法一样,一股脑将其转换为字符串。

例子

 ({} + {}) = ?

   两个对象的值进行+运算符,肯定要先进行隐式转换为原始类型才能进行计算。

  1.   进行ToPrimitive转换,由于没有指定PreferredType类型,{}会使默认值为Number,进行ToPrimitive(input, Number)运算。
  2.   所以会执行valueOf方法,({}).valueOf(),返回的还是{}对象,不是原始值。
  3.   继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。

   故得到最终的结果,"[object Object]" + "[object Object]" = "[object Object][object Object]"

2 * {} = ?
  1.   1、首先*运算符只能对number类型进行运算,故第一步就是对{}进行ToNumber类型转换。
  2.   2、由于{}是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。
  3.   3、所以会执行valueOf方法,({}).valueOf(),返回的还是{}对象,不是原始值。
  4.   4、继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。
  5.   5、转换为原始值后再进行ToNumber运算,如上显示,字符串进行Number()所以得:"[object Object]"就转换为NaN。

  故最终的结果为 2 * NaN = NaN

 {} + [] // 0
 [] + {} // '[object Object]'

1.如果{}(空对象)在前面,而[](空数组)在后面时,前面(左边)那个运算元会被认为是区块语句而不是对象字面量。所以{} + []相当于+[]语句,也就是相当于强制求出数字值的Number([])运算,相当于Number("")运算,最后得出的是0数字 进行ToNumber

  1. [].valueOf() // 返回数组自身,不是原始数据
  2. 调用 [].toString() // 返回空字符串
  3. Number("") // 空字符串转型为数字,返回0

大家肯定会注意为什么这里是用Number(''),由于JS中如果+运算符由二元运算符变成一元运算符就会将哪个操作符变成Number,MDN

2. [] + {} ===> ToNumber('' + '[object Object]') === ''[object Object]''

注意

在 ES6 之后,还允许对象通过显式指定 @@toPrimitive Symbol 来覆盖原有的行为。

var o = { 
    valueOf : () => {console.log("valueOf"); return {}}, 
    toString : () => {console.log("toString"); return {}} 
} 

o[Symbol.toPrimitive] = () => {console.log("toPrimitive"); return "hello"} 

console.log(o + "") // toPrimitive // hello

注意:

就算以知 +号一边是字符串,那么就是字符串运算符,而不是说一定会进行ToString转换而还是进行默认ToNumber转换,只有使用字符串模板才是进行ToString转换

// An object without Symbol.toPrimitive property.
var obj1 = {};
console.log(+obj1);     // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ''); // "[object Object]"

// An object with Symbol.toPrimitive property.
var obj2 = {
  [Symbol.toPrimitive](hint) {
    if (hint == 'number') {
      return 10;
    }
    if (hint == 'string') {
      return 'hello';
    }
    return true;
  }
};
console.log(+obj2);     // 10        -- hint is "number"
console.log(`${obj2}`); // "hello"   -- hint is "string"
console.log(obj2 + ''); // "true"    -- hint is "default"

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值