@07 July 28, 2024
一、问题
给定一个函数:
const isTrue = a => a == 1 && a == 2 && a == 3
试问:当isTrue传入什么样的a时,isTrue返回的值可以为true?
答:
isTrue({
v: 0,
toString(){
return ++this.v
}
})
//或者
isTrue({
v: 0,
valueOf(){
return ++this.v
}
})
二、解释
从a == 1 && a == 2 && a == 3
看出,a既等于1又等于2又等于3,明显不是一个常量,所以排除基本数据类型(Number、Boolean、String等)。可以肯定a是一个可变的值,每次我们去访问它的时候,一开始我们去访问它的时候,它的值为1,接着递增为2、3。那怎么去实现呢?我们可以看到a的右边是数字类型的,如果a是一个对象,引擎将调用该对象valueOf方法将它转为原始值,因此我们可以重写这个方法,返回让它第一次返回1,第二次返回2,第三次返回3。这样一来a == 1 && a == 2 && c == 3
就为true了。因此可以定义一个对象a:
const a = {
v: 0,
valueOf(){
return ++this.v
}
}
为什么重写toString也可以?
因为如果没有valueOf,那就会调用toString方法
三、本题涉及几个JS的语法知识
-
原始值的定义
除了对象以外,所有类型都定义了表示在语言最低层面的不可变值。我们将这些值称为原始值。(参考:JavaScript 数据类型和数据结构 - JavaScript | MDN (mozilla.org))
-
“==“的语义(参考:相等(==) - JavaScript | MDN (mozilla.org))
- 等号两边类型相同
- 对象 → 比对引用
- 字符串、数字、布尔值、大整型 → 比对值
- 符号(Symbol)比对是否是同一个Symbol
- null和undefined比对为true
- 非原始值的操作数会被转换为原始值。
- 数字与布尔值比对时,1会被转为true,非1被转为false
- 数字和字符串比对时,字符串会被转为数字,如果字符串不是合法的数字,就会转为NaN
- 等号两边类型相同
-
对象的toString和valueOf方法
- toString表示将对象转为字符串
- valueOf表示将对象转为基本数据类型
- 在进行类型转换时
- 如果要转换为数字类型或基本数据类型,会优先调用valueOf方法,没有再调用toString方法。
- 转换为字符串类型时,会优先调用toString方法,没有就调用原生的toString方法(未被重写的toString,如对象返回”[object Object]“)
只重写了valueOf时:
const obj1 = { valueOf: () => 'valueOf' } console.log(obj1 + 100); //输出:valueOf100 console.log(new Error(obj1)) //输出:Error: [object Object] console.log(`${obj1}`); //[object Object] console.log(String(obj1)); //输出:[object Object] console.log(obj1 == 'valueOf', obj1 == 'toString'); //true false console.log(obj1 + obj1); //输出:valueOfvalueOf
只重写了toString时:
const obj2 = { toString: () => 'toString' } console.log(obj2 + 100); //输出:toString100 console.log(new Error(obj2)) //输出:Error: toString console.log(`${obj2}`); //输出:toString console.log(String(obj2)); //输出:toString console.log(obj2 == 'valueOf', obj2 == 'toString'); //false true console.log(obj2 + obj2); //输出:toStringtoString
重写了valueOf和toString时:
const obj3 = { valueOf: () => 'valueOf', toString: () => 'toString' } console.log(obj3 + 100); //输出:valueOf100 console.log(new Error(obj3)) //输出:Error: toString console.log(`${obj3}`); //输出:toString console.log(String(obj3)); //输出:toString console.log(obj3 == 'valueOf', obj3 == 'toString'); //true false console.log(obj3 + obj3); //输出:valueOfvalueOf
参考链接:
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/toString
- https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf
- toString()和valueOf()函数调用和优先级-腾讯云开发者社区-腾讯云
- https://www.cnblogs.com/peakleo/p/6248242.html
- 彻底了解toString和valueOf区别-CSDN博客