续:在什么情况下a===a-1 ?
akira-cn opened this issue · 1 comments
还记得上一期我们讨论过在什么情况下a===a-1 ?
当时提了几种情况,我们先复习一下:
- ±Infinity,Infinity与任何有穷数相加减的值均为Infinity
- 较大的数,比如1e45,准确地说,是超过
Number.MAX_SAFE_INTEGER
的数,超过整数精度范围
其实除了利用Number的思路之外,还有其他思(歪)路(招),那么我们今天再讨论更多的情况。
如果在浏览器中,我们可以利用window对象:
let count = 0;
Object.defineProperty(window, 'a', {
get() {
return ++count;
}
});
console.log(a === a - 1); // true
或者按照新的TC39的proposal-global:
let count = 0;
Object.defineProperty(globalThis, 'a', {
get() {
return ++count;
}
});
console.log(a === a - 1); // true
在这里我们利用global scope下直接访问一个变量,会访问global对象上的属性这一特性,以及ES5的accessor property,在global对象上定义a属性为getter,每次获取a的时候,让count+1,于是 a === a - 1
由于每次获取a,a的值都加1,就正好是true了。
不过上面的实现还有个问题,那就是我们在外面定义了一个count变量,这样导致代码实现有side effect,让我这种有强迫症代码洁癖的程序员,感觉不是很好……
所以我们改进一下:
Object.defineProperty(window, 'a', {
get() {
let count = 0;
Object.defineProperty(this, 'a', {
get() {
return ++count;
}
});
return count;
},
configurable: true,
});
console.log(a === a - 1); // true
我们把count变量搬到defineProperty里面,把side effect限制在window.a这个属性里,这样感觉就好多了。
这里的技巧是,在通过getter读取a属性的时候,再一次重新defineProperty这个window.a属性,注意因为要重新defineProperty,我们要将descriptor对象的configurable属性设置为true。
补充
@hax 贺老提到我们可以直接用块级作用域把防止count泄漏出来,这样也挺好的。
{
let count = 0;
Object.defineProperty(globalThis, 'a', {
get() {
return ++count;
}
});
}
那么还有什么办法让a === a - 1
呢?
好吧,我们可以使用禁招,请出with
同学~
with({
count: 0,
get a() {
return ++this.count;
}
}){
console.log(a === a - 1); // true
}
如果说没有不让用with的话,那么这招也是一个办法😄,不过就是这个代码就限制只能在with的block里面了。
好了,以上是另外三种让a === a - 1
成立的办法。
你还有什么其他好办法吗?
欢迎在issue中讨论~
这个双重defineProp感觉没有必要啊,不想把count漏出来我们可以直接用个block包一下就好啦:
{
let count = 0;
Object.defineProperty(globalThis, 'a', {
get() {
return ++count;
}
});
}
另外side effect或者说泄漏了一个状态在 a === a - 1 这种奇异行为面前简直是小巫见大巫,不,是咪咪巫见格格巫!所以我觉得就不用care了 😛