“+”号运算符的深入理解(javascript)

这个符号相信我们大家都不陌生,在面试中很容易遇到这个符号的各种骚操作问题,接下来我们就来深入理解分析下这个运算符。

let n = "10",
    m = 10;

console.log(10 + n); //'1010'  示例一 "+"有一边出现字符串「前提:有两边」 则是字符串拼接‘1010’
console.log(+n); // 10  示例二  “+”只有一边,把字符串转为数字 10
console.log(++n); // 11  示例三  “++”和上面一样的,只是会自身累加1
  // i = i+1 i+=1 这两者一样
  // ++i i++ 大部分情况和上面一致,如果i是字符串则和上面不一致「上面会处理成字符串拼接,下面是数学累加」

let res = {} + m;
console.log(res); //[object object]10  示例四
console.log(m + {}); //10[object object]  示例五
console.log(m + new Number(10)); //20  示例六
console.log(m + { name: 10 }); //10[object object]  示例七
console.log({} + m); //[object object]10  示例八

上面用几个比较典型的用法作为示例,那么下面我们来分析总结一下:

  • 前提:"+" 只有一边
    • 会把字符串转为数字 比如示例二、示例三
  • 前提:"+" 有两边
    • "+" 有一边出现字符串,则是字符串拼接 比如示例一
    • "+" 有一边是对象,可能会是字符串拼接
      • 比如:上面的示例四、五、10+{} / 10+{name:11} -> '10[object object]' 、10+[10,20,30] -> '1010,20,30'
      • 特殊情况:
        • 10+new Number(10) -> 20 因为对象没参与运算,浏览器认为对象只是个代码块,只计算+10
        • {}+10/{name:10}+10 -> 10 在consle直接输出就是数字10,和上面原因一样
        • 但下面这种情况也是字符串拼接,因为从语法分析来讲对象参与运算了,就先把对象转成字符串
        • ({}+10)-> '[object object]10' let x = {} + 10; x -> '[object object]10' 这也就是为什么上面代码块里的示例七、八会是字符串拼接的原因

上面的总结分析是只能看到结果,如果想要真正的搞明白那就肯定得知道对象在做数学运算的时候底层原理机制(也是隐式转换的机制):

  • 首先检测对象的 Symbol.toPrimitive 这个属性值,如果有则基于这个值进行计算,如果没有
  • 检测对象的 valueOf() 这个值「原始值:基本类型值」,如果有则基于这个值进行计算,如果没有
  • 就获取对象的 toString() 把其变成字符串,遇到了“+”就是字符串拼接

我们是可以改写对象的Symbol.toPrimitive 这个属性值的,具体怎么操作我们来看看下面的代码。

let obj = {
  [Symbol.toPrimitive](hint) {
    //hint是浏览器识别出来的类型,有三个值 string/bumber/default
    if (hint === "string") {
      return "holle";
    }
    if (hint === "number") {
      return 2;
    }
    return null;
  },
};
console.log(+obj);  //2
console.log(`${obj}`); //"holle"
console.log(obj + "10"); //"null10"

记录下long long ago的面试题的解题思路和方法

/** 题目 var a = ?   if(a == 1 && a == 2 && a == 3){console.log('ok')} **/

/** 第一类的解题思路,就是上面讲到的数据隐式转换会调取的底层方法来做 **/
 
var a = {
    i: 0,
    [Symbol.toPrimitive](){ //这里可以用toString/valueOf
          return ++this.i;
      }
}
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}

var a = [1,2,3]
a.toString = a.shift;
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}

/** 第二类:ES6 数据劫持 (全局上下文中,基于var/function声明变量,也相当于给window设置了属性 window.a=12,所以可以劫持window的这个属性) **/
var i = 0;
Object.defineProperty(window, 'a', {
      get(){
            return ++i;
      }
})
if (a == 1 && a == 2 && a == 3) {
    console.log('OK');
}
posted @ 2020-11-18 16:59  guyigg  阅读(594)  评论(0)    收藏  举报