js隐式转换

先看个例子

const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}
if(a==1){
  console.log('1')
}
if(a==2){
  console.log('2')
}
if(a==3){
  console.log('3')
}

答案自己运算试试

先说说js数据类型

  1. 基础类型(原始值):
    Undefined、Null、String、Number、Boolean、Symbol
  2. 复杂类型(对象值):
    Object

三种隐式转换类型

涉及隐式转换最多的两个运算符 + 和 ==
+运算符即可数字相加,也可以字符串相加。
-*/ 这些运算符只会针对number类型,估转换的结果只能是转换成number类型。

隐式转换中主要涉及到三种转换:

  1. 将值转为原始值(基础类型的值),ToPrimitive()
  2. 将值转为数字,ToNumber()
  3. 将值转为字符串,ToString()

通过ToPrimitive将值转换为原始值

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

  • 如果PreferredType被编辑为Number,则会进行下面的操作流程来转换输入的值。
1. 如果输入的值已经是一个原始值,则直接返回它。
2. 否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
3. 否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
4. 否则,抛出TypeError异常。
  • 如果PreferredType被标记为String,则会进行下面的操作流程来转换输入的值。
1. 如果输入的值已经是一个原始值,则直接返回它。
2. 否则,调用这个对象的toString()方法,如果toString()方法返回的是一个原始值,则返回这个原始值。
3. 否则,如果输入的值是一个对象,则调用该对象的valueOf()方法,如果valueOf()方法的返回值是一个原始值,则返回这个原始值。
4. 否则,抛出TypeError异常。

既然PreferredType是可选参数,那么如果没有这个参数时,怎么转换?规则如下:

1. 该对象为Date类型,则PreferredType被设置为String
2. 否则,PreferredType被设置为Number

valueOf方法和toString方法解析

Object.prototype具有valueOf和toString方法,而Object.prototype是所有对象原型链顶层原型,所有对象都会继承该原型的方法,故任何对象都会有valueOf和toString方法。

valueOf函数对js的常见内置对象转换结果:

  1. Number、Boolean、String这三种构造函数生成的基础值的对象形式,通过valueOf转换后变成相应的原始值。
var num = new Number('123');
num.valueOf();  //123

var str = new String('123');
str.valueOf(); //'123'

var bool = new Boolean('fa');
bool.valueOf(); // true
  1. Date这种特殊的对象,其原型Date.prototype上内置的vauleOf函数将日期转换为毫秒的形式的数值。
var a = new Date();
a.valueOf();  //1608262149351
  1. 除此之外返回的都为this,即对象本身:
var a = new Array();
a.valueOf()  //[]

var b = new Object({});
b.valueOf()  //{}

toString函数对js的常见内置对象转换结果:

var num = new Number('123sd');  //若为纯数字,则为数字字符串
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();   //"Fri Dec 18 2020 11:52:17 GMT+0800 (中国标准时间)"

var func = function(){}
func.toString();  // 'function(){}'

var obj = new Object({});
obj.toString(); // "[object Object]"

练习题

({} + {} ) = ?
两个对象的值进行+运算符,肯定要先进行隐式转换为原始类型才能进行计算。
1. 进行ToPrimitive转换,由于没有指定PeferredType类型,{}会使默认值为Number,进行ToPrimitive(input,Number)运算。
2. 所以会执行vauleOf方法,({}).valueOf(),返回的还是{}对象,不是原始值。
3. 继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。
所以答案是"[object Object]" + "[object Object]" = "[object Object][object Object]"
2 * {} = ?
1、首先*运算符只能对number类型进行运算,故第一步就是对{}进行ToNumber类型转换。
2、由于{}是对象类型,故先进行原始类型转换,ToPrimitive(input, Number)运算。
3、所以会执行valueOf方法,({}).valueOf(),返回的还是{}对象,不是原始值。
4、继续执行toString方法,({}).toString(),返回"[object Object]",是原始值。
5、转换为原始值后再进行ToNumber运算,"[object Object]"就转换为NaN。
故最终的结果为 2 * NaN = NaN
  1 + false
  1 + '2' + false
  1 + '2' - false
  1 - '2' + false
  1 - '2' - false
const a = {
  i: 1,
  toString: function () {
    return a.i++;
  }
}
if(a==1){
  console.log('1')
}
if(a==2){
  console.log('2')
}
if(a==3){
  console.log('3')
}

解析:

1. 当执行a == 1 && a == 2 && a == 3 时,会从左到右一步一步解析,首先 a ==  1,会进行上面第9步转换。ToPrimitive(a, Number) == 1。
2. ToPrimitive(a, Number),按照上面原始类型转换规则,会先调用valueOf方法,a的valueOf方法继承自Object.prototype。返回a本身,而非原始类型,故会调用toString方法。
3. 因为toString被重写,所以会调用重写的toString方法,故返回1,注意这里是i++,而不是++i,它会先返回i,在将i+1。故ToPrimitive(a, Number) = 1。也就是1 == 1,此时i = 1 + 1 = 2。
(此处延伸++i 和 i++ 的区别:
  ++i,是先将值赋值给其他值之后,在进行+1运算
  i++,是先进行+1运算之后,将值赋值给其他值
)
4. 执行完a == 1返回true,会执行a == 2,同理,会调用ToPrimitive(a, Number),同上先调用valueOf方法,在调用toString方法,由于第一步,i = 2此时,ToPrimitive(a, Number) = 2, 也就是2 == 2, 此时i = 2 + 1。
5. 同上可以推导 a == 3也返回true。故最终结果 a == 1 && a == 2 && a == 3返回true

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容