我们都知道原始值之间是可以互相转换的,但是如果对象转原始值呢?

  • 所有的对象在布尔上下文(context)中均为 true 。所以对于对象,不存在 to-boolean 转换, 只有字符串和数值转换。
  • 数值转换发生在对象相减或应用数学函数时。例如, Date 对象(将在 日期和时间 一章中介 绍)可以相减, date1 - date2 的结果是两个日期之间的差值。
  • 至于字符串转换 —— 通常发生在我们像 alert(obj) 这样输出一个对象和类似的上下文中。

所以,由此可见对象转原始值的情况下大致可以分为数值转换和字符串转换两种,继续往下

什么是hint?

7.1.1.1 OrdinaryToPrimitive ( Ohint )

The abstract operation OrdinaryToPrimitive takes arguments O and hint. It performs the following steps when called:

  1. AssertType(O) is Object.

  2. Asserthint is either string or number.

  3. If hint is string, then

    1. Let methodNames be « "toString", "valueOf" ».
  4. Else,

    1. Let methodNames be « "valueOf", "toString" ».
  5. For each element name of methodNames, doThrow a TypeError exception.

    1. Let method be ? Get(Oname).
    2. If IsCallable(method) is true, then
      1. Let result be ? Call(methodO).
      2. If Type(result) is not Object, return result.

我们在ECMA规范中可以得知,hint是类型转换的变体,不太明白?没关系,继续往下

当在对象到字符串的转换中,hint的值便是"string"

var obj = {name:"谢绝先生"};
var anotherObj = {[obj]:"北有极光"};

当在对象到数字的转换中,hint的值便是"number"

var user = {name:"申屠肆"};
console.log(+user);

对于不确定转换的类型时,它将依据 hint的值为"default"  ,例如,二进制加法 + 可用于字符串(连接),也可以用于数字(相加),所以字符串和数字这两 种类型都可以

var sth = {name:"申屠肆"};
console.log(sth + 2);

接下来,更进一步,为了进行转换,JavaScript 尝试查找并调用三个对象方法:

  1. Symbol.toPrimitive
  2. toString
  3. valueOf

在进行类型转换的时候,首先会去查找个名为 Symbol.toPrimitive 的内建 symbol,像这样

obj[Symbol.toPrimitive] = function(hint) {
// 返回一个原始值
// hint = "string"、"number" 和 "default" 中的一个
}

该函数接收一个参数 hint,hint便是需要进行转换的原始值的类型;通过该函数我们可以完全掌控生成什么样的原始值,从而达到我们想要的目的,举个栗子:

var sth = {
name:"申屠肆",
money:1000,
[Symbol.toPrimitive](hint) {
if (hint == "string")
return this.name;
else
return this.money;
}
} console.log(+sth); // 1000
console.log(`${sth}`); // 申屠肆

古老的 toString / valueOf

如果没有 Symbol.toPrimitive ,那么 JavaScript 将尝试找到它们,并且按照下面的顺序进行 尝试: 对于 “string” hint, toString -> valueOf 。 其他情况, valueOf -> toString 。 这些方法必须返回一个原始值。如果 toString 或 valueOf 返回了一个对象,那么返回值会 被忽略(和这里没有方法的时候相同)。 默认情况下,普通对象具有 toString 和 valueOf 方法: toString 方法返回一个字符串 "[object Object]" 。 Symbol.toPrimitive obj[Symbol.toPrimitive] = function(hint) { // 返回一个原始值 // hint = "string"、"number" 和 "default" 中的一个 } let user = { name: "John", money: 1000, [Symbol.toPrimitive](hint) { alert(`hint: ${hint}`); return hint == "string" ? `{name: "${this.name}"}` : this.money; } }; // 转换演示: alert(user); // hint: string -> {name: "John"} alert(+user); // hint: number -> 1000 alert(user + 500); // hint: default -> 1500 toString/valueOf ● valueOf 方法返回对象自身。

解释一下:

就是说如果hint 为 "string",在没有 Symbol.toPrimitive 的情况下,会优先查找 toString方法;

其他情况下("default","number"),在没有 Symbol.toPrimitive 的情况下,valueOf的优先级高一些;

至于为什么valueOf和toString方法返回的只能是原始值的情况下,valueOf还会返回对象本身,这是一个历史问题;

代码实例:

//Node.js环境下,根目录下 index.js文件

let user = {
name:'Joe',
money:1000,
toString() {
// "hint" 为 string
console.log('执行执行~',this.name);
return this.name;
},
valueOf() {
// hint 为 default 或者 number;
return this.money;
}
} module.exports = user;
//与index.js文件同目录下的测试文件

var assert = require('chai').assert;
var user = require('./index'); describe('对象转原始值',function() {
it('hint 为 string的情况下',function() {
assert( `${user}` === user.name,'成功的触发了toString方法');
});
it('hint 为 default的情况下',function() {
assert( user + 1 === user.money + 1,'成功的触发了valueOf方法');
});
it('hint 为 number的情况下',function() {
assert( +user === user.money,'成功的触发了valueOf方法');
});
})
// package.json
{
"name": "something",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"test":"mocha ./index.test.js"
},
"dependencies": {
"chai": "^4.3.0",
"mocha": "^8.2.1"
}
}

单元测试结果如下:

2021-02-04 23:56:54

最新文章

  1. Android解析服务器Json数据实例
  2. 新浪微博的账号登录及api操作
  3. UML2
  4. 由SimpleAyncTaskExecutor到ListenableFutureTask
  5. BZOJ-2002 弹飞绵羊 Link-Cut-Tree (分块)
  6. spark分片个数的确定及Spark内存错误(GC error)的迂回解决方式
  7. 数往知来 三层架构 <十四>
  8. python flask model 序列化
  9. jquery插件formValidator的ajaxValidator传参数问题
  10. foxmail创建163公司企业邮箱的时候会出现ERR Unable to log on
  11. 编译并使用Lua语言
  12. ios开发——实战OC篇&SQLite3的实际应用
  13. php操作memcache的用法、详解和方法介绍
  14. python3.5学习之路_day1_login
  15. 小强的HTML5移动开发之路(2)——HTML5的新特性
  16. python面对对象(不全解)
  17. [Swift]LeetCode944. 删除列以使之有序 | Delete Columns to Make Sorted
  18. 微信小程序Dom事件实现
  19. phpcms全站搜索
  20. maven assembly plugin使用

热门文章

  1. 量子化学Gaussian技术实战课 2021年4月9号--12号 远程在线教学
  2. centos6-centos7防火墙(iptables-firewalld)设置端口nat转发
  3. Docker的Ubuntu镜像安装的容器无ifconfig命令和ping命令
  4. Mybatis plus 报错Invalid bound statement (not found) 终极解决办法
  5. MySQL的sql_mode模式 解决数据Incorrect DECIMAL value: ‘0’ for column ” at row -1问题
  6. 编写Hello World ts程序
  7. 切片声明 切片在内存中的组织方式 reslice
  8. 从零开始学Java (一)环境配置
  9. Flutter环境搭建遇坑小结(一)
  10. Java 跨域 Json字符转类对象