js基础:valueOf、toString、[Symbol.toPrimitive] 方法解析
valueOf 和 toString,我们在日常使用中很少会手动调用,[Symbol.toPrimitive] 就更少了,这里记录一下他们的用途。
是什么 MDN 的说法是:
1 2 3 - valueOf() 方法返回指定对象的'原始值'。 - toString() 方法返回一个表示该对象的字符串。 - [Symbol.toPrimitive]() 当一个对象转换为对应的'原始值'时,会调用此函数。
问题来了, 什么是原始值 ? MDN 的说法是:
In JavaScript, a primitive (primitive value, primitive data type) is data that is not an object and has no methods. There are 7 primitive data types: string, number, bigint, boolean, undefined, symbol, and null.
基本上可以理解为,原始数据、原始值是一种既非对象也无方法的数据,也就是基本数据类型 。
不同类型对象的表现 用途 很少会显式地使用这三个方法(除了 toString 偶尔会用到) 当对象需要被转换成原始值的时候,就会被调用,例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 const obj = { a : 1 , } obj + 1 obj + '' const obj1 = { [obj]: 1 , } alert (obj)
以上这些场景发生的时候,就会隐式调用这三个方法。
优先级 重写三个方法,尝试每个转换场景,看看每个场景下,这三个函数的调用优先级;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const obj = { valueOf ( ) { console .log ('valueOf called' ) return 1 }, toString ( ) { console .log ('toString called' ) return 2 }, [Symbol .toPrimitive ]() { console .log ('Symbol.toPrimitive called' ) return 3 }, } obj > 1 obj + 1 obj + '' !obj obj || true if (obj) { console .log ('haha' ) } const b = { [obj]: 1 , } alert (obj)
结论一:Symbol.toPrimitive 调用优先级最高, 当存在 Symbol.toPrimitive 方法时, 所有转换都会调用它
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 const obj = { valueOf ( ) { console .log ('valueOf called' ) return 1 }, toString ( ) { console .log ('toString called' ) return 2 }, } obj > 1 obj + 1 obj + '' obj * 1 !obj obj || true if (obj) { console .log ('haha' ) } const b = { [obj]: 1 , } alert (obj)
结论二: 比较和算术运算 => valueOf, 作为对象的 key、作为函数参数时 => toString
无聊的运用 有一道面试题,是让 a == 1 && a == 2 && a == 3
成立; 老实说这种题目就是脑残,单纯是为了炫技,实际工作谁要这样写,不会被 n+1 ?
思路是,当使用 == 的时候会发生隐式转换,会调用 valueOf,所以只要劫持 valueOf 即可,解法:
1 2 3 4 5 6 7 8 9 10 class A { constructor (value ) { this .value = value } valueOf ( ) { return this .value ++ } } const a = new A (1 )console .log (a == 1 && a == 2 && a == 3 )
如果是 === 怎么办,a === 1 && a === 2 && a === 3
=== 不会有隐式转换,所以用 defineProperty 劫持就好了
1 2 3 4 5 6 7 8 const value = 1 Object .defineProperty (window , 'a' , { get ( ) { return value++ }, }) console .log (a === 1 && a === 2 && a === 3 )
版权声明: 本博客所有文章除特别声明外,均采用
CC BY 4.0 CN协议
许可协议。转载请注明出处!
Жизнь, как качели - то вверх, то вниз.