zoukankan      html  css  js  c++  java
  • 秋招快要开始了,前端笔试中的坑位-JS隐式转换问题

    我们在写笔试题的时候,经常碰到涉及隐式转换的题目,例如

     "1" + 2
     obj + 1
     [] == ![] 
     [null] == false

    === 和 ==

    = 叫做严格运算符,对象类型指向地址相同或原始类型( 数值、字符串、布尔值)值相同;叫做相等运算符,类型不同会进行转化再比较,undefined、null相等,对象类型还是比较引用。运算符将原始值和其包装对象视为相等,但=运算符将它们视为不等。 所有obj.anull(相当于obj.a= null || obj.a ===undefined)。

    相等运算符就是常常引起JS隐式转换的坑货,它也常常出现在我们的面试题中,不过我们在现实开发中,为了避免不必要的问题要求使用严格运算符,但是了解还是很有必要的。

    想要了解JS隐式转换,就要先从三个知识点下手。

    原始类型

    原始类型(基本类型、基本数据类型、原始数据类型)是一种既非对象也无方法的数据。在 JavaScript 中,共有7种:string,number,bigint,boolean,null,undefined,symbol (ECMAScript 2016新增)。

    falsy 值 (虚值)

    falsy 值 (虚值) 是在 Boolean 上下文中认定为 false 的值,在JavaScript只有 七个 falsy 值。

    1. false false 关键字

    2. 0 数值 zero

    3. 0n 当 BigInt 作为布尔值使用时, 遵从其作为数值的规则. 0n 是 falsy 值.

    4. 一个空字符串 (字符串的长度为零). JavaScript 中的字符串可用双引号 "", 单引号 '', 或 模板字面量 `` 定义。

    5. null null - 缺少值

    6. undefined undefined - 原始值

    7. NaN NaN - 非数值

    特别要说明的是,除了这七个对象全是真值,如new Number 和new Boolean 都是真值。

     let b = new Boolean(false);i
     f(b){
     //会执行到这里。
     }

    四大转换规则

    • toString规则:其他类型的值转换为字符串类型的操作

    • null => "null"

    • undefined => "undefined"

    • true => "true" false=>"false"

    • 10 => "10" "1e21"=>"1e+21"

    • [1,2,3] => "1,2,3"

    • Object对象 => "[Object Object]" 其实是调用toString方法

    • ToPrimitive规则:对象类型数组转为原始类型的操作

    • 当对象类型需要被转为原始类型时,它会先查找对象的valueOf方法,如果valueOf方法返回原始类型的值,则ToPrimitive的结果就是这个值

    • 如果valueOf不存在或者valueOf方法返回的不是原始类型的值,就会尝试调用对象的toString方法,也就是会遵循对象的ToString规则,然后使用toString的返回值作为ToPrimitive的结果

    • Date 是先toString再ValueOf

    • 如果在toString再ValueOf后都不能拿到原始类型,再判断相等、加减时就抛出Uncaught TypeError: Cannot convert object to primitive value

    • ToNumber规则

    • null=> 0

    • undefined => NaN

    • "123"=>123 "12ssd"=>NaN ""=>0

    • false => 0 true=>1

    • 数组、对象ToPrimitive

    • ToBoolean规则

    • js中七个falsy 值 (虚值) 为false,其他都为true

    隐式转换

    有了对上面知识点的认识,我们可以来一举拿下JS隐式转换了。

    • == 的过程(优先换成数字、字符串)

    1. 首先看==前后有没有NaN,有的话都是返回false。NaN不等于任何值,包括其本身

    2. 布尔值会转成数字类型,true转成1,false转成0

    3. 数字和字符串比较,字符串会转成数字

    4. undefined和null除了和undefined或null相等,和其他相比都是false

    5. 数字或者字符串和对象相比,对象使用ToPrimitive规则转换。

    6. 当两个操作数都是对象时,JavaScript会比较其内部引用,当且仅当他们的引用指向内存中的相同对象(区域)时才相等,即他们在栈内存中的引用地址相同。

    • +的过程(优先换成字符串、数字)

    1. 如果至少有一个操作数是对象,它会被转换成原始值(字符串,数字或布尔);

    2. 转换之后,如果至少有一个操作数是字符串类型,第二个操作数会被转换成字符串,并且会执行连接。

    3. 在其他的情况下,两个操作数都会转换成数字并执行算数加法运算。

    • -的过程(转换成数字) 这个就很简单了,全部用ToNumber规则转换成数字

    检测学习成果

    我们根据以上所学看几个笔试题。如果你都知道结果,就不用看我的废解释了。

     [] == [] 
     [] == ![] 
     [null] == false

    第一个,左右都是对象,比较引用地址,这个两个不同的实例,肯定不相等啊。 第二个,!的优先级高于,所以先 [] 是真值,求非当让是false了,转成数字0,==左是对象右是数字,对象使用ToPrimitive规则转换成"",再用ToNumber规则就转成0了,判断为相等。 第三个,[null]ToPrimitive再ToNumber规则就转成0,false也转成0。

     
    var a = 1;
     var b = "3";
      
     var obj1 = {
      i:1,
      toString:function() {
      return "1";
      },
      valueOf:function() {
      return 1;
      }
     };
     var obj2 = {
      i:1,
      toString:function() {
      return "2";
      }
     };
     var obj3 = {
      i:1,
      valueOf:function() {
      return 3;
      }
     };
     var obj = {
      i:1,
     };
     var objE = {
      i:1,
      valueOf:function() {
      return [];
      },
      toString:function() {
      return {};
      }
     };
      
      
     a+b  
     a + obj  
     a + objE 
      
     a+obj1  
     a+obj2  
     a+obj3  
      
     b+obj1  
     b+obj2  
     b+obj3  
      
     a==obj2  
     a==obj1

     

    这道题比较简单你只要熟练掌握我上面说的那几个知识点可以了。下面直接写出结果啦。

     a + b    //"13"
     a + obj  //"1[object Object]"
     a + objE //Uncaught TypeError: Cannot convert object to primitive value
      
     a+obj1  //2
     a+obj2  //"12"
     a+obj3  // 4
      
     b+obj1  //"31"
     b+obj2  //"32"
     b+obj3  //“33”
      
     a==obj2  //false
     a==obj1  //true

     

    最后提一个比较奇葩的题目。

    定义一个变量a,使得下面的表达式结果为true

     a == 1 && a == 2 && a == 3

    这里我简单提示下,a要是一个对象,重写valueOf方法,让它每次隐式转换的时候,调用时i++。

    img

    valueOf()在Object上默认返回的是对象不是原始类型,它会再调用toString。所以只要重写toString也可以。

    如果还是没有思路,你们可以去看下这道题的文章原文从一道面试题说起—js隐式转换踩坑合集。

    更多学习内容观看我的知乎打造全网web高级前端工程师资料库(总目录)看完学的更加快,知识更牢固。你值得拥有(持续更新)~

     

  • 相关阅读:
    《那些年啊,那些事——一个程序员的奋斗史》连载再开感言
    《那些年啊,那些事——一个程序员的奋斗史》——126
    《那些年啊,那些事——一个程序员的奋斗史》连载再开感言
    《那些年啊,那些事——一个程序员的奋斗史》——126
    伍定轩乱语
    《那些年啊,那些事——一个程序员的奋斗史》连载再开感言
    《那些年啊,那些事——一个程序员的奋斗史》——125
    《那些年啊,那些事——一个程序员的奋斗史》——125
    《那些年啊,那些事——一个程序员的奋斗史》——126
    UVA 10127题目描述
  • 原文地址:https://www.cnblogs.com/coderhf/p/13166271.html
Copyright © 2011-2022 走看看