- if(a == 1 && a == 2 && a == 3){
- console.log("我走进来了");
- }
- <!-- 答案 1:-->
- var a = {num:0};
- a.valueOf = function(){
- return ++a.num
- }
- <!-- 答案 2:-->
- var num = 1;
- function a(){
- return num++;
- }
- if(a() == 1 && a() == 2 && a() == 3){
- console.log("我走进来了");
- }
- <!-- 答案 3:-->
- var num = 0;
- Function.prototype.toString = function(){
- return ++num;
- }
- function a(){}
- <!-- 答案 4:-->
- var a = {[Symbol.toPrimitive]: ((i) => () => ++i) (0)};
== 和 ===
宽松相等 == 和严格相等 === 都是来判断两个值是够相等, 但是他们有两个有一个很重要的区别 == 允许在相等比较中进行强制类型转换, 而 === 不允许 那么这也是这道题之所以成为这道题的原因
对象和非对象之间的相等比较
关于 (对象 / 函数 / 数组) 和标量基本类型 (字符串 / 数字 / 布尔值) 之间相等比较, ES5 有下面规定:
如果 Type(x)是字符串或数字, Type(y)是对象, 则返回
x == ToPrimitive(y)
的结果;
如果 Type(x)是对象, Type(y)是字符串或数字, 则返回
ToPromitive(x) == y
的结果
那么 ToPromitive 操作是什么呢?
对象 (包括数组) 会转换为相应的基本类型, ToPromitive 会首先检查该值是否有 valueOf()方法如果有并返回基本类型值, 就使用该值进行强制类型转换如果没有就使用 toString()的返回值 (如果存在) 来进行强制类型转换
如果 valueOf()和 toString()均不返回基本类型值, 会产生 TypeError 错误
那么按照这个规则那么答案一的原理就显而易见了
那么按照这个规则下面代码也可以正常运行
- var a = [3,4]
- a.i = 0;
- a.valueOf = function() {
- return ++a.i
- }
- // 或者
- // a.toString = function() {
- // return ++a.i
- // }
- if(a == 1 && a == 2 && a == 3){
- console.log("我走进来了");
- }
注意: 数组也是对象, 所以也可以赋值属性, 所以 a.i 是正确的写法, 一般不推荐这么做!!
++a, 和 a++
大家可以看到在答案一和答案二中有一个区别是 ++a 和 a++ 那么他们的初始值也是不一样的, 那么这个是为什么呢? 这个就要说到 ++a 和 a++ 的副作用了
大部分的表达式是没有副作用的, 我们来看下下面的代码
- function foo(){
- a = a + 1
- }
- var a = 1
- foo() // 结果值: undefined 副作用: a 的值被改变
再看
- var a = 1
- var b = a++
a++ 首先返回变量 a 的当前值 1, 再将值赋值给 b, 然后将 a 的值加 1:
- var a = 1
- var b = a++
- a // 2
- b // 1
看下面代码
- var a = 1
- a++ // 1
- a // 2
- ++a // 3
- a++ // 3
++ 在前面时, 它的副作用产生在表达式返回结果之前, 而 a++ 的副作用则产生在之后
根据上面的这些原理, 那么也就解释了 num++ 和 a.num++ 和为什么他们的初始值不相同了
Symbol.toPrimitive
这是元编程的里面的东西那么什么是元编程呢?
元编程是针对程序本身的行为进行操作的编程换句话说, 它是为你的程序的编程而进行的编程
元编程关注几点: 代码检视自己, 代码修改自己, 或者代码修改默认的语言行为而使其她代码受影响
那么我们来看 toPrimitive
== 操作符将在一个对象上不使用任何提示来调用 ToPrimitive 操作 -- 如果存在
@@toPrimitive 方法
的话, 将使用 default 被调用
Function.prototype.toString
由于原型链的关系, 方法 a(){}可以调用到 Function 上的 toString()方法 那当然下面的代码也可以使用开发中不要这么做
- var num = 0;
- Object.prototype.toString = function(){
- return ++num;
- }
以上就是这道题的原理解析, 有什么不同的错误请大家指正和提出意见建议
希望大家知其然知其所以然, 也希望社区里关于这些题能给出更多的原理分析和解析, 而不是简单的写出一个答案
愿世界和平!
来源: https://juejin.im/post/5aa1ec40f265da23a228b2e4