秋招快要开始了,前端笔试中的坑位-JS隐式转换问题

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

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

=== 和 ==

<mark style="box-sizing: border-box; background: rgb(255, 255, 0); color: rgb(0, 0, 0);">= 叫做严格运算符,对象类型指向地址相同或原始类型( 数值、字符串、布尔值)值相同;</mark>叫做相等运算符,类型不同会进行转化再比较,undefined、null相等,对象类型还是比较引用。<mark style="box-sizing: border-box; background: rgb(255, 255, 0); color: rgb(0, 0, 0);">运算符将原始值和其包装对象视为相等,但</mark>=运算符将它们视为不等。 所有obj.a<mark style="box-sizing: border-box; background: rgb(255, 255, 0); color: rgb(0, 0, 0);">null(相当于obj.a</mark>= 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

第一个,<mark style="box-sizing: border-box; background: rgb(255, 255, 0); color: rgb(0, 0, 0);">左右都是对象,比较引用地址,这个两个不同的实例,肯定不相等啊。 第二个,!的优先级高于</mark>,所以先 [] 是真值,求非当让是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高级前端工程师资料库(总目录)看完学的更加快,知识更牢固。你值得拥有(持续更新)~

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