如何让 a == 1 && a == 2 && a == 3 成立
Posted 前端筱悦
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何让 a == 1 && a == 2 && a == 3 成立相关的知识,希望对你有一定的参考价值。
在javascript中,让"a == 1 && a == 2 && a == 3"成立,这听起来像是一个不可能的任务。毕竟,a要么等于1、2、3中的一个,要么不等于任何一个。但是,有一个奇怪的技巧可以让这个条件成立。在这篇文章中,我们将探讨这个技巧,并深入研究背后的原理。
首先,让我们看一下条件"a == 1 && a == 2 && a == 3"的含义。它意味着什么?它意味着a必须等于1、2和3。但是,这是不可能的,因为a只能有一个值。所以,我们需要一种方法来欺骗JavaScript,让它认为a实际上等于1、2和3。下面是一个实现这个目标的方法:
var a =
i: 1,
toString: function()
return a.i++;
;
if (a == 1 && a == 2 && a == 3)
console.log("条件成立!");
这段代码看起来很奇怪。我们定义了一个名为a的对象,该对象具有一个属性i和一个toString方法。i的初始值为1,toString方法返回i的值,并将i的值加1。所以,当我们在条件中使用a时,JavaScript会调用a.toString()方法,这会返回i的值,并将i的值加1。这意味着我们可以通过修改i的值来欺骗JavaScript,使它认为a等于1、2和3。
让我们逐步解释这个过程。首先,当我们在条件中使用a时,JavaScript会尝试将a转换为布尔值。因为a是一个对象,JavaScript会调用a.valueOf()方法,该方法返回对象本身,因为对象是真值。然后,JavaScript会调用a.toString()方法,该方法返回i的值,即1。所以,我们现在有一个等式:
if (1 == 1 && a == 2 && a == 3)
console.log("条件成立!");
下一步,JavaScript会再次调用a.toString()方法,该方法返回i的值,即2。现在,我们有一个等式:
if (1 == 1 && 2 == 2 && a == 3)
console.log("条件成立!");
最后,JavaScript再次调用a.toString()方法,该方法返回i的值,即3。现在,我们有一个等式:
if (1 == 1 && 2 == 2 && 3 == 3)
console.log("条件成立!");
这个等式是真的,所以条件成立了!我们成功地欺骗了JavaScript,让它认为a等于1、2和3。
但是,这个技巧背后的原理是什么?为什么我们可以通过修改toString方法来改变对象的值?这涉及到JavaScript中的类型转换和对象属性访问的机制。
首先,让我们看一下JavaScript中的类型转换。在JavaScript中,有两种类型转换:显式转换和隐式转换。显式转换是通过调用类型转换函数来执行的,如Number()、String()和Boolean()。隐式转换是在需要不同类型的值时自动发生的,例如将字符串与数字相加时,JavaScript会将字符串转换为数字。
隐式转换在我们的例子中起了关键作用。当我们将a与数字1、2和3进行比较时,JavaScript将调用a.valueOf()和a.toString()方法,这是隐式转换发生的结果。
其次,让我们看一下对象属性访问的机制。在JavaScript中,有两种访问对象属性的方法:点表示法和方括号表示法。点表示法是通过对象名和属性名之间的点号来访问属性的,例如obj.property。方括号表示法是通过对象名和属性名之间的方括号来访问属性的,例如obj['property']。这两种方法在访问属性时的行为略有不同。
点表示法要求属性名是一个有效的标识符,即它不能包含空格或运算符。如果属性名不是一个有效的标识符,则必须使用方括号表示法。方括号表示法可以使用任何字符串作为属性名,包括包含空格和运算符的字符串。
另一个重要的区别是,方括号表示法可以使用变量作为属性名。例如,如果我们有一个变量name,我们可以使用obj[name]来访问对象的属性,这是点表示法所不能做的。
在我们的例子中,我们使用了一个对象来模拟a的值。这个对象具有一个名为i的属性,它的值是1。我们还为对象定义了一个toString方法,该方法返回i的值,并将i的值加1。因为我们使用了方括号表示法来访问对象的属性,我们可以使用变量i作为属性名,这使得我们可以通过修改i的值来改变对象的属性值。
综上所述,我们成功地利用了JavaScript中的类型转换和对象属性访问机制来欺骗JavaScript,让它认为a等于1、2和3。这个技巧虽然看起来很奇怪,但它展示了JavaScript中一些有趣而强大的机制。在编写JavaScript代码时,理解这些机制可以帮助我们更好地掌握这门语言。
那么,如何将这些机制应用到我们的问题中呢?下面是一个实现这个问题的代码:
const a =
i: 1,
toString: function ()
return this.i++;
;
if (a == 1 && a == 2 && a == 3)
console.log('a == 1 && a == 2 && a == 3');
在这个代码中,我们定义了一个对象a,它有一个名为i的属性,初始值为1。我们还为这个对象定义了一个toString方法,这个方法会将i的值加1,并返回i的旧值。这就是我们在前面讨论的利用对象属性访问机制的方法。
然后,我们在if语句中比较a是否等于1、2和3。在这个比较中,JavaScript会将a转换为字符串类型。由于a是一个对象,JavaScript会调用a的toString方法来执行转换。在每次调用toString方法时,i的值会加1,因此第一次调用返回1,第二次调用返回2,第三次调用返回3。
当a与数字1、2和3进行比较时,它们都是字符串类型,因此JavaScript将它们转换为数字类型。由于字符串"1"、"2"和"3"都可以转换为数字1、2和3,所以比较结果为真,if语句的代码块被执行。
这就是我们如何使用类型转换和对象属性访问机制欺骗JavaScript,让a等于1、2和3。当然,这并不是一种好的编程实践。这个技巧容易让代码变得难以理解和维护,并且在不同的JavaScript引擎中可能会产生不同的结果。在编写实际的应用程序时,我们应该避免使用这种技巧,而是使用更清晰和易于理解的代码。
如何让 a == 1 && a == 2 && a == 3同时成立?
简述
看到这个问题是不是觉得很神奇,其实只要利用一点Java的语法特性就能解决问题。
1、解决思路:
Java专家组发现,Integer对象初始化的大部分数据介于-128~127之间,因此Integer对小数据(-128~127)预置了缓存,以此来提升大部分情况下实例化一个Integer的性能。其解决办法是,在jvm初始化的时候,数据-128~127之间的数字便被缓存到了本地内存中,如果初始化-128~127之间的数字,会直接从内存中取出,不需要新建一个对象,而这个数据被缓存在Integer的内部类IntegerCache中。所以我们通过获取Integer内部类IntegerCache,也就是缓存-128~127的类,并将索引为129(也就是1)的对象赋值给130(2)、131(3),此时当我们从Integer中去取值的时候就会发现1 == 2 == 3。
2、Integer内部类IntegerCache源码
源码示例:
/**
* IntegerCache缓存了-128~127
*/
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
}
}
high = h;
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
}
private IntegerCache() {}
}
3、具体实现
代码示例:
package com.lizba.p3;
import java.lang.reflect.Field;
/**
* <p>
* a == 1 && a == 2 && a == 3示例代码
* </p >
*
* @Author: Liziba
* @Date: 2021/6/3 17:19
*/
public class IntegerTest {
public static void main(String[] args){
try {
Class<?>[] declaredClasses = Integer.class.getDeclaredClasses();
Class<?> integerCache = declaredClasses[0];
Field f = integerCache.getDeclaredField("cache");
f.setAccessible(true);
Integer[] cache = (Integer[]) f.get(integerCache);
System.out.println(cache[129]);
System.out.println(cache[130]);
System.out.println(cache[131]);
cache[130] = cache[129];
cache[131] = cache[129];
Integer a = 1;
// true
if (a == (Integer) 1 && a == (Integer) 2 && a == (Integer) 3) {
System.out.println(true);
}
// true
if (a == Integer.valueOf(1) && a == Integer.valueOf(2) && a == Integer.valueOf(3)) {
System.out.println(true);
}
// 无输出
if (a == new Integer(1) && a == new Integer(2) && a == new Integer(3)) {
System.out.println(true);
}
System.out.println(cache[129]);
System.out.println(cache[130]);
System.out.println(cache[131]);
} catch (Exception e) {
e.printStackTrace();
}
}
}
查看输出结果
4、注意点
如下三个为什么前两个为true,最后一个为false呢?
// true
if (a == (Integer) 1 && a == (Integer) 2 && a == (Integer) 3) {
System.out.println(true);
}
// true
if (a == Integer.valueOf(1) && a == Integer.valueOf(2) && a == Integer.valueOf(3)) {
System.out.println(true);
}
// 无输出
if (a == new Integer(1) && a == new Integer(2) && a == new Integer(3)) {
System.out.println(true);
}
这个答案我们通过源码来揭晓:
当我们通过new关键字来构造一个Integer时,此时是重新在JVM中实例化的一个对象,因此对象地址是不相等的。
/**
* The value of the {@code Integer}.
*
* @serial
*/
private final int value;
/**
* Constructs a newly allocated {@code Integer} object that
* represents the specified {@code int} value.
*
* @param value the value to be represented by the
* {@code Integer} object.
*/
public Integer(int value) {
this.value = value;
}
而当我们使用Integer.valueOf(int),-128~127的值会从IntegerCache中获取,此时返回的是同一个对象,地址是相等的。
// -128~127从IntegerCache中获取
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
5、总结
这些知识点都是用来考验一个开发者对JDK特性的熟练程度和平时的积累,有时候要是问上了也是有用的,或者也给我们在实际开发中做数据预热来提升服务的性能,带来了一定的思考价值。
有经典,有干货,微信搜索【李子捌】关注这个傻瓜式坚持的程序员。
以上是关于如何让 a == 1 && a == 2 && a == 3 成立的主要内容,如果未能解决你的问题,请参考以下文章
如何让 a == 1 && a == 2 && a == 3同时成立?
前端面试 JavaScript— 如何让if(a == 1 && a == 2)条件成立?