You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
如果 obj 为引用值,且含有 @@toPrimitive 方法(必须是函数),然后
a. 若参数 hint 不存在,令 hint 为 "default";若 hint 为字符串,令 hint 为 "string";否则令 hint 为 "number"。
b. 调用 @@toPrimitive 方法,若其返回值为「原始值」,则返回其值,否则抛出 TypeError。
若参数 hint 不存在,令 hint 为 "number";
当 hint 为 "string",将会先后调用 obj 的 toString()、valueOf() 方法,然后
a. 若 toString 为函数,则调用该方法。若其返回值为「原始值」,则返回该值,否则进行往下。
b. 若 valueOf 为函数,则调用该方法。若其返回值为「原始值」,则返回该值,否则抛出 TypeError。
当 hint 为 "number",将会先后调用 obj 的 valueOf()、toString() 方法,然后
a. 若 valueOf 为函数,就调用该方法。若其返回值为「原始值」,则返回该值,否则进行往下。
b. 若 toString 为函数,就调用该方法。若其返回值为「原始值」,则返回该值,否则抛出 TypeError。
目前 ECMAScript 内置的对象中,只有 Date 和 Symbol 对象有实现其 @@toPrimitive 方法。因此,其他内置对象无非就是根据 valueOf() 或 toString() 方法,得到其转换结果罢了,所以数据类型转换没那么神秘。
consta={[Symbol.toPrimitive](hint){if(hint==='number')return100if(hint==='string')return1000if(this._val===undefined)this._val=0this._val++returnthis._val},}console.log(a==1&&a==2&&a==3)// true,此时 hint 为 "default"console.log(+a)// 100,此时 hint 为 "number"console.log(`${a}`)// 1000,此时 hint 为 "string"
那么,这个 hint 有何规律呢?实在惭愧,我也没太琢磨出来。常见操作的 hint 如下:
constobj={[Symbol.toPrimitive](hint){if(hint==='number'){return1}elseif(hint==='string'){return'string'}else{return'default'}}}console.log(+obj)// 1 hint is "number"console.log(Number(obj))// 1 hint is "number"console.log(`${obj}`)// "string" hint is "string"console.log(String(obj))// "string" hint is "string"console.log(obj+'')// "default" hint is "default"console.log(obj+1)// "default1" hint is "default"
一、背景
上周回家路上,逛社区给我推了这样一道「面试题」,要使其结果为
true
,如何实现?心想不是很简单嘛,考察的是数据类型转换的知识。自实现一个
@@toPrimitive
方法就行,思路很简单。换句话说:实现这样一个方法,在每次调用时返回值增加1
。这样大家闭眼就能写出来了:这道题它的属性名
[Symbol.toPrimitive]
比较少用少见,仅此而已。二、为什么?
这会该有人跳出来吐槽:实际项目中毫无意义,怎么还有面试官问这种傻逼问题?我尝试换位思考,面试官如何在短时间内判断一个候选人的专业技能?通过这些看似奇葩,但综合性较强的题目来考察不失为一种好方法(这题好像不太强)。
加个菜,若要使下面同时成立(临时想出来的),你还会做吗?
其实也很简单,原因是
@@toPrimitive
方法在执行时,会接收到一个hint
参数,其值为default
、string
、number
之一。然后你又能立刻实现出来了:私以为,不能做到举一反三,可能是没有完全掌握相关知识。这样的话,应该找时间去学习一下。
三、进一步深入?
在 ECMAScript 标准中,常见数据类型转换操作有这些:
注意,以上这些并不是 JavaScript 里面具体的方法,而是 ECMAScript 标准中的抽象操作(Abstract Operations)。其实不止这些,ECMAScript 标准还有很多转换方法,更多请看 Type Conversion 章节。如果你是第一次阅读 ECMAScript 标准,难免会有种羞涩难懂的感觉,这里推荐阮一峰老师读懂规范一文,或许有帮助。
就文章开头的题目而言,这里明显就是「ToPrimitive」操作了,给大家看下 ECMAScript 是如何定义(详见):
第一次阅读的时候,也曾感慨「不愧是抽象操作,确实很抽象」,但反复阅读下来之后,也不会很难。
本文将不会逐行逐字进行翻译,此前写那篇文章 数据类型转换详解 已经做了这件事。
以
ToPrimitive(obj, hint)
为例目前 ECMAScript 内置的对象中,只有
Date
和Symbol
对象有实现其@@toPrimitive
方法。因此,其他内置对象无非就是根据valueOf()
或toString()
方法,得到其转换结果罢了,所以数据类型转换没那么神秘。然后,回到文章开头那道题:
令
a
成为一个引用值,比如对象。这时,除了实现@@toPrimitive
方法,还可以改写其toString()
方法去达到目的。但如果要使成立,只能利用
@@toPrimitive
方法会传入hint
参数的特点去实现了:也就是
那么,这个
hint
有何规律呢?实在惭愧,我也没太琢磨出来。常见操作的hint
如下:还有一个略麻烦的方法,在规范中通过 References 中一个一个找到引用此算法的其他操作,然后一层一层去查哪些方法有使用了这种操作,然后总结列出来。
四、其他
此前写过不少与 JavaScript 数据类型相关的文章,如果对此不熟的童鞋,可以看一看:
The end.
The text was updated successfully, but these errors were encountered: