关于javascript:深度剖析之由浅入深揭秘JavaScript类型转换最全总结篇

28次阅读

共计 11385 个字符,预计需要花费 29 分钟才能阅读完成。

前言

系列首发于公众号『前端进阶圈』,若不想错过更多精彩内容,请“星标”一下,敬请关注公众号最新消息。

深度分析之由浅入深揭秘 JavaScript 类型转换(最全总结篇)

值类型转换

  • 将值从一种类型转换为另一种类型通常称为类型转换,分为 隐式强制类型转换 显示强制类型转换。两者的区别在于是否可直观看出。
  • 如下代码:

    var a = 42;
    
    var b = a + "";         // 隐式强制类型转换
    
    var c = String(a);    // 显式强制类型转换
    
    b; // 42
    c; // 42
  • 上述代码中,对于 b 而言是隐式转换,而对于 c 而言是显示转换。

形象值操作

  • 在值类型转换前咱们先来看看字符串、数字、布尔值之前的根本转换规则。

    toString

  • 该操作,负责解决非字符串到字符串的强制类型转换。
  • 例如:null -> “null”,undefined -> “undefined”, true -> “true”
  • 对于一般对象来说,除非自定义,否则都会调用其外部的 toString() 办法。
  • Array

    • 数组的 toString() 办法通过了重定义,会将所有数组元素用 , 连接起来。

      var a = [1,2,3];
      
      a.toString(); // 1,2,3
  • JSON

    • 工具函数 JSON.stringify() 在将 JSON 对象序列化为字符串时也用到了 toString
  • 对于大多数简略值来说,JSON 字符串与 toString() 的后果基本相同。但对于某一些值来说不同,例如:undefined, function, symbol, 循环援用(对象之间的互相援用,行程一个有限循环),JSON.stringify() 就无奈解决它。
  • 如下代码:

    JSON.stringify(undefined); // undefined
    JSON.stringify(function () {}); // undefined
    
    JSON.stringify([1, undefined, function () {}, 4]); // "[1,null,null,4]"
    JSON.stringify({a: 2, b: function () {}}); // "{"a":2}"
    JSON.stringify([undefined, Object, Symbol("")]);  //'[null,null,null]'
  • 对于蕴含循环援用的对象执行 JSON.stringify() 会出错。但咱们能够通过 toJSON() 办法进行重写。
  • 如下代码:

    // eg1:
    var o = { };
    
    var a = {
    b: 42,
    c: o,
    d: function(){}
    };
    // 在 a 中创立一个循环援用
    o.e = a;
    
    // 循环援用在这里会产生谬误
    // JSON.stringify(a); // TypeError: Converting circular structure to JSON
    
    // 自定义的 JSON 序列化
    a.toJSON = function() {
    // 序列化仅蕴含 b
    return {b: this.b};
    };
    
    JSON.stringify(a); // "{"b":42}"
    
    
    // eg2:
    var a = {val: [1,2,3],
    
    // 可能是咱们想要的后果!toJSON: function(){return this.val.slice( 1);
    }
    };
    JSON.stringify(a); // "[2,3]"
  • 还有对于 JSON.stringify() 的不太为人知的性能:

    • 可向 JSON.stringify() 中传递第二个参数 replacer, 能够是 数组或函数
    • 如果 replacer 为数组, 那它必须为字符串数组,数组中蕴含了要序列化要解决的对象 key, 除此之外的属性则会被疏忽
    • 如果 replacer 为函数,那它会对对象自身调用一次,而后对对象中的每个属性各调用一次,可传递两个参数,键和值。
  • 如下代码:

    var a = {
    b: 42,
    c: "42",
    d: [1,2,3]
    };
    
    // replacer 为数组
    JSON.stringify(a, ["b","c"] ); // "{"b":42,"c":"42"}"
    
    // replacer 为函数
    JSON.stringify(a, function(k,v){if (k !== "c") return v;
    } );
    // "{"b":42,"d":[1,2,3]}"
  • 还有一个可选参数 space,用于指定缩进格局。

    var a = {
    b: 42,
    c: "42",
    d: [1,2,3]
    };
    
    JSON.stringify(a, null, 3);
    // "{
    //    "b": 42,
    //    "c": "42",
    //    "d": [
    //       1,
    //       2,
    //       3
    //    ]
    // }"
  • 总结:

    • 对于字符串,数字,布尔值和 null,后果与 toString() 基本相同。
    • 如果在 JSON.stringify() 的对象中重定义了 toJSON() 办法,那该办法会在字符序列化前调用。

      toNumber

  • 其中 true 转换为 1,false 转换为 0。undefined 转换为 NaN,null 转换为 0。
  • 将值转换时会遵循以下规定:

    • 在应用 Number() 或 toNumber() 办法将一个字符串转换为数字时,如果字符串中呈现非数字字符,则会返回 NaN。

      let obj = {
      // 首先调用
      [Symbol.toPrimitive]() {return 200;},
      // 两头调用
      valueOf() {return 300;},
      // 最初调用
      toString() {return 'Hello';}
      }
      console.log(obj + 200); // 400

      toBoolean

  • 以下这些是假值:

    • undefined
    • null
    • false
    • +0、-0 和 NaN
    • ""
    
    // 假值的布尔强制类型转换后果为 false。
  • 咱们能够这么了解除了以上假值列表意外的值都是真值。

    // eg1:
    var a = new Boolean(false);
    var b = new Number(0);
    var c = new String("");
    console.log(!!(a && b && c)); // true
    
    // eg2:
    var a = 'false';
    var b = '0';
    var c = "''";
    console.log(!!(a && b && c)); // true

    toPromitive

  • 转换规则:

    • 如果查看该值是否有 valueOf 办法,看是否会返回原始值,如果返回值是原始值,则间接应用。否则,就应用 toString 办法,如果 toString 办法返回的是原始值,则间接应用,否则抛出 TypeError 谬误。
    "0" == false; // true
    false == 0; // true
    false == ""; // true
    false == []; // true
    "" == 0; // true
  • == []; // true

  • ~(非) 运算符

    • 对于非运算符的了解:咱们可了解为 ~ 会返回 2 的补码
  • 如下:

    // ~x 大抵等于 -(x + 1)。~42; // -(42 + 1) ==> -43
  • 在 -(x + 1) 中惟一可能失去 0 的 x 值是 -1。也就是如果 x 为 -1 时,~ 与其余一些数字值会返回 false 值,否则返回 true 值。

    // before
    var a = "Hello World";
    
    if (a.indexOf( "lo") >= 0) {   // true
    // 找到匹配!}
    if (a.indexOf( "lo") != -1) {  // true
    // 找到匹配!}
    
    if (a.indexOf( "ol") < 0) {    // true
    // 没有找到匹配!}
    if (a.indexOf( "ol") == -1) {  // true
    // 没有找到匹配!}
    
    // after
    var a = "Hello World";
    
    ~a.indexOf("lo");         // -4   <-- 真值!
    
    if (~a.indexOf( "lo")) {   // true
    // 找到匹配!}
    
    ~a.indexOf("ol");         // 0    <-- 假值!
    !~a.indexOf("ol");        // true
    
    if (!~a.indexOf( "ol")) {  // true
    // 没有找到匹配!}
  • 显示转换为布尔值

    // before
    var a = "0";
    var b = [];
    var c = {};
    
    var d = "";
    var e = 0;
    var f = null;
    var g;
    
    Boolean(a); // true
    Boolean(b); // true
    Boolean(c); // true
    
    Boolean(d); // false
    Boolean(e); // false
    Boolean(f); // false
    Boolean(g); // false
    
    
    
    // after
    var a = "0";
    var b = [];
    var c = {};
    
    var d = "";
    var e = 0;
    var f = null;
    var g;
    
    !!a;    // true
    !!b;    // true
    !!c;    // true
    
    !!d;    // false
    !!e;    // false
    !!f;    // false
    !!g;    // false
  • 在 if() 判断中,如果没有应用 Boolean() 和 !!, 就会主动隐式进行 toBoolean 转换。

    隐式强制类型转换

  • + 运算符既能用于加法运算,也能用于字符串拼接。

    var a = "42";
    var b = "0";
    
    var c = 42;
    var d = 0;
    
    a + b; // "420"
    c + d; // 42
  • S: 如果 + 运算符中其中一个操作数是字符串,则执行字符串拼接,否则执行加法运算。

    隐式强制类型转换为布尔值

  • (1) if (..) 语句中的条件判断表达式。
  • (2) for (.. ; .. ; ..) 语句中的条件判断表达式(第二个)。
  • (3) while (..) 和 do..while(..) 循环中的条件判断表达式。
  • (4) ? : 中的条件判断表达式。
  • (5) 逻辑运算符 ||(逻辑或)和 &&(逻辑与)右边的操作数(作为条件判断表达式)。
  • || 和 &&

    • 他们的 返回值两个操作数中的其中一个

      var a = 42;
      var b = "abc";
      var c = null;
      
      a || b;     // 42
      a && b;     // "abc"
      
      c || b;     // "abc"
      c && b;     // null
  • || 和 && 操作符会对第一个操作数进行条件判断,且会对第一个操作数进行隐式类型转换(会通过 toBoolean 操作),而后再进行条件判断。
  • || 运算符,如果条件判断后果为 true,就返回第一个操作数的后果。如果为 false, 就返回第二个操作数的后果。
  • && 运算符则相同,如果条件判断后果为 true 就返回第二个操作数后果,如果为 false, 就返回第一个操作数的后果。

    a || b;
    // 大抵相当于
    a ? a : b;
    
    a && b;
    // 大抵相当于
    a ? b : a;

    宽松相等 (==) 和严格相等(===)

  • 宽松相等 == 与严格相等 === 都是用于判断两个值是否相等。但他们之间有一个重要的区别,特地是在 判断条件上
  • 在之前的理解和很多文章中很多人这样聊到:== 查看值是否相等,=== 查看值和类型是否相等。这么说听起来蛮有情理,但不够精确。正确的解释应该是: == 容许在相等比拟中进行强制类型转换,而 === 不容许

    两种操作符的性能

  • 依据第一种 (== 查看值是否相等,=== 查看值和类型是否相等) 解释:严格相等(===) 比 宽松相等(==) 仿佛做的事件更多,因为它还要查看值的类型。而第二种(== 容许在相等比拟中进行强制类型转换,而 === 不容许) 解释:宽松相等(==) 仿佛做的事件更多,如果值类型不同还须要进行强制类型转换。
  • 这样下来,有人感觉 == 比 === 慢,实际上的确 == 在强制类型转换的时候须要破费工夫,但这个工夫为奥妙级的 (百万分之一秒)。所以, 在进行比拟两个值类型雷同的状况下,应用 == 与 === 没有什么区别 如果两个值类型不同,这时候就要思考有没有强制类型转换的必要,有就用 ==,没有就用 ===,不须要在乎性能
  • == 和 === 他们都会查看操作数的类型,区别在于操作数类型不同时他们的解决形式的不同。

    字符串和数字之间的相等比拟
    var a = 42;
    var a = "42";
    
    a === b; // false
    a == b; // true
  • a === b 因为没有强制类型转换,所以 a === b 为 false, 也就是 42 和 “42” 不相等。
  • a == b 因为是宽松相等,即当两个值类型不同时,则对其中一个值进行强制类型转换。那如何转换,是转换 a,还是转换 b 呢?
  • ES5 标准 11.9.3.4-5 规定:

    • 如果 Type(x) 为数字,Type(y) 为字符串,则返回 x == toNumber(y) 的后果
    • 如果 Type(x) 为字符串,Type(y) 是数字,则返回 toNumber(x) == y 的后果
  • 所以依据以上规定,”42″ 会被进行 toNumber 转换而后进行相等比拟,所以 42 == 42 为 true。

    其余类型与布尔类型之间的相等比拟
  • == 很容易出错的一个中央就是 true、false 和其余类型之间的相等比拟。

    var a = "42";
    var b = true;
    
    a == b; // false
  • 咱们晓得变量 a 为字符串 “42” 是一个真值,那为什么 a == b 会返回 false 呢?
  • ES5 标准 11.9.3.6-7 规定:

    • 如果 Type(x) 是布尔类型,则返回 toNumber(x) == y 的后果
    • 如果 Type(y) 是布尔类型,则返回 x == toNumber(y) 的后果
  • 所以依据以上规定,Type(b) 为布尔类型,所以会对 b 进行 toNumber 操作,而后就是 true = 1, 依据字符串与数字之间的比拟规定可得出 42 != 1,所以后果为 false。
  • 所以当初你搞懂了吗???
  • “42” 是一个真值没错,但 “42” == true 并没有产生布尔值比拟和强制类型转换。这里并不是 “42” 转换为布尔值,而是 true 进行 toNumber 操作。
  • 所以咱们要搞清 == 对不同类型的组合会怎么解决,== 两边的布尔值会进行 toNumber 操作
  • 所以倡议大家不论什么状况下都不要应用 == true 和 == false 来判断。但对于 === 来说,它不会产生强制类型转换,所以不须要进行 toNumber 操作。

    var a = "42";
    // 不要这样用,条件判断不成立:if (a == true) {// ..}
    
    // 也不要这样用,条件判断不成立:if (a === true) {// ..}
    
    // 这样的显式用法没问题:if (a) {// ..}
    
    // 这样的显式用法更好:if (!!a) {// ..}
    
    // 这样的显式用法也很好:if (Boolean( a)) {// ..}
    null 和 undefined 之间的相等比拟
  • ES5 标准 11.9.3.2-3 规定:

    • 如果 x 为 null, y 为 undefined, 则后果为 true
    • 如果 x 为 undefined, y 为 null, 则后果为 true
  • 在 == 中 null 和 undefined 相等且他们也与本身相等,除此之外不存在这种状况。也就是说 在 == 中的 null 和 undefined 是一回事,可进行隐式的强制类型转换

    var a = null;
    var b;
    
    a == b;     // true
    a == null;  // true
    b == null;  // true
    null == undefined;  // true
    null == null;  // true
    undefined == undefined;  // true
    
    a == false; // false
    b == false; // false
    a == "";    // false
    b == "";    // false
    a == 0;     // false
    b == 0;     // false
  • 所以咱们 可将 null 和 undefined 作为等价来解决

    var a = doSomething();
    
    if (a == null) {// ..}
  • 以上的 if 判断语句只有当 a 为 null 或 undefined 时才成立,除此之外都不成立,蕴含 0, false 和 ”。

    对象与非对象之间的相等比拟
  • 对于对象 (对象、函数、数组) 与根本类型 (字符串、数字,布尔值) 之间的相等比拟。
  • ES5 标准 11.9.3.8-9 规定如下:

    • 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == toPromitive(y) 的后果
    • 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 toPromitive(x) == y 的后果

      var a = 42;
      var b = [42];
      
      a == b; // true
  • [42] 首先调用 toPromitive 形象操作,返回 “42”,变成 “42” == 42,而后又变成 42 == 42,最初二者相等。
比拟少见的状况
  • 如何让同时 a == 1 && a == 2 && a == 3?
  • 其中不能用同时,因为 a = 1 在 a = 2 之前执行,a = 2 在 a = 3 之前执行。
  • 如下代码:

    // 办法一:var a = {
    i: 1,
    [Symbol.toPrimitive]() {return this.i++;}
    };
    if (a == 1 && a == 2 && a == 3) {console.log(a); // {i: 4, valueOf: [Function: valueOf] } 输入 a 对象,留神 i 的值
    }
    
    // 办法二:var a = {
    i: 1,
    valueOf() {return this.i++;},
    };
    if (a == 1 && a == 2 && a == 3) {console.log(a); // {i: 4, valueOf: [Function: valueOf] } 输入 a 对象,留神 i 的值
    }
    // 如果让 a.valueOf() 每次调用都产生副作用,比方第一次返回 1, 第二次返回 2,以此类推,就会产生这种状况。// 办法三:var a = {
    i: 1,
    toString() {return this.i++;},
    };
    if (a == 1 && a == 2 && a == 3) {console.log(a); // {i: 4, valueOf: [Function: valueOf] } 输入 a 对象,留神 i 的值
    }
  • 在 == 隐式强制类型转换中最令人头疼的就是假值得相等比拟。

    "0" == null;           // false
    "0" == undefined;      // false
    "0" == false;          // true -- 晕!"0" == NaN;            // false
    "0" == 0;              // true
    "0" == "";             // false
    
    false == null;         // false
    false == undefined;    // false
    false == NaN;          // false
    false == 0;            // true -- 晕!false == "";           // true -- 晕!false == [];           // true -- 晕!false == {};           // false
    
    ""== null;            // false"" == undefined;       // false
    ""== NaN;             // false"" == 0;               // true -- 晕!""== [];              // true -- 晕!"" == {};              // false
  • == null; // false
  • == undefined; // false
  • == NaN; // false
  • == []; // true — 晕!
  • == {}; // false

  • 以上的这 24 种状况 中有 17 中咱们比拟好了解,但有 7 中不好了解。
  • 如何平安应用 == 操作符呢?

    1. 如果两边的值有 true 或 false, 千万不要应用 ==
    2. 如果两边的值有 []、""、0, 千万不要应用 ==

形象关系比拟

  • 在咱们日常的代码中,可能会存在 a < b 这种状况的判断,但这外面也波及了隐式强制类型转换,有必要要理解一下。
  • 会产生隐式强制类型转换的算法只会针对于 a < b, a = "" > b 会被解决为 b <>
  • ES5 规定:

    • 比拟单方会首先调用 toPromitive,如果后果中呈现非字符串,就依据 toNumber 的规定将单方强制类型转换为数字进行比拟

      // 如下:var a = 42;
      var b = "43";
      a < b; // true 这里为什么会返回 true, 先保留纳闷,前面会解答
      b < a; // false
      
      
      // 再比方:如果比拟单方都是字符串,则依照字母程序进行比拟:var a = ["42"];
      var b = ["043"];
      a < b; // false
      b < a; // true
      
      
      
      // 再比方:如果比拟单方都是字符串, 则会进行 toPromitive 操作
      var a = {b: 42};
      var b = {b: 43};
      a < b; // false
      b < a; // false
      // 因为 a = [object Object], b 也是 [object, Object],所以依照字母程序排序 a < b, b < a 不成立。// 再比方:var a = {b: 42};
      var b = {b: 43};
      a < b; // false
      a == b; // false
      a > b; // false
      a <= b; // true
      a >= b; // true
      
      // 此时你可能会好奇 a < b 和 a == b 都是 false,为什么 a <= b 和 a > b 为 true?// 因为依据规定 a <= b 会被解决为 b < a, 而后将后果反转。(如果没懂,回头看这段实例代码)
  • 下面的后果可能与咱们构想的天壤之别,相等比拟有严格相等,关系比拟却没有严格相等,也就是说 如果要防止 a < b 之间的隐式强制类型转转,就只能确保 a 和 b 为雷同的类型, 或进行显示的强制类型转换。

小结

  1. 值类型转换规定:

    • toString:对于一般对象来说,除非自定义,否则都会调用其外部的 toString() 办法。
    • toNumber: 在应用 Number() 或 toNumber() 办法将一个字符串转换为数字时,如果字符串中呈现非数字字符,则会返回 NaN。
    • toBoolean: 除 undefined、null、false、+0、-0 和 NaN、"" 都为真值
    • toPromitive: 如果查看该值是否有 valueOf 办法,看是否会返回原始值,如果返回值是原始值,则间接应用。否则,就应用 toString 办法,如果 toString 办法返回的是原始值,则间接应用,否则抛出 TypeError 谬误。
  2. 显 / 隐式强制类型转换:

    • 如果 + 运算符中其中一个操作数是字符串,则执行字符串拼接,否则执行加法运算
    • ~(非) 运算符: ~ 会返回 2 的补码, 而 ~x 大抵等于 -(x + 1)

      // ~x 大抵等于 -(x + 1)。~42; // -(42 + 1) ==> -43
  3. || 与 &&:

    • || 和 && 操作符会对第一个操作数进行条件判断,且会对第一个操作数进行隐式类型转换(会通过 toBoolean 操作),而后再进行条件判断。
    • || 运算符,如果条件判断后果为 true,就返回第一个操作数的后果。如果为 false, 就返回第二个操作数的后果
    • && 运算符则相同,如果条件判断后果为 true 就返回第二个操作数后果,如果为 false, 就返回第一个操作数的后果

      a || b;
      // 大抵相当于
      a ? a : b;
      
      a && b;
      // 大抵相当于
      a ? b : a;
  4. 严格相等 (===) 与宽松相等(==) 有一个重要的区别,特地是在判断条件上( 在于对操作数类型不同时他们的解决形式不同):== 容许在相等比拟中进行强制类型转换,而 === 不容许

    • 在两个值类型雷同状况下,应用 == 与 === 没有区别
    • 在两个值类型不同状况下,就要思考是否有没有强制类型转换的必要,有就用 ==, 没有就用 ===
  5. 字符串与数字之间的比拟规定:

    • 如果 Type(x) 为数字,Type(y) 为字符串,则返回 x == toNumber(y) 的后果
    • 如果 Type(x) 为字符串,Type(y) 是数字,则返回 toNumber(x) == y 的后果

      var a = 42;
      var a = "42";
      
      a === b; // false
      a == b; // true
  6. 其余类型与布尔值的比拟规定:(宽松相等(==) 判断时两边的布尔值会进行 toNumber 操作)

    • 如果 Type(x) 是布尔类型,则返回 toNumber(x) == y 的后果
    • 如果 Type(y) 是布尔类型,则返回 x == toNumber(y) 的后果

      var a = "42";
      var b = true;
      
      a == b; // false
      var a = "42";
      // 不要这样用,条件判断不成立:if (a == true) {// ..}
      
      // 也不要这样用,条件判断不成立:if (a === true) {// ..}
      
      // 这样的显式用法没问题:if (a) {// ..}
      
      // 这样的显式用法更好:if (!!a) {// ..}
      
      // 这样的显式用法也很好:if (Boolean( a)) {// ..}
  7. null 与 undefined 的比拟规定:

    • 如果 x 为 null, y 为 undefined, 则后果为 true
    • 如果 x 为 undefined, y 为 null, 则后果为 true

      var a = null;
      var b;
      
      a == b;     // true
      a == null;  // true
      b == null;  // true
      null == undefined;  // true
      null == null;  // true
      undefined == undefined;  // true
      
      a == false; // false
      b == false; // false
      a == "";    // false
      b == "";    // false
      a == 0;     // false
      b == 0;     // false
  8. 所以咱们 可将 null 和 undefined 作为等价来解决

    var a = doSomething();
    
    if (a == null) {// ..}
  9. 对象与非对象之间的相等比拟规定:

    • 如果 Type(x) 是字符串或数字,Type(y) 是对象,则返回 x == toPromitive(y) 的后果
    • 如果 Type(x) 是对象,Type(y) 是字符串或数字,则返回 toPromitive(x) == y 的后果
  10. 宽松相等(==) 的假真值比拟:

    "0" == null;           // false
    "0" == undefined;      // false
    "0" == false;          // true -- 晕!"0" == NaN;            // false
    "0" == 0;              // true
    "0" == "";             // false
    
    false == null;         // false
    false == undefined;    // false
    false == NaN;          // false
    false == 0;            // true -- 晕!false == "";           // true -- 晕!false == [];           // true -- 晕!false == {};           // false
    
    ""== null;            // false"" == undefined;       // false
    ""== NaN;             // false"" == 0;               // true -- 晕!""== [];              // true -- 晕!"" == {};              // false
  11. == null; // false
  12. == undefined; // false
  13. == NaN; // false
  14. == []; // true — 晕!
  15. == {}; // false

  16. 如何平安应用 宽松相等(==) 操作符呢?

    1. 如果两边的值有 true 或 false, 千万不要应用 ==;
    2. 如果两边的值有 []、""、0, 千万不要应用 ==;
  17. 形象关系比拟存在隐式的强制类型转换,通常存在于 a < b, a = "" > b 会被解决为 b <> 判断中,其中一个很重要的点是,会将后果反转
  18. 如何躲避掉上述隐式的强制类型转换

    • 确保 a 和 b 为雷同的类型, 或进行显示的强制类型转换。
  19. 如何让同时 a == 1 && a == 2 && a == 3?

    • 其中不能用同时,因为 a = 1 在 a = 2 之前执行,a = 2 在 a = 3 之前执行。

      // 办法一:var a = {
      i: 1,
      [Symbol.toPrimitive]() {return this.i++;}
      };
      if (a == 1 && a == 2 && a == 3) {console.log(a); // {i: 4, valueOf: [Function: valueOf] } 输入 a 对象,留神 i 的值
      }
      
      // 办法二:var a = {
      i: 1,
      valueOf() {return this.i++;},
      };
      if (a == 1 && a == 2 && a == 3) {console.log(a); // {i: 4, valueOf: [Function: valueOf] } 输入 a 对象,留神 i 的值
      }
      // 如果让 a.valueOf() 每次调用都产生副作用,比方第一次返回 1, 第二次返回 2,以此类推,就会产生这种状况。// 办法三:var a = {
      i: 1,
      toString() {return this.i++;},
      };
      if (a == 1 && a == 2 && a == 3) {console.log(a); // {i: 4, valueOf: [Function: valueOf] } 输入 a 对象,留神 i 的值
      }

特殊字符形容:

  1. 问题标注 Q:(question)
  2. 答案标注 R:(result)
  3. 注意事项规范:A:(attention matters)
  4. 详情形容标注:D:(detail info)
  5. 总结标注:S:(summary)
  6. 剖析标注:Ana:(analysis)
  7. 提醒标注:T:(tips)

    往期举荐:

  8. 前端面试实录 HTML 篇
  9. 前端面试实录 CSS 篇
  10. JS 如何判断一个元素是否在可视区域内?
  11. Vue2、3 生命周期及作用?
  12. 排序算法:QuickSort
  13. 箭头函数与一般函数的区别?
  14. 这是你了解的 CSS 选择器权重吗?
  15. JS 中 call, apply, bind 概念、用法、区别及实现?
  16. 罕用位运算办法?
  17. Vue 数据监听 Object.definedProperty()办法的实现
  18. 为什么 0.1+ 0.2 != 0.3,如何让其相等?
  19. 聊聊对 this 的了解?
  20. JavaScript 为什么要进行变量晋升,它导致了什么问题?

    最初:

  21. 欢送关注『前端进阶圈』公众号,一起摸索学习前端技术 ……
  22. 公众号回复 加群 或 扫码, 即可退出前端交流学习群,一起高兴摸鱼和学习 ……
  23. 公众号回复 加好友,即可添加为好友

正文完
 0