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

  • 所有的对象在布尔上下文(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. mysqldumpslow基本使用

    参数解释 -s, 是表示按照何种方式排序 c: 访问计数 l: 锁定时间 r: 返回记录 t: 查询时间 al:平均锁定时间 ar:平均返回记录数 at:平均查询时间 -t, 是top n的意思,即为 ...

  2. Linux Centos7之由Python2升级到Python3教程

    1.先查看当前系统Python版本,默认都是Python2.7,命令如下: [root@localhost gau]# python -V Python 2.7.5 2.安装Python3,安装方法很 ...

  3. 使用EFCore连接Oracle数据库时出现的问题

    问题 System.TypeLoadException: Method 'Create' in type 'Oracle.EntityFrameworkCore.Infrastructure.Inte ...

  4. __new__() to create it, and __init__() to customize it 类方法 实例方法

    https://docs.python.org/3/reference/datamodel.html#object.__init__

  5. It is thread-safe and idempotent, but not reentrant.

    https://github.com/django/django/blob/master/django/apps/registry.py

  6. Base64原理 bits 3->4 8bits/byte-->6bits/byte

    实践: window.btoa('a')a YQ==abcdef YWJjZGVmabc YWJjab YWI= https://en.wikipedia.org/wiki/Base64 The Ba ...

  7. windows命令行关闭IE代理

    打开:reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\Internet Settings" /v ProxyEnab ...

  8. 关于js中each()使用return不能终止循环

    Jquery的each里面用return false代替break:return ture代替continue $(xx).each(function() { if(xx){ return false ...

  9. LOJ10128. 花神游历各国

    花神喜欢步行游历各国,顺便虐爆各地竞赛.花神有一条游览路线,它是线型的,也就是说,所有游历国家呈一条线的形状排列,花神对每个国家都有一个喜欢程度(当然花神并不一定喜欢所有国家). 每一次旅行中,花神会 ...

  10. 90% 的 Java 程序员都说不上来的为何 Java 代码越执行越快(1)- JIT编译优化

    麻烦大家帮我投一票哈,谢谢 经常听到 Java 性能不如 C/C++ 的言论,也经常听说 Java 程序需要预热,那么其中主要原因是啥呢? 面试的时候谈到 JVM,也有很多面试官喜欢问,为啥 Java ...