阅读 39

js运算

1、加法运算

(1)、规则

a、基本类型:若运算子中含有字符串,另一个运算子转换为字符串以后再做加法运算;若运算子中不含字符串,则直接转为Number再进行计算;

b、对象类型:JS中的值有原始类型(Primitive)和对象类型(Object)。在做相加等操作时,不是原始类型的要先使用ToPrimitive运算转换为原始类型(基本类型),再执行相关的操作。

(2)、原理探究

a、ToPrimitive的探究

ToPrimitive(input, PreferredType?)
复制代码

这里的input是代入的值,PreferredType可以是数字(Number)或字符串(String)其中一种,表示需要优先转换的原始类型。但如果没有提供这个值也就是预设情况,则会设置转换的hint值为"default"。这个首选的转换原始类型的指示(hint值),是在作内部转换时由JS视情况自动加上的,一般情况就是预设值。

而在JS的Object原型的设计中,有两个方法,valueOf与toString,在对象的数据类型转换过程中会根据传入的值调整被调用的顺序。

  • PreferredType为数字(Number)时
    当PreferredType为数字(Number)时,input为要被转换的值,转换input值的步骤:
    1.如果input为原始数据类型,直接返回input。
    2.否则,input是对象,调用valueOf()方法,如果能得到原始数据类型的值,返回这个值。
    3.否则,input是对象,调用toString()方法,如果能得到原始数据类型的值,返回这个值。
    4.否则,抛出TypeError错误。

  • PreferredType为字符串(String)时
    1.如果input是原始数据类型,直接返回input。
    2.否则,input是对象,调用toString()方法,如果能得到原始数据类型的值,返回这个值。
    3.否则,input是对象,调用valueOf()方法,如果能得到原始数据类型的值,返回这个值。
    4.否则,抛出TypeError错误。

  • PreferredType未提供(default)时
    PreferredType预设类型为Number,所以先调用valueOf(),再调用toString()。

b、valueof()和toString()

valueOf()和toString()是Object上的两个方法,但是在JS中,可能会根据Object之间的差异,返回值有所不同。

  • 普通的Object对象
    **valueOf():**返回对象本身。
    toString():"[object Object]"字符串值,不同的内建对象的返回值是"[object type]"字符串,"type"指的是对象本身的类型识别,例如Math对象是返回"[object Math]"字符串。但有些内建对象因为覆盖了这个方法,所以直接调用时不是这种值。(注意: 这个返回字符串的前面的"object"开头英文是小写,后面开头英文是大写)。

利用Object中的toString来进行各种不同对象的判断语法:

Object.prototype.toString.call([])
"[object Array]"

Object.prototype.toString.call(new Date)
"[object Date]"
复制代码

需要配合call,才能得到正确的对象类型值。

  • Array(数组)
    Array(数组)虽然是个对象类型,但它与Object的设计不同,它的toString有覆盖,说明一下数组的valueOf与toString的两个方法的返回值:
    valueOf(): 返回对象本身
    toString(): 相当于用数组值调用join(',')所返回的字符串。也就是[1,2,3].toString()会是"1,2,3",这点要特别注意。

  • Function对象
    Function对象很少会用到,它的toString也有被覆盖,所以并不是Object中的那个toString,Function对象的valueOf与toString的两个方法的返回值:
    valueOf(): 返回对象本身
    toString(): 返回函数中包含的代码转为字符串值。

  • Date对象
    valueOf(): 返回给定的时间转为UNIX时间(自1 January 1970 00:00:00 UTC起算),但是以微秒计算的数字值
    toString(): 返回本地化的时间字符串

例如:

//先看看toString()方法的结果
var a = 3;
var b = '3';
var c = true;
var d = {test:'123',example:123}
var e = function(){console.log('example');}
var f = ['test','example'];

a.toString();// "3"
b.toString();// "3"
c.toString();// "true"
d.toString();// "[object Object]"
e.toString();// "function (){console.log('example');}"
f.toString();// "test,example"



//再看看valueOf()方法的结果
var a = 3;
var b = '3';
var c = true;
var d = {test:'123',example:123}
var e = function(){console.log('example');}
var f = ['test','example'];

a.valueOf();// 3
b.valueOf();// "3"
c.valueOf();// true
d.valueOf();// {test:'123',example:123}
e.valueOf();// function(){console.log('example');}
f.valueOf();// ['test','example']
复制代码

c、五种基本类型的转换

(3)、实例尝试

  1. 运算元其一为字符串,字符串的拼接运算。

    /**
     * 运算元其一为字符串(String)
     */
    console.log('12'+1);            // 121
    console.log('abc'+'def');       // abcdef
    console.log('1'+true);          //1true
    console.log('1'+undefined);     //1undefined
    console.log('1'+null);          //1null
    复制代码
  2. 1+'def'为运算元其一为字符串情况,其余为在没有字符串情况下,运算元其一为数字,做类型转换后相加。

    /**
     * 运算元其一为数字(Number)
     */
    console.log(1+1);            // 2
    console.log(1+'def');       // 1def
    console.log(1+true);          //2
    console.log(1+undefined);     //NaN
    console.log(1+null);          //1
    复制代码
  3. 当数字与字符串以外的,其他原始数据类型直接使用加号运算时,就是转为数字再运算,这与字符串完全无关。

    /**
     * 数字(Number)/字符串(String)以外的原始类型相加
     */
    console.log(true+true);             // 2
    console.log(true+null);             // 1
    console.log(true+undefined);        //NaN
    console.log(undefined+null);        //NaN
    console.log(undefined+undefined);   //NaN
    console.log(null+null);            //0
    复制代码
  4. 空数组+空数组

    console.log([] + []);        //""
    
    两个数组相加,左右运算元先调用valueOf(),返回数组本身,
    调用toString(),返回原始数据类型,即空字符串,作连接操作,
    得到一个空字符串。
    复制代码
  5. 空对象+空对象

    console.log({} + {});        //"[object Object][object Object]"
    
    两个对象相加,左右运算元先调用valueOf(),返回对象本身,
    调用toString(),返回原始数据类型,即对象字符串[object Object],作连接操作,
    得到字符串[object Object][object Object]
    复制代码
  6. 空对象+空数组

    console.log({} + []);        //"[object Object]"
    
    空对象和空数组相加,左右运算元先调用valueOf(),返回对象数组本身,
    调用toString(),返回原始数据类型,即对象字符串[object Object]和"",作连接操作,
    得到字符串[object Object]
    复制代码
  7. +{ } 或者 +[ ]

    console.log(+[]);     // 0
    console.log(+{});     // NaN
    console.log(+null);     //0
    console.log(+true);     //1
    console.log(+undefined);     //NaN
    
    一元加号运算时,唯一的运算元相当于强制求出数字值的Number([])运算。
    复制代码

2、其他运算

除了加法运算符,其他算术运算符(比如减法、除法和乘法)都不会发生重载。它们的规则是:所有运算子一律转为数值,再进行相应的数学运算。

参考链接 :www.jianshu.com/p/f4f2a57b0…

3、关于js的隐式类型转换

  • 类型转换表

  • 数学运算符中常见的隐式类型转换

         1、减乘除 在进行运算时 若不是Number类型,则需要将其转为Number类型之后,然后再操作;

         2、加法

  • 当一侧有字符串,被识别为字符串拼接,并会优先将另一侧转换为字符串类型。

  • 当一侧为Number类型,另一侧为原始类型,则将原始类型转换为Number类型。

  • 当一侧为Number类型,另一侧为引用类型,将引用类型和Number类型转换成字符串后拼接。

  • 逻辑语句中的隐式类型转换

        1、使用单个变量:如果只有单个变量,会先将变量转换为Boolean值。(这里可参考类型转换表)

        2、使用 == 比较中的5条规则

  • 规则 1:NaN和其他任何类型比较永远返回false(包括和他自己)。

  • 规则 2:Boolean 和其他任何类型比较,Boolean 首先被转换为 Number 类型。

  • 规则 3:StringNumber比较,先将String转换为Number类型。

  • 规则 4:null == undefined比较结果是true,除此之外,nullundefined和其他任何结果的比较值都为false

  • 规则 5:原始类型引用类型做比较时,引用类型会依照ToPrimitive规则转换为原始类型。

  • 牛刀小试

    [] == ![] // true [undefined] == false // true {} == !{} // false {} == {} // false

 js规定 null和undefined宽松相等(==),并且都与自身相等,但和其他值都不相等;

null == null   //true
undefined == undefined  //true
null == undefined  //true

null == 0  //false
null == false  //false
undefined == 0  //false
undefined == false  //false
null == []  //false
null == {}  //false
unfefined == []  //false
undefined == {}  //false

"a" + "b"  // "ab"
"a" + 1    // "a1"
"a" + {}   // "a[object object]"
"a" + []   // "a"
"a" + true  // "atrue"
"a" + null  // "anull"
"a" + undefined // "aundefined"
 
 1 + 2     // 3
 1 + true  // 2
 1 + null  // 1
 true + true   // 2
 true + false  // 1
 true + null   // 1
 false + null  // 0
 
 var c = {
     valueOf(){
         return 1;
     }
 }

 1 + undefined   // NaN
 true + undefined  // NaN
 true + c   // 2
 1 + c   // 2
 
 NaN + 1  // NaN
 NaN + null  // NaN
 
 [] + {}  // "[object object]"
 {} + []  // 0
复制代码

再来一波

[] == 0      //返回结果是 true
![] == 0	 //返回结果是 true
[] == ''     //返回结果是 true
!![] == ''   //返回结果是 false
'' == true   //返回结果是 false

注意:带有!的这种 说明是先要进行逻辑运算符处理的,而不带的需要自己先根据toPrimitive()转换,
[]转换结果为‘’,在转为Number值为0 所以 []==0,其他的同理。
复制代码

参考链接1:chinese.freecodecamp.org/news/javasc…

参考链接2:juejin.cn/post/684490…

文章分类
前端
文章标签