-
Notifications
You must be signed in to change notification settings - Fork 53
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在什么情况下 a === a - 1 ? #1
Labels
Comments
x = 1
a = { x, valueOf: () => a.x }
Object.defineProperty(a, 'x', { get() { return --x } }) 测试: a == a - 1 // true
a == a - 1 // true |
"Infinity" - 1 == "Infinity" |
Open
@justemit 巧妙的用了隐式转换,当 a 是对象时,没有toString 方法,则调用重写后的 valueOf来返回。又用了 defineProperty 拦截 x 属性的 get,妙呀。 var set = 1
Object.defineProperty(window, "a", {
get : function(){
return set++
},
enumerable : true,
configurable : true
}); |
const a = {
times: 0,
valueOf() {
if (this.times & 1) {
return 0;
}
this.times += 1;
return 1;
},
};
console.log(a == a - 1); // true |
妙极了 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
从一道可(变)爱(态)的面试题说起。
上周,我们团队小仙女同学考了我一道面试题,题目是:在什么情况下,a === a - 1。
我也不知道这道题具体来源是谁,但是作为一位沉浸于前端多年的老江湖,这种题目自然是难不倒我的。
当然这道题其实并不难,很多同学应该第一感就能说出一个答案,但是这道题有几个答案呢?你们能不能说出更多答案,甚至是无穷多个答案来?
思考10秒钟再往下看——
第一个答案自然是Infinity,或者说,扩展一下,应该是正负Infinity。
👉🏻 知识点: 在JavaScript里,
Infinity
是一个Number类型的字面量,表示无穷大。当一个Number类型的值,在运算过程中超过了所能表示的最大值,就会得到无穷大。比如,如果我们将一个不为0的正数除以0,得到的结果就是无穷大。
对应的,负数有负无穷大。
如果我们数值运算的值,超过了Number允许表示的范围,也是会得到Infinity。
在JavaScript里,
Number.POSITIVE_INFINITY
和Number.NEGATIVE_INFINITY
两个常量的值,对应正负Infinity。Number.isFinite()
可以判断一个数是否是有穷的,Number.isFinite(n),当n是Number类型时,只有它是正负Infinity或NaN时,返回false,其他情况下返回true。任何一个有穷的数和Infinity的加减运算的结果都是Infinity,而
Infinity === Infinity
,所以:这样我们就得到了两个答案。
💡 但是,要注意,Infinity运算的结果并不总是Infinity,比如我们看下面几种运算:
结论是,Infinity运算也有可能得到NaN,所以需要小心,例如我们的一个计算表达式中,有两个值相乘,一个值有可能很大,另一个值有可能为0时,就需要小心,如果那个很大的值得到Infinity,另一个值恰好为0时,整个表达式的值可能是NaN,这会造成一些bug。
好了,以上是我们的第一个答案:正负Infinity。
接下来,我们看另一个(另一些)答案。
我们给a一个比较大的数值,比如1e45:
有些同学一看,诶,这也行?
这个不但可以,你随便找两个比较大的数,应该都是可以的:
那这又是怎么回事呢?
👉🏻 知识点:在JavaScript里,整数可以被精确表示的范围是从
-2 ** 53 + 1
到2 ** 53 - 1
,即-9007199254740991
到9007199254740991
。超过这个数值的整数,都不能被精确表示。常量
Number.MAX_SAFE_INTEGER
和Number.MIN_SAFE_INTEGER
分别对应9007199254740991
和-9007199254740991
。我们来测试一下:
在chrome下的输出结果是这样的:
看到在 a + i 的值小于等于 9007199254740991 时,输出正常的每次循环加1的结果,到了大于 9007199254740991 后,输出的结果里出现了两次 9007199254740992,少了 9007199254740993 和 9007199254740995。这是因为,超过 9007199254740991 之后,JavaScript的Number类型就没办法精确地表示整数了。因为丢失了精度,所以 9007199254740993 和 9007199254740995 不见了。
我们可以利用这个知识点构造其他一些满足需求的值:
大整数 Big Integer
在最新的Chrome浏览器下,其实我们可以精确表示大整数,TC39的Big Integer提案目前是Stage 3阶段,在Chrome浏览器上已经被支持。
NaN
有同学可能想到NaN,不过NaN与任何值都不相等,包括NaN自身,所以,利用NaN是不可以的:
最后,我们再扩展一下,如果面试题要求的不是
a === a - 1
,而是a == a - 1
,那么有没有其他答案呢?大家可以思考一下,然后在github issue下讨论。The text was updated successfully, but these errors were encountered: