乐趣区

JavaScript-实现a-可以同时-1-2-3

参考自 微信公众号 鱼头的 Web 海洋

关于这道题目:

var a = ?;
if (a == 1 && b == 2 && c == 3) {console.log('yes');
}

学习了网上的几种解法, 如下:

首先,JS 中类型转化只有三种情况:

  • 转换为布尔值
  • 转换为数字
  • 转换为字符串

对象在转换类型的时候, 会执行原生方法 ToPrimitive
其算法如下:
1. 如果已经是 原始类型 , 则返回当前值;
2. 如果需要转 字符串 则先调用 toString 方法, 如果此时是 原始类型 则直接返回, 否则再调用 valueOf 方法并返回结果;
3. 如果不是 字符串 , 则先调用 valueOf 方法, 如果此时是 原始类型 则直接返回, 否则再调用 toString 方法并返回结果;
4. 如果都没有 原始类型 返回, 则跑出 T ypeErro r 类型错误.


解法如下:
1.

var a = {arr: [3, 2, 1],
  valueOf () {console.group('valueOf');
    console.log(this.arr);
    console.groupEnd('valueOf');
    return this.arr.pop();}
}
if (a == 1 && a == 2 && a == 3) {console.log('yes');
}

执行结果:

解析:

1.运行时会先判断 a 的类型, 此时 typeof a === ‘object’, 不是原始类型, 也不是字符串, 因此会先执行 a.valueOf()
2.由于 valueOf()被覆盖了, 因此执行覆盖后的 valueOf(), 每一次都会返回 a.arr 的尾元素, 并更新 a.arr
3.得出三次执行结果为 1, 2, 3, 实现了这个功能


2.

var b = {arr: [3, 2, 1],
  toString () {console.group('toString');
    console.log(this.arr);
    console.groupEnd('toString');
    return this.arr.pop();}
}
if (b == 1 && b == 2 && b == 3) {console.log('yes');
}

执行结果:

解析:

1.运行时会先判断 b 的类型, 此时 typeof a === ‘object’, 不是原始类型, 也不是字符串, 因此会先执行 b.valueOf()
2.b.valueOf()得到的结果是 {arr: Array(3), toString: ƒ}, 不是原始类型. 不是字符串, 因此执行 b.toString()
3.由于 toString()被覆盖了, 因此执行覆盖后的 toString(), 每一次都会返回 b.arr 的尾元素, 并更新 b.arr
3.得出三次执行结果为 1, 2, 3, 实现了这个功能


3.

var c = {arr: [3, 2, 1],
  [Symbol.toPrimitive] () {console.group('Symbol.toPrimitive');
    console.log(this.arr);
    console.group('Symbol.toPrimitive');
    return this.arr.pop();}
}
if (c == 1 && c == 2 && c == 3) {console.log('yes');
}

执行结果:

解析:
先把上面的方法合并, 测试优先级:

var d = {arr: [3, 2, 1],
  valueOf () {console.group('valueOf');
    console.log(this.arr);
    console.groupEnd('valueOf');
    return this.arr.pop();},
  toString () {console.group('toString');
    console.log(this.arr);
    console.groupEnd('toString');
    return this.arr.pop();},
  [Symbol.toPrimitive] () {console.group('Symbol.toPrimitive');
    console.log(this.arr);
    console.group('Symbol.toPrimitive');
    return this.arr.pop();}
}
if (d == 1 && d == 2 && d == 3) {console.log('yes');
}

执行结果:


可以看出会先执行 toPrimitive 这个原生方法, 但是被覆盖了, 所以执行覆盖后的 toPrimitive()


4.

var f = {
    reg: /\d/g,
    valueOf() { return this.reg.exec(123)[0] }
}
if (f == 1 && f == 2 && f == 3) {console.log('yes');
}

执行结果:


解析:

1.exec() 方法在一个指定字符串中执行一个搜索匹配。返回一个结果数组或 null。
2.如果匹配成功,exec() 方法返回一个数组,并更新正则表达式对象的属性。返回的数组将完全匹配成功的文本作为第一项,将正则括号里匹配成功的作为数组填充到后面。如果匹配失败,exec() 方法返回 null。
3.先测试 var reg=/d/g; reg.exec(123); 得到以下结果:


可看到正则进行全局搜索, 判断返回一个数据, 数组的首元素为成功匹配的文本
4. 因此每次进行 f == 1, f == 2, f == 3 时都会返回数组的首元素, 也就是匹配的文本. 由此实现这个功能

参考自 微信公众号 鱼头的 Web 海洋
退出移动版