[对象转原始类型总结] ('' + obj) === `${obj}`? 不一定!

news/2024/7/4 1:10:00

一个小测试, 试试:

let o = {
  valueOf() {
    return 0;
  },
};
console.log(+o); // 0
console.log(1 + o); // 1
console.log(1 - o); // 1
console.log('' + o); // '0'
console.log(`${o}`); // '[object Object]'

结论

  1. 当操作需要一个字符串时, hint=string, 当操作需要一个数字时, hint=number, 当运算符不确定时hint=default.
  2. 如果存在 obj[Symbol.toPrimitive](hint), 就直接调用
  3. 如果 hintstring, 先调用 obj.toString(), 没有再调用 obj.valueOf()
  4. 如果 hintnumber, 先调用 obj.valueOf(), 没有再调用obj.toString()
  5. 如果 hintdefault, Date 按照 hint=string处理, 其它按照 hint=number 处理
  6. 如果 toString 或者 valueOf 返回的不是原始类型, 则忽略该调用, 转向下一个调用, 如果没有下一个调用, 则报错, 但是 toPrimitive 必须返回原始类型, 否则报错

详解

根据上下文, 会有以下转换 hint

string

当操作需要一个字符串时, 对象转换的 hintstring.

// alert(参数是字符串)
alert(obj);
confirm(obj);

// 对象的属性是字符串
anotherObj[obj] = 123;

number

当操作需要一个数字时, 对象转换的 hintnumber.

// 明确转换成数字
Number(obj);
// 转换成数字(非加法)
+obj;
// 数学运算(加法除外)
1 - obj;
1 * obj;
1 / obj;

因为历史原因大小比较的 hint 也是 number

// hint 为 number
obj1 > obj2;

default

当运算符不确定时, 对象转换的 hintdefault.

// 比如加法, 可以是数字相加, 也可以是字符串相加
1 + obj;
'1' + obj;

// == 弱相等比较
// obj == string/number/symbol
obj == '1';
obj == 1;

通常, 内置对象(除了 Date 外), default 转换 和 number 转换是相同的
Date 的 default 转换 和 string 相同 [Date.prototype[@@toPrimitive]](https://developer.mozilla.org...

转换步骤

  1. 如果存在 obj[Symbol.toPrimitive](hint), 就直接调用
  2. 如果 hintstring, 先调用 obj.toString(), 没有再调用 obj.valueOf()
  3. 如果 hintnumber, 先抵用 obj.valueOf(), 没有再调用obj.toString()

example

Symbol.toPrimitive

type primitiveType = null | undefined | number | boolean | string | symbol;
type hintType = 'string' | 'number' | 'default';

obj[Symbol.toPrimitive] = function(hint: hintType): primitiveType {
  console.log(`hint is: ${hint}`);

  return hint == 'string' ? '一个字符串' : 0;
};

toString / valueOf

let user = {
  name: 'John',
  money: 1000,

  // for hint="string"
  toString(): string {
    return `{name: "${this.name}"}`;
  },

  // for hint="number" or "default"
  valueOf(): number {
    return this.money;
  },
};

alert(user); // toString -> {name: "John"}
alert(+user); // valueOf -> 1000
alert(user + 500); // valueOf -> 1500
let obj = {
  toString() {
    return '2';
  },
};

// 加法, 调用 `default` hint, `default` 和 `number` 转换相同,
// 先调用 valueOf 方法, 因为不存在, 所以调用 toString 方法, 返回 "2"
// "2" + 2 = "22"
alert(obj + 2); // "22"

// 存在 valueOf, 所以 2+2 = 4
let obj = {
  toString() {
    return '2';
  },
  valueOf() {
    return 2;
  },
};

alert(obj + 2); // 4
let d = new Date();
let d2 = d.getTime() - 1;

// 加法, 调用 `default` hint, Date 的 `default` 和 `string` 相同
alert(1 + d); // 1Fri Feb 15 2019 20:59:00 GMT+0800 (China Standard Time)

// 减法, 调用 `number` hint
alert(d - d2); // 1

参考文档

  • https://javascript.info/object-toprimitive
  • [Date.prototype[@@toPrimitive]](https://developer.mozilla.org...

文章若有纰漏请大家补充指正,谢谢~~
http://blog.xinshangshangxin.com SHANG 殇

http://www.niftyadmin.cn/n/2745924.html

相关文章

干货|Tomcat 连接数与线程池详解

2019独角兽企业重金招聘Python工程师标准>>> 前言 在使用tomcat时,经常会遇到连接数、线程数之类的配置问题,要真正理解这些概念,必须先了解Tomcat的连接器(Connector)。 在前面的文章 详解Tomcat配置文件s…

virtualbox+vagrant学习-3-Vagrant Share-2-HTTP Sharing

HTTP Sharing Vagrant Share可以创建一个可公开访问的URL端点来访问在Vagrant环境中运行的HTTP服务器。这被称为“HTTP共享”,在使用Vagrant Share时默认启用。 因为这种共享模式创建了一个可公开访问的URL,所以访问方不需要安装Vagrant来查看你的环境。…

java存储_java 存储

1. 寄存器这是最快的存储区,因为它位于不同于其他存储区的地方——处理器内部。但是寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能在程序中感觉到寄存器存在的任何迹象。2. 栈(stack)位于通用RAM中, 存放…

java构造者模式_Lombok的Builder与构造者模式

1. 简介在Lombok初遇,我们简单的介绍了一下Lombok的使用。其中有一个Builder注解,这个注解和构造者模式有什么关系呢?2. 构造者模式建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过…

记录: Android测试网速实现

2.3开始android提供了一个流量统计类, android.net.TrafficStats,通过使用这个类提供的方法,就可以获取设备流量。下面为该类中的常用方法,欢迎大家完善补充 static long getMobileRxBytes() //获取通过Mobile连接收到的字节总数&…

Spring AOP原理

ProxyFacotryBean是FacotryBean的一种实现,FacotryBean要产生bean都要重写getObject方法,而ProxyFacotryBean这里的这个getObject正是为代理做了准备并返回代理对象。首先用initializeAdvisorChain(第一次去取代理对象时初始化一遍)初始化Advisor链后对于singleton和…

mysql insert优化_MySql的insert语句的性能优化方案

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼下面是数据库方面调优的一个小例子,你也完全可以通过掌握基础知识,完成简单的sql语句级别的性能调优。很专注自动化测试,性能测试,安全性测试,移动端的自动化测试的人员培…

Android4.4 及以下TextView,Button等控件使用矢量图报错

2019独角兽企业重金招聘Python工程师标准>>> 1 问题描述 最近项目开发中,图标资源我尽量使用了矢量图,然而配置了基本的兼容设置,程序在低版本中运行还是出现了问题。 xml布局文件中,在TextView中使用矢量图&#xff0…