azl397985856 / fe-interview

宇宙最强的前端面试指南 (https://lucifer.ren/fe-interview)
Apache License 2.0
2.83k stars 260 forks source link

【每日一题】- 2019-08-26 - 如何令a ==1 && a== 2 && a==3 返回true #22

Closed azl397985856 closed 4 years ago

azl397985856 commented 4 years ago

在 JavaScript 中, (a ==1 && a== 2 && a==3) 是否有可能为 true ?

BrucePhoebus commented 4 years ago

取巧的答案:a是一个对象,每次a的对象都不一样

var a = {
    value: 1,
    valueOf: function()  {
        return this.value++;
    }
}
(a ==1 && a == 2 && a ==3); // true

这里的valueOf为什么会被调用?原因参考==转换规则

  1. 如果一个是null,一个是undefined,则它们相等
  2. 如果一个是数字,一个是字符串,先将字符串转换成数字,然后使用转换后的值进行比较
  3. 如果其中的一个值为true,则转换成1再进行比较;如果其中一个值为false,这转换成0再进行比较
  4. 如果一个值是对象,另一个值是数字或者字符串,则将对象转换成原始值再进行比较。转换成字符串时,会先调用toString(),如果没有toString()方法或者返回的不是一个原始值,则再调用valueOf(),如果还是不存在或者返回不是原始值,则会抛出一个类型错误的异常。返回的原始值会被转换成字符串;如果转换成数字时,也是类似的,不过是会先调用valueOf(),再调用toString(),返回的原始值会被转换成数字
  5. 其他不同类型之间的比较均不相等

所以在这里使用a与这些字符进行比较时会被转换成数字,此时会默认调用字符串的valueOf()方法,我们将这个方法进行重新,用于拦截处理a的值

取巧2:使用getter存储器

var temp = 1;
Object.defineProperty(window, 'a', {
    get: function() { // 每次取值,temp+1
        return this.temp++
    }
});
(a ==1 && a== 2 && a==3); // true
(a ===1 && a === 2 && a ===3); // true

参考:关于如何使(a === 1 && a === 2 && a === 3)返回true问题的思考 网上不少这种问题的回答,基本都是使用对象或其他处理的,例如函数、es6 proxy、拓展数字变量名。。。 应该就是类似这些解决方案了

azl397985856 commented 4 years ago

取巧的答案:a是一个对象,每次a的对象都不一样

var a = {
  value: 1,
  valueOf: function()  {
      return this.value++;
  }
}
(a ==1 && a == 2 && a ==3); // true

这里的valueOf为什么会被调用?原因参考==转换规则

  1. 如果一个是null,一个是undefined,则它们相等
  2. 如果一个是数字,一个是字符串,先将字符串转换成数字,然后使用转换后的值进行比较
  3. 如果其中的一个值为true,则转换成1再进行比较;如果其中一个值为false,这转换成0再进行比较
  4. 如果一个值是对象,另一个值是数字或者字符串,则将对象转换成原始值再进行比较。转换成字符串时,会先调用toString(),如果没有toString()方法或者返回的不是一个原始值,则再调用valueOf(),如果还是不存在或者返回不是原始值,则会抛出一个类型错误的异常。返回的原始值会被转换成字符串;如果转换成数字时,也是类似的,不过是会先调用valueOf(),再调用toString(),返回的原始值会被转换成数字
  5. 其他不同类型之间的比较均不相等

所以在这里使用a与这些字符进行比较时会被转换成数字,此时会默认调用字符串的valueOf()方法,我们将这个方法进行重新,用于拦截处理a的值

  • 同理可以使用toString方法处理,因为字符串转数字类型时会涉及到valueOf()和toString(),道理一样

取巧2:使用getter存储器

var temp = 1;
Object.defineProperty(window, 'a', {
    get: function() { // 每次取值,temp+1
        return this.temp++
    }
});
(a ==1 && a== 2 && a==3); // true
(a ===1 && a === 2 && a ===3); // true

参考:关于如何使(a === 1 && a === 2 && a === 3)返回true问题的思考 网上不少这种问题的回答,基本都是使用对象或其他处理的,例如函数、es6 proxy、拓展数字变量名。。。 应该就是类似这些解决方案了

非常好,有兴趣整理到题解,成为仓库的贡献者么??

BrucePhoebus commented 4 years ago

hello,我是有这方面的兴趣啦!我个人比较喜欢写博客,一直在积累各种技术知识,并且现在一直积极参与各种社区,希望找到自己感兴趣的社区,非常有兴趣成为开源贡献者,只不过没有相关经验,希望能带个入门 QQ:1634372267 微信:ZYK18125742635

------------------ 原始邮件 ------------------ 发件人: "lucifer"notifications@github.com; 发送时间: 2019年9月4日(星期三) 下午2:55 收件人: "azl397985856/fe-interview"fe-interview@noreply.github.com; 抄送: "郑烨锟"1634372267@qq.com;"Comment"comment@noreply.github.com; 主题: Re: [azl397985856/fe-interview] 【每日一题】- 2019-08-26 - 如何令a ==1 && a== 2 && a==3 返回true (#22)

取巧的答案:a是一个对象,每次a的对象都不一样 var a = { value: 1, valueOf: function() { return this.value++; } } (a ==1 && a == 2 && a ==3); // true

这里的valueOf为什么会被调用?原因参考==转换规则

如果一个是null,一个是undefined,则它们相等

如果一个是数字,一个是字符串,先将字符串转换成数字,然后使用转换后的值进行比较

如果其中的一个值为true,则转换成1再进行比较;如果其中一个值为false,这转换成0再进行比较

如果一个值是对象,另一个值是数字或者字符串,则将对象转换成原始值再进行比较。转换成字符串时,会先调用toString(),如果没有toString()方法或者返回的不是一个原始值,则再调用valueOf(),如果还是不存在或者返回不是原始值,则会抛出一个类型错误的异常。返回的原始值会被转换成字符串;如果转换成数字时,也是类似的,不过是会先调用valueOf(),再调用toString(),返回的原始值会被转换成数字

其他不同类型之间的比较均不相等

所以在这里使用a与这些字符进行比较时会被转换成数字,此时会默认调用字符串的valueOf()方法,我们将这个方法进行重新,用于拦截处理a的值

同理可以使用toString方法处理,因为字符串转数字类型时会涉及到valueOf()和toString(),道理一样

取巧2:使用getter存储器 var temp = 1; Object.defineProperty(window, 'a', { get: function() { // 每次取值,temp+1 return this.temp++ } }); (a ==1 && a== 2 && a==3); // true (a ===1 && a === 2 && a ===3); // true

参考:关于如何使(a === 1 && a === 2 && a === 3)返回true问题的思考 网上不少这种问题的回答,基本都是使用对象或其他处理的,例如函数、es6 proxy、拓展数字变量名。。。 应该就是类似这些解决方案了

非常好,有兴趣整理到题解,成为仓库的贡献者么??

— You are receiving this because you commented. Reply to this email directly, view it on GitHub, or mute the thread.

BrucePhoebus commented 4 years ago

认领

azl397985856 commented 4 years ago

认领

done

jackmovestart commented 4 years ago

var a =[1,2,3]; a.join = a.shift; a==1&&a==2&&a==3

BrucePhoebus commented 4 years ago

var a =[1,2,3]; a.join = a.shift; a==1&&a==2&&a==3 问下可以简单说明下原理?这个答案是OK的,但是道理是什么?

jackmovestart commented 4 years ago

var a =[1,2,3]; a.join = a.shift; a==1&&a==2&&a==3 问下可以简单说明下原理?这个答案是OK的,但是道理是什么?

对于数组对象,toString 方法返回一个字符串,该字符串由数组中的每个元素的 toString() 返回值经调用 join() 方法连接(由逗号隔开)组成。可以看到数组 toString 会调用本身的 join 方法,这里把自己的join方法该写为shift,每次返回第一个元素,而且原数组删除第一个值,正好可以使判断成立。这里 == 比较也带来的副作用

BrucePhoebus commented 4 years ago

var a =[1,2,3]; a.join = a.shift; a==1&&a==2&&a==3 问下可以简单说明下原理?这个答案是OK的,但是道理是什么?

对于数组对象,toString 方法返回一个字符串,该字符串由数组中的每个元素的 toString() 返回值经调用 join() 方法连接(由逗号隔开)组成。可以看到数组 toString 会调用本身的 join 方法,这里把自己的join方法该写为shift,每次返回第一个元素,而且原数组删除第一个值,正好可以使判断成立。这里 == 比较也带来的副作用

可以可以,又是骚操作,a每次比较的时候都会调用toString(),然后toString()又会调用join(),join改为shift,这样调用每次都会导致a数组删除第一个值并且返回删除掉的那个值o( ̄▽ ̄)d

var a =[1,2,3];
a.join = a.shift;
console.log(a);             // (3) [1, 2, 3, join: ƒ]
// console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 );   // true
console.log(a == 1);        // true
console.log(a);             // (2) [2, 3, join: ƒ]
console.log(a == 2);        // true
console.log(a);             // [3, join: ƒ]
console.log(a == 3);        // true
console.log(a);             // [join: ƒ]