- 小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
起因
之前冲浪的时候看到一道题目,问能不能实现这种情况:
a === 0 && a === 1 // true
当时第一时间我的反应是 怎么可能!
之后我仔细想了一下,其实应该是有操作空间的。
思路
- getter
get语法将对象属性绑定到查询该属性时将被调用的函数。
let obj = {
name: 'zebra',
get names(){
return obj.name;
}
};
console.log(obj, obj.name, obj.names); // { name: 'zebra', names: [Getter] } zebra zebra
那按照这个说法,我直接改呢?
let obj = {
staticProp: 0,
get ages(){
return ++obj.staticProp;
}
};
console.log(obj.ages === 1 && obj.ages === 2); // true
怎么感觉希望就在前方啊!!!
我直接A了出来~
let obj = {
staticProp: -1,
get ages(){
return ++obj.staticProp;
}
};
let a = obj.ages;
console.log(a === 1 && a === 2); // false
这不合理啊?为啥啊?
let obj = {
staticProp: -1,
get ages(){
return ++obj.staticProp;
}
};
let a = obj.ages;
console.log(a,a,a,a); // 0 0 0 0
console.log(obj.ages, obj.ages); // 1 2
console.log(a,a,a,a); // 0 0 0 0
这。。。
我再试试?
// ...rest
a += 100;
console.log(typeof obj.ages); // number
console.log(a,a,a,a); // 100 100 100 100
console.log(obj.ages, obj.ages); // 1 2
console.log(a,a,a,a); // 100 100 100 100
好家伙, 我终于破案了,直接指向导致obj.ages直接被保存在一个原始类型的数值中,这导致读取a的时候,根本就不进obj.ages的getter。
裂开了。 G!
Proxy
之前在整理ES6新功能的时候,我记得好像看过Proxy.
Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
不BB, 我们看一个简单的例子。
var obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
return Reflect.get(target, key, receiver);
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
obj.value = 1;
console.log('apple');
console.log(obj);
console.log('pineapple');
console.log(obj.value);
// results -->
// setting value!
// apple
// { value: 1 }
// pineapple
// getting value!
// 1
看上去好像有get那味了,我试试看:
const obj = new Proxy({}, {
get: function (target, key, receiver) {
console.log(`getting ${key}!`);
// return Reflect.get(target, key, receiver);
return ++target[key];
},
set: function (target, key, value, receiver) {
console.log(`setting ${key}!`);
return Reflect.set(target, key, value, receiver);
}
});
obj.value = 0;
console.log(obj.value === 1 && obj.value === 2); // true
和之前的结果相似。
但是也不行。
a === 0的时候就已经固定了a是基础类型了,根本没办法改,所以尝试使用===来的都不行。(不信你试试~)
a == 0 && a == 1
但如果是==的话, 我们就有操作空间了。
在这里给大家复习一下:
相等操作符比较两个值是否相等,在比较前将两个被比较的值转换为相同类型。在转换后(等式的一边或两边都可能被转换),最终的比较方式等同于全等操作符 === 的比较方式。 相等操作符满足交换律。
所以下面这种操作也是可以的:
const obj = {
value: 1,
toString(){
return obj.value
}
};
console.log(obj == 1) // true
那解决方案就很简单了:
const obj = {
value: 0,
toString(){
return ++obj.value
}
};
console.log(obj == 1 && obj == 2) // true
结论
a == 0 && a == 1 行!
a === 0 && a === 1 不行!
以上。