6道奇怪的js面试题,你能答出几道?

893 阅读3分钟

这是我目前为止见到的一些比较罕见且奇怪的js面试题。 与正常的js面试题不同,这些题看似简单,但是却考察了你对js理解的透彻程度。你能答出几道呢?

第一题

x 为什么值时打印 Hello?

const x = ____;

if(x !== x) {
    console.log('Hello');
}
解答

NaN

这题似乎是老生常谈,NaN 不等于任何值,甚至不等于自身

如果要判断一个值是否为 NaN,可以使用 Number.isNaN(x) 或者 Object.is(x, NaN)


第二题

x 为什么值时打印 Hello?

const x = ____;

if(x === x + 1) {
    console.log('Hello');
}
解答

Infinity

本题答案不唯一,任何大于 Number.MAX_SAFE_INTEGER 的值都有可能产生此效果。


第三题

x 为什么值时打印 Hello?

const x = ____;

if((x + 1 !== 1) && (x + 2 === 2)) {
    console.log('Hello');
}
解答

Number.EPSILON

Number.EPSILON 属性表示 1Number 可表示的大于 1 的最小的浮点数之间的差值。

这么说可能有点难以理解,Number.EPSILON 是 ES6 新加的一个属性,用于解决浮点数精度问题,比如著名的

0.1 + 0.2 !== 0.3

这时候只需要

Math.abs((0.1 + 0.2) - 0.3) < Number.EPSILON;   // true

Number.EPSILON 可以用来规定浮点数 能够接受的误差范围,如果两个浮点数差的绝对值小于 Number.EPSILON,我们就可以假定这两个浮点数是相等的。

因为 2 精度超过了 1, 所以 Number.EPSILON 在计算中精度丢失了,也是 2 + Number.EPSILON === 2的原因。


第四题

x 为什么值时打印 Hello?

const x = ____;

if(x > x) {
    console.log('Hello');
}
解答

const x = {
    value: 0,
    [Symbol.toPrimitive]() {
        return --this.value;
    }
}

本题看上去不太可能,一个值不可能大于自身。

但是js在做数学运算时(比如加减乘除、大小比较)时,如果对象并非 Number 等值类型,js会尝试调用 [Symbol.toPrimitive] 获取它的值类型。

这里我们就可以钻空子,让 x 为一个 object,然后利用它作数学运算的副作用(Side Effects) [Symbol.toPrimitive]时将其每次返回的值递减,这样便造成了 x > xtrue

本题的解法也可以解答出第三题。


第五题

x 为什么值时打印 Hello?

if(!isNaN(x) && x !== x) {
    console.log('Hello');
}
解答

Object.defineProperty(globalThis, 'x', {
    get() {
        return Math.random();
    }
})

这题似乎是第一题的进化版,但是排除了 xNaN 的可能性,而 x 也必须是 Number 或者可以转成Number的值。并且也没有进行数学运算,所以想要利用 [Symbol.toPrimitive]toString()valueOf() 等副作用方法似乎也不可能。

难道除了 NaN ,还有什么值不等于自身吗?

我们考虑到,x 并没有使用声明方式定义,所以我们完全可以把 x 定义为全局对象的属性。当获取 x 时,相当于隐式调用了 globalThis.x。这边给了我们可乘之机,我们将 xget() 方法每次都返回一个随机值,这样可以保证几乎在任何情况下每次获取到的 x 值都不一样。


第六题

x 为什么值时打印 Hello?

const x = ____;

if(typeof x === 'undefined' && x.length > 0) {
    console.log('Hello');
}
解答

const x = document.all;

什么鬼?如果 x 的类型是 undefinedx 就一定是 undefined 啊,引用 x.length 按照常理肯定会抛出异常不是吗?

难道 typeof 还能被重载?

这里算是js历史遗留的一个后门,document.all 最初是由IE浏览器拥有的,并不属于 W3C 规范范畴,他返回包括 html 自身在内的所有DOM集合。

ECMA规定 document.all 对象拥有内部槽 [[IsHTMLDDA]] , 拥有该槽的对象 boolean 值为 false、并且 typeof 返回 undefined