先来做几道简单的计算题:
计算题:
{} + []
[] + {}
1 + true
1 + false
是不是觉得很简单,是的,如果你的基础很好的话,就会觉得确实是挺简单的。如果你对你的答案不是很确定的话,别着急,后面会详细和你讲解这几道题,并且会说到为什么会是这样。
话不多说先把答案给大家看看把
console.log({}+[]);//[object Object]
console.log([]+{});//[object Object]
console.log(1 + true);//2
console.log(1 + false);//1
第一道题:一个数组和一个对象相加,返回的答案是[object Object],其实在JavaScript中,引用数据类型是做不了加法的,必须要把加号两边的值都转换成基本数据类型,再来进行加法运算。那如何把这两个引用数据类型的值转换成基本数据类型呢?
按照如下步骤,你就可以将引用数据类型,转换成基本数据类型
1.判断左边是否为基本数据类型,如果是的话,步骤到此结束,如果不是,执行下面的步骤
2.调用valueOf方法,如过返回值是基本数据类型,步骤到此结束,如果不是,执行下面步骤
3.调用toString方法,如果返回的是基本数据类型,步骤到此结束,如果不是,报错
按照以上步骤,来实际操看看这道题,左边是{},一看就不是基本数据类型,执行步骤2,调用valueOf,返回的是对象本身{},经检测不是基本数据类型,然后执行步骤3,调用toString方法,返回字符串[object Object],判断字符串是基本数据类型,结束所有步骤。
右边是一个空数组[],依旧是按照步骤来,先调用valueOf,返回的是一个空字符串,判断这个空字符串是基本数据类型,结束步骤
左右两边都转换成了基本数据类型,可以相加了,空字符串与[object Object]相加,当然[object Object]字符串了。
第二道题:如果你看了第一道题的解析,第二道题就不用讲了,基本上是一模一样,但是为什么要出两个一样的题目呢,原因就是为了迷惑你的眼睛,笔试题经常出这样的题,其实结果是一样的。
第三道题:1 + true,左边数字1是基本数据类型,右边Boolean类型true,都是基本数据类型,所以上面的做法是完全不需要的,按理来说是可以直接相加的,但是怎么相加呢?由于JavaScript是弱类型语言,就是不会进行类型检查,但是虽然js是弱类型语言不会进行类型检查,这不意味着两种数据类型就可以相加。所以来说,数字类型和布尔类型是不可以相加的,那为什么返回这道题返回了2呢,其实在相加中还存在一个步骤,那就是隐式类型转换。所有和Number类型相加的值都会转换成Number,在这道题中,true转换成了数字1,所以返回的是2.
第四道题:1 + false,和第三道题一样,false隐式转换成了0,1+0返回的数据就是1了。
这几道题设计到的知识点:
1.基本数据类型和引用数据类型
基本数据类型有:string, number, boolean, null, undefined, symbol, bigint
引用数据类型:Object
基本数据类型也叫做原始数据类型,什么是原始类型后者说基本类型呢?
除 Object 以外的所有类型都是不可变的(值本身无法被改变)。例如,与 C 语言不同,JavaScript 中字符串是不可变的(译注:如,JavaScript 中对字符串的操作一定返回了一个新字符串,原始字符串并没有被改变)。我们称这些类型的值为“原始值”。
2.基本数据类型的隐式转换规则
为了大家更加容易记住,我们在这里进行分类,此处简单分为三类。
2.1字符串 + 其他原始类型
记住一句话,不管是谁和字符串相加,都需要转换成基本数据类型字符串
2.2数字 + 其他的非字符串的原始数据类型
Number的优先级比字符串低一点,不管是什么数据类型(除了字符串),与Number类型的数值相加的话,都需要转换成Number类型
此处可以看出来Boolean类型的true转换成1,false转换成0,null转换成0,undefined转换成NaN(也就是not a number的缩写)
2.3数字/字符串以外的原始数据类型作加法运算
当数字与字符串以外的其他原始数据类型直接使用加号运算时,就是转为数字再运算,这与字符串完全无关
3.引用数据类型如何转换成基本数据类型(ToPrimitive 转换算法)
ToPrimitive(input, PreferredType)算法:
ToPrimitive 算法的作用就是将值转换成原始值,内部调用的方法就是value方法和toString方法来转换的
大概的转换步骤:
1.如果 input
是原始值,返回这个值(没有其他需要做的)。
2.否则,如果 input
是对象,调用 input.valueOf()
。 如果结果是原始值,则返回结果。
3.否则,调用 input.toString()
。如果结果是原始值,返回结果。
4.否则,抛出一个 TypeError
(说明将输入转换成原始值出错了)。
PreferredType 是 String
将 Number 的转换步骤中第二步和第三步交换。
PreferredType 也可以被省略
这种情况下,日期会被认为是 String 而其他值会被认为是 Number ,因此+运算符和==运算符可以操作 ToPrimitive()。
4.toString方法,valueOf方法
首先MDN官方链接奉上,这里写的很详细,看这两个文档,你就啥都明白了。当然我下面也会简单总结一下。
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf
toString:
**toString()**
方法返回一个表示该对象的字符串。
因为toString方法是Object原型上面的方法,由于JavaScript是通过原型链进行继承的,而且所有对象都继承自Object所以其他对象都继承Object的toString方法,但是有些内置对象对toString方法进行了重写
个对象都有一个 toString()
方法,当该对象被表示为一个文本值时,或者一个对象以预期的字符串方式引用时自动调用。默认情况下,toString()
方法被每个 Object
对象继承。如果此方法在自定义对象中未被覆盖,toString()
返回 “[object type]”,其中 type
是对象的类型。以下代码说明了这一点:
var o = new Object();
o.toString(); // returns [object Object]
valueOf:
**valueOf()**
方法返回指定对象的原始值。
描述:
JavaScript调用valueOf
方法将对象转换为原始值。你很少需要自己调用valueOf
方法;当遇到要预期的原始值的对象时,JavaScript会自动调用它。
默认情况下,valueOf
方法由Object后面的每个对象继承。 每个内置的核心对象都会覆盖此方法以返回适当的值。如果对象没有原始值,则valueOf
将返回对象本身。
JavaScript的许多内置对象都重写了该函数,以实现更适合自身的功能需要。因此,不同类型对象的valueOf()方法的返回值和返回值类型均可能不同。
对象 | 返回值 |
Array | 返回数组对象本身。 |
Boolean | 布尔值。 |
Date | 存储的时间是从 1970 年 1 月 1 日午夜开始计的毫秒数 UTC。 |
Function | 函数本身。 |
Number | 数字值。 |
Object | 对象本身。这是默认情况。 |
String | 字符串值。 |
Math 和 Error 对象没有 valueOf 方法。 |