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

  • 所有的对象在布尔上下文(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

深入剖析JavaScript中的对象与原始值之间的转换机制的更多相关文章

  1. JavaScript中字符串与16进制之间的转换

    一.字符串转换为16进制 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> ...

  2. JavaScript中对象转换为原始值的规则

    JavaScript中对象转换为原始值遵循哪些原则? P52 对象到布尔值对象到布尔值的转换非常简单:所有的对象(包括数字和函数)都转换为true.对于包装对象亦是如此:new Boolean(fal ...

  3. javascript中的对象,原型,原型链和面向对象

    一.javascript中的属性.方法 1.首先,关于javascript中的函数/“方法”,说明两点: 1)如果访问的对象属性是一个函数,有些开发者容易认为该函数属于这个对象,因此把“属性访问”叫做 ...

  4. JavaScript中判断对象类型方法大全1

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  5. JavaScript中判断对象类型的种种方法

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  6. 转 JavaScript中判断对象类型的种种方法

    我们知道,JavaScript中检测对象类型的运算符有:typeof.instanceof,还有对象的constructor属性: 1) typeof 运算符 typeof 是一元运算符,返回结果是一 ...

  7. javascript中字符串对象常用的方法和属性

    前言 字符串是一种非常重要的数据类型,在Java等面向对象编程语言中,它代表对象类型,而在javascript中它却是一种基本数据类型,在开发的领域中,我们经常会碰到,无论是前端还是后台.比如后台验证 ...

  8. Javascript 中判断对象为空

    发现了一个巧妙的实现: 需要检查一个对象(Object)是否为空,即不包含任何元素.Javascript 中的对象就是一个字典,其中包含了一系列的键值对(Key Value Pair).检查一个对象是 ...

  9. JavaScript 中的对象

    JavaScript 中的对象 在 JavaScript 中,对象是数据(变量),拥有属性和方法. JavaScript 中的所有事物都是对象:字符串.数字.数组.日期,等等.   访问对象的属性 访 ...

随机推荐

  1. es6语法详解

    什么是ECMAScript? ECMAScript是浏览器脚本语言的规范,而我们熟知的js语言,如JavaScript则是规范的具体实现.es6就好比Java的jdk. 一.es6语法详解:let声明 ...

  2. 【pytest】(十二)参数化测试用例中的setup和teardown要怎么写?

    还是一篇关于pytest的fixture在实际使用场景的分享. fixture我用来最多的就是写setup跟teardown了,那么现在有一个用例是测试一个列表接口,参数化了不同的状态值传参,来进行测 ...

  3. 浅谈linux IO csy 360技术 2021-01-18

    浅谈linux IO csy 360技术 2021-01-18

  4. hashlib,configparser,logging

    # hash: 算法, 结果是什么? 是内存地址, # print(hash('123')) # dic = {'name':'alex'} # print(hash('name')) # print ...

  5. odoo-nginx 配置之80端口

    1 upstream odoo { 2 server 127.0.0.1:8069 weight=1 fail_timeout=0; 3 } 4 5 upstream odoo-im { 6 serv ...

  6. Oracle数据库查询锁表及解锁

    一.查询哪些表被锁以及查看锁表得会话及操作系统进程ID 其中locked_mode为锁的级别,spid为数据库所在操作系统的进程id select c.sid, c.serial#, c.userna ...

  7. java实现注销登录

    servlet HttpServletRequest request HttpSession session=request.getSession(); session.removeAttribute ...

  8. JavaWeb——过滤器及监听器

    什么是过滤器? 过滤器示意图 Filter是如何实现拦截的? Filter的生命周期 Filter的创建 Filter的销毁 FilterConfig接口 Servlet过滤器有关接口 过滤器配置 F ...

  9. Vagrant基本知识、基本操作

    Vagrant基本知识.基本操作 一.介绍 二.安装Vagrant 三.安装到Windows 四.准备Boxes 五.基本操作 六.Vagrant常用命令 七.Vagrantfile 7.1 box ...

  10. Spring Boot整合Spring Data JPA

    1.JPA 2.Spring Data JPA 3.导入依赖 4.连接数据库 5.实体类 6.Repository 7.测试 1.JPA JPA是Java Persistence API的简称,中文名 ...