如何实现a===1 && a===2 && a===3返回true?
if(a == 1 && a == 2 && a == 3){
console.log(true);
}
//console.log(a == 1 && a == 2 && a == 3); // true
怎么实现a 能与1,2,3相等呢?下面我整理一些可行的实现方案,希望对你有所帮助。
方案一:重写toString()或valueOf()
let a = {
i: 1,
toString: function () {
return a.i++;
}
}
console.log(a == 1 && a == 2 && a == 3); // true
在做判断时,首先会调用valueOf函数,数组调用valueOf后返回的还是数组本身,就会再次调用toString函数,这里是重写了toString方法,并且return的是a.i++,所以每调用一次,都会在上次的值得基础上自加一次,
所以结果为true。同下:
let a = {
i: 1,
valueOf: function() {
return this.i++;
}
}
console.log(a == 1 && a == 2 && a == 3); // true
这里i定义为1,我们还可以定义正则表达式的方式来实现,比如:
let a = {
reg: /\d/g,
valueOf: function() {
return this.reg.exec(123)[0];
},
};
console.log(a == 1 && a == 2 && a == 3); // true
方案二:数组
数组的toString接口默认调用数组的join方法,重写join方法。定义a为数字,每次比较时就会调用 toString()方法,我们把数组的shift方法覆盖toString即可:
let a = [1,2,3];
a.toString = a.shift;
console.log(a == 1 && a == 2 && a == 3); // true
当然把toString改为valueOf也是一样效果:
let a = [1,2,3];
a. valueOf = a.shift;
console.log(a == 1 && a == 2 && a == 3); // true
结合方案一,我们还可以这样来实现:
let a = {
value:[3,2,1],
valueOf:function() { //或者toString
return this.value.pop();
},
}
console.log(a == 1 && a == 2 && a == 3); // true
方案三:数字变量
我们将数字作为变量名,让a=1,让数字变量=a。
let a = 1;
let 1 = a;
let 2 = a ;
let 3 = a ;
console.log( a ==ᅠ1 && a ==ᅠ2 && a ==ᅠ3 ); // true
方案四:使用Object.defineProperty()
Object.defineProperty()用于定义对象中的属性,接收三个参数:object对象、对象中的属性,属性描述符。属性描述符中get:访问该属性时自动调用,vue3之前的版本实现双向绑定主要就用到了它。
Object.defineProperty(this, 'a', {
get: function () {
return this.value = this.value ? (this.value += 1) : 1
}
})
console.log(a===1 && a===2 && a===3) //true
或者
var _a = 1;
Object.defineProperty(this,'a',{
get:function(){
return _a++
}
})
console.log(a===1 && a===2 && a===3)//true
方案五:使用ES6 Proxy
es6的proxy用于在目标对象的外层搭建了一层拦截,外界对目标对象的某些操作,必须通过这层拦截。我们这里重新定义了属性的读取(get)行为。
let a = new Proxy({ i: 0 }, {
get: (target, name) => name === Symbol.toPrimitive ? () => ++target.i : target[name],
});
console.log(a == 1 && a == 2 && a == 3); // true
方案六:使用Reflect.defineProperty
我们还可以通过Reflect.defineProperty定义一个全局的属性_a,当属性_a被访问的时候就会调用上面定义的getter方法,所以和上面对象的隐式类型转换过程是一样的。
let _a= 1;
Reflect.defineProperty(this, 'a', {
get() {
return _a++;
}
});
console.log(a === 1 && a === 2 && a === 3);//true
方案七:Race Condition(竞态条件)
这是在底层的内存上修改一个变量的值,而不是通过一些所谓的技巧去让上面的表达式成立。而且这在现实的开发中是可能会出现的一种情况。在进入下面的讲解之前,我们需要先了解一些前置的知识点。
SharedArrayBuffer
SharedArrayBuffer对象用来表示一个通用的,固定长度的原始二进制数据缓冲区,类似于 ArrayBuffer对象,它们都可以用来在共享内存上创建视图。与ArrayBuffer不同的是SharedArrayBuffer不能被分离。
Web Worker
Web Worker为Web内容在后台线程中运行脚本提供了一种简单的方法。线程可以执行任务而不干扰用户界面。
此外,他们可以使用XMLHttpRequest执行 I/O (尽管responseXML和channel属性总是为空)。
一旦创建, 一个worker 可以将消息发送到创建它的JavaScript代码, 通过将消息发布到该代码指定的事件处理程序(反之亦然)。详情可以参考使用 Web Workers。
了解了前置的知识我们直接看接下来的代码实现吧。
index.js
// index.js
const worker = new Worker('./worker.js');
const competitors = [
new Worker('./competitor.js'),
new Worker('./competitor.js'),
];
const sab = new SharedArrayBuffer(1);
worker.postMessage(sab);
competitors.forEach(w => {
w.postMessage(sab);
});
worker.js
// worker.js
self.onmessage = ({ data }) => {
const arr = new Uint8Array(data);
Reflect.defineProperty(self, 'a', {
get() {
return arr[0];
},
});
let count = 0;
while (!(a === 1 && a === 2 && a === 3)) {
count++;
if (count % 1e8 === 0) console.log('running...');
}
console.log(`After ${count} times, a === 1 && a === 2 && a === 3 is true!`);
};
competitor.js
// competitor.js
self.onmessage = ({ data }) => {
const arr = new Uint8Array(data);
setInterval(() => {
arr[0] = Math.floor(Math.random() * 3) + 1;
});
};
在开始深入上面的代码之前,你可以在本地运行一下上面的代码,在看到结果之前可能需要等上一小会。
或者直接在这里打开浏览器的控制台看一下运行的结果。
需要注意的是,因为SharedArrayBuffer现在仅在Chrome浏览器中被支持,所以需要我们使用Chrome浏览器来运行这个程序。
运行之后你会在控制台看到类似如下的结果:
158 running...
After 15838097593 times, a === 1 && a === 2 && a === 3 is true!
我们可以看到,运行了15838097593次才出现一次相等。不同的电脑运行这个程序所需要的时间是不一样的,就算同一台机器每次运行的结果也是不一样的。
下面我们来深入的讲解一下上面的代码,首先我们在index.js中创建了三个worker,其中一个worker用来进行获取a的值,并且一直循环进行比较。直到a === 1 && a === 2 && a === 3成立,才退出循环。
另外两个worker用来制造Race Condition,这两个worker一直在对同一个地址的数据进行修改。
在index.js中,我们使用SharedArrayBuffer申请了一个字节大小的一段连续的共享内存。
然后我们通过worker的postMessage方法将这个内存的地址传递给了3个worker。
在这里我们需要注意,一般情况下,通过Worker的postMessage传递的数据要么是可以由结构化克隆算法处理的值(这种情况下是值的复制),要么是Transferable类型的对象(这种情况下,一个对象的所有权被转移,在发送它的上下文中将变为不可用,并且只有在它被发送到的worker中可用)。
更多详细内容可以参考Worker.postMessage() 。
但是如果我们传递的对象是SharedArrayBuffer类型的对象,那么这个对象的代表的是一段共享的内存,是可以在主线程和接收这个对象的Worker中共享的。
在competitor.js中,我们获取到了传递过来的SharedArrayBuffer对象,因为我们不可以直接操作这段内存,需要在这段内存上创建一个视图,然后才能够对这段内存做处理。
我们使用Uint8Array创建了一个数组,然后设置了一个定时器一直对数组中的第一个元素进行赋值操作,赋值是随机的,可以是1,2,3中的任何一个值。
因为我们有两个worker同时在做这个操作,所以就形成了Race Condition。
在worker.js中,我们同样在传递过来的SharedArrayBuffer对象上创建了一个Uint8Array的视图。然后在全局定义了一个属性a,a的值是读取Uint8Array数组的第一个元素值。
然后是一个while循环,一直在对表达式a === 1 && a === 2 && a === 3进行求值,直到这个表达式的值为true,就退出循环。
本文完~
学习更多技能
请点击下方公众号