this.name = name;
} }
const best = new Person("Kobe"); console.log(best); // log: Person {name: "Kobe"} console.log(best.toString()); // log: [object Object] console.log(best.valueOf()); // log: Person {name: "Kobe"} console.log(best + "GiGi"); // log: [object Object]GiGi
| | |
| --- | --- |
| best | Person |
| best.toString() | [object Object] |
| best.valueOf() | Person |
| best + 'GiGi' | [object Object]GiGi |
从上面的输出我们可以观察到一个细节,`toString()`输出的是`[object Object]`,而`valueOf()`输出的是`Person`对象本身,而当运算到`best + 'GiGi'`的时候竟然是输出了`[object Object]GiGi`,我们可以初步推断是对象调用的`toString()`方法得到的字符串进行计算的,难道是运算符`+`的鬼斧神工吗?
为了验证我们上一步的推断,我们稍微做一点改变,把 `valueOf` 方法进行一次复写:
class Person { constructor(name) { this.name = name; } // 复写 valueOf 方法 valueOf() { return this.name; } }
| | |
| --- | --- |
| best | Person |
| best.toString() | [object Object] |
| best.valueOf() | Person |
| best + 'GiGi' | KobeGiGi |
这次跟上面只有一处产生了不一样的结果,那就是最后的`best + 'GiGi'`前后两次结果在复写了`valueOf()`方法之后发生了改变,从中我们可以看出来,对象的本质其实没有发生根本的改变,但是当它被用作直接运算的时候,它的值是从复写的`valueOf()`中获取的,并继续参与后续的运算。
当然不要忘了我们还有个`toString()`方法,所以我们也复写它,看看结果会不会也受影响:
class Person {
constructor(name) {
this.name = name;
}
valueOf() {
return this.name;
}
toString() {
return Bye ${this.name};
}
}
| | |
| --- | --- |
| best | Person |
| best.toString() | Bye Kobe |
| best.valueOf() | Kobe |
| best + 'GiGi' | KobeGiGi |
我们发现 `best + 'GiGi'`还是没有发生任何改变,还是使用我们上一次复写`valueOf()`的结果
其实我们重写了`valueOf`方法,不是一定调用`valueOf()`的返回值进行计算的。而是`valueOf`返回的值是基本数据类型时才会按照此值进行计算,如果不是基本数据类型,则将使用`toString()`方法返回的值进行计算。
class Person {
constructor(name) {
this.name = name;
}
valueOf() {
return this.name;
}
toString() {
return Bye ${this.name};
}
}
const best = new Person({ name: "Kobe" });
console.log(best); // log: Person name: {name: "Kobe"} console.log(best.toString()); // log: Bye [object Object] console.log(best.valueOf()); // log: Person {name: "Kobe"} console.log(best + "GiGi"); // log: [object Object]GiGi
| | |
| --- | --- |
| best | Person |
| best.toString() | Bye [object Object] |
| best.valueOf() | {name: "Kobe"} |
| best + 'GiGi' | Bye [object Object]GiGi |
看上面的例子,现在传入的`name`是一个对象`new Person({ name: "Kobe" })`,并不是基本数据类型,所以当执行加法运算的时候取`toString()`方法返回的值进行计算,当然如果没有`valueOf()`方法,就会去执行`toString()`方法。
所以铺垫了这么久,我们就要揭开答案,我们正是使用上面这些原理去解答这一题:
class A { constructor(value) { this.value = value; } toString() { return this.value++; } } const a = new A(1); if (a == 1 && a == 2 && a == 3) { console.log("Hi Eno!"); }
这里就比较简单,直接改写`toString()`方法,由于没有`valueOf()`,当他做运算判断`a == 1`的时候会执行`toString()`的结果。
class A { constructor(value) { this.value = value; } valueOf() { return this.value++; } } const a = new A(1); if (a == 1 && a == 2 && a == 3) { console.log("Hi Eno!"); }
当然,你也可以不使用`toString`,换成`valueOf`也行,效果也是一样的:
class A { constructor(value) { this.value = value; } valueOf() { return this.value++; } }
const a = new A(1); console.log(a); if (a == 1 && a == 2 && a == 3) { console.log("Hi Eno!"); }
所以,当一个对象在做运算的时候(比如加减乘除,判断相等)时候,往往会有`valueOf()`或者`toString`的调用问题,这个对象的变量背后通常隐藏着一个函数。
当然下面这题原理其实也是一样的,附上解法:
// 设置一个函数输出一下的值 f(1) = 1; f(1)(2) = 3; f(1)(2)(3) = 6;
function f() { let args = [...arguments]; let add = function() { args.push(...arguments); return add; }; add.toString = function() { return args.reduce((a, b) => { return a + b; }); }; return add; } console.log(f(1)(2)(3)); // 6
当然还没有结束,这里还会有一些特别的解法,其实在使用对象的时候,如果对象是一个数组的话,那么上面的逻辑还是会成立,但此时的`toString()`会变成隐式调用`join()`方法,换句话说,对象中如果是数组,当你不重写其它的`toString()`方法,其默认实现就是调用数组的`join()`方法返回值作为`toString()`的返回值,所以这题又多了一个新的解法,就是在不复写`toString()`的前提下,复写`join()`方法,把它变成`shift()`方法,它能让数组的第一个元素从其中删除,并返回第一个元素的值。
class A extends Array { join = this.shift; } const a = new A(1, 2, 3); if (a == 1 && a == 2 && a == 3) { console.log("Hi Eno!"); }
我们的探寻之路还没结束,细心的同学会发现我们题目是`如何让(a===1&&a===2&&a===3)的值为 true`,但是上面都是讨论宽松相等`==`的情况,在严格相等`===`的情况下,上面的结果会不同吗?
答案是不一样的,你们可以试试把刚才上面的宽松条件改成严格调试再试一次就知道结果了。
class A extends Array { join = this.shift; } const a = new A(1, 2, 3); // == 改成 === 后: if (a === 1 && a === 2 && a === 3) { console.log("Hi Eno!"); // Hi Eno!此时再也没出现过了 } 前端资料汇总
我一直觉得技术面试不是考试,考前背背题,发给你一张考卷,答完交卷等通知。
首先,技术面试是一个 认识自己 的过程,知道自己和外面世界的差距。
更重要的是,技术面试是一个双向了解的过程,要让对方发现你的闪光点,同时也要 试图去找到对方的闪光点,因为他以后可能就是你的同事或者领导,所以,面试官问你有什么问题的时候,不要说没有了,要去试图了解他的工作内容、了解这个团队的氛围。 找工作无非就是看三点:和什么人、做什么事、给多少钱,要给这三者在自己的心里划分一个比例。 最后,祝愿大家在这并不友好的环境下都能找到自己心仪的归宿。