掌握js类型转换,先来学习js原始值转换的抽象操作 toPrimitive
文章目录
- 前言
- js的原始值和引用值
- js原始值转换的抽象操作 toPrimitive
- 日期对象的特殊情况
- 字符串连接符与算术隐式转换规则混淆
- 实例详解
- `valueOf()` 和 `toString()`
- 参考
前言
Symbol.toPrimitive
是一个内置的抽象操作,它是作为对象的函数值属性存在的,当一个对象转换为对应的 原始值 时,会调用此函数。
注意:这里涉及到原始值的概念,所以在详细讲解toPrimitive
之前,我们会介绍一下 什么是原始值?
让我们开始吧~
js的原始值和引用值
在ECMAScript中,变量可以存放两种类型的值,即原始值和引用值。
原始值(primitive value)
:
原始值是固定而简单的值,是存放在栈(stack)
中的简单数据段,也就是说,它们的值直接存储在变量访问的位置。
最新的 ECMAScript 标准定义了7 种原始值:undefined
、Boolean
、Number
、String
、BigInt
、Symbol
和 null
。
其实在今年的早些时候,
null
还不属于原始类型。
引用值(reference value)
:
引用值则是比较大的对象,存放在堆(heap)
中的对象,也就是说,存储在变量处的值是一个指针(pointer)
,指向存储对象的内存处。
所有引用类型都集成自Object
。
如果一个值是引用类型的,那么它的存储空间将从堆中分配。由于引用值的大小会改变,所以不能把它放在栈中,否则会降低查询速度。相反,存放变量的栈空间中的值是该对象存储在堆中的地址。地址的大小是固定的,所以把它存放在栈中对变量性能无任何负面影响。如图:
我们看一下MDN对原始值的定义:
原始值( primitive values )
除 Object
以外的所有类型都是不可变的(值本身无法被改变)。例如,与 C 语言不同,JavaScript
中字符串是不可变的(译注:如,JavaScript
中对字符串的操作一定返回了一个新字符串,原始字符串并没有被改变)。我们称这些类型的值为“原始值”
。
js原始值转换的抽象操作 toPrimitive
Symbol.toPrimitive
是一个内置的抽象操作,它是作为对象的函数值属性存在的,当一个对象转换为对应的原始值时,会调用此函数。
该函数被调用时,会被传递一个字符串参数,表示要转换到的原始值的预期类型。参数的取值是 "number"
、"string"
和 "default"
中的任意一个。
toPrimitive
转换规则如下:
如果传入参数是string
,也就是对象到字符串的转换,经过了如下步骤:
- 如果对象中有
toString()
方法,则调用这个方法。如果它返回一个原始值(undefined、Boolean、Number、String、BigInt、Symbol 和 null)
,js将这个值转换为字符串(如果本身不是字符串的话),并返回这个字符串结果。 - 如果对象没有
toString()
方法,或者toString()
没有返回一个原始值,那么js会调用valueOf()
方法。如果返回值是原始值,js将这个值转换为字符串,并返回字符串结果。 - 否则,js抛出一个类型错误异常。
如果传入参数是number/default
,也就是对象到数字的转换,经过了如下步骤:
和上面有点不同,到数字的转换会先尝试使用valueOf()
方法
- 如果对象具有
valueOf()
方法,后者返回一个原始值,则js会将其转换为数字(如果需要的话)并返回这个数字。 - 否则,如果对象具有
toString()
方法,返回一个原始值(字符串直接量),则js将其转换为数字类型,并返回这个数字。 - 否则,js抛出一个类型错误异常。
注意:对于所有非日期对象来说,对象到原始值的转换基本上是对象到数字的转换
日期对象的特殊情况
日期对象在原型里自定义了toString(),即Date.prototype.toString()
。
1 var date = new Date();
2 date.toString(); // => "Mon Dec 28 2015 21:58:10 GMT+0800 (中国标准时间)"
Date 对象覆盖了从 Object 继承来的Object.prototype.toString()
方法。Date的toString()
方法总是返回一个美式英语日期格式的字符串。当一个日期对象被用来作为文本值或用来进行字符串连接时,toString()
方法会被自动调用。
“+” 和 “==” 应用的对象到原始值的转换包含日期对象的一种特殊情形。
日期类是JavaScript语言核心中唯一的预先定义类型,它定义了有意义的向字符串和数字类型的转换。
对于所有非日期的对象来说, 对象到原始值的转换基本上是对象到数字的转换(首先调用valueOf()) , 日期对象则使用对象到字符串的转换模式,然而,这里的转换和上文讲述的井不完全一致:通过valueOf或toString()返回的原始值将被直接使用,而不会被强制转换为数字或字符串。
和"==" 一样, "<” 运算符以及其他关系运算符也会做对象到原始值的转换, 但要除去日期对象的特殊情形:任何对象都会首先尝试调用valueOf(), 然后调用toString()。不管得到的原始值是否直接使用,它都不会进一步被转换为数字或字符串。
“+”、 “==”、 “!=” 和关系运算符是唯一执行这种特殊的字符串到原始值的转换方式的运算符。 其他运算符到特定类型的转换都很明确,而且对日期对象来讲也没有特殊情况。 例如 " - , (减号)运算符把它的两个操作数都转换为数字。
下面的代码示例:
var now = new Date(); // 当前时间
typeof (now + 1); // "string"
typeof (now - 1); // "number"
now == now. toString(); // true
now > (now -1); // true
>var now = new Date();
>now + 1
>'Fri Oct 01 2021 10:58:55 GMT+0800 (中国标准时间)1'
>now - 1
>1633057135763
字符串连接符与算术隐式转换规则混淆
console.log(1 + true); //2
console.log(1 + "true"); //"1true"
console.log(1 + undefined); //NaN
console.log(1 + null); //1
+
两边有一边是字符串,那这个+
就是字符串连接符,它会把其他数据类型调用String()
方法转成字符串然后拼接;
+
做为算术运算符会把其他数据类型调用Number()
转成数字然后做加法运算;
布尔值true
会被转换数字 1
,
undefined
会被转换为 NaN
,
null
会转换为数字 0
实例详解
//大坑
console.log ( [] == 0 ); //true
console.log ( ! [] == 0 ); //true
//神坑
console.log ( [] == ! [] ); //true
console.log ( [] == [] ); //false
//史诗级坑
console.log({} == !{}); //false
console.log({} == {}); //false
[]
与 0
比较:
(1)[].valueOf().toString()
得到空字符串
(2)Number("") == 0
成立
![]
与 0
比较:
(1)逻辑非优先级高于关系运算符 ![] = false
(空数组转布尔得到true,然后取反得到false)
(2)false == 0
成立
[]
与 ![]
比较:
(1) [].valueOf().toString()
得到空字符串 “”
(2) ![] = false
(3) Number("") == Number(false)
成立 都是0
[]
与 []
比较:
引用类型数据存在堆内存中,栈内存中存储的是地址,所以他们的结果是false
{}
与 !{}
比较:
(1) {}.valueOf().toString()
得到字符串'[object Object]'
(2) !{} = false
(3) Number('[object Object]') == Number(false)
不成立,因为转换到最后 是NaN
和 0
比较,所以结果为 false
{}
与 {}
比较:
引用类型数据存在堆内存中,栈内存中存储的是地址,所以他们的结果是false
>{}+[]
>0
空对象加空数组就不一样了,加号运算符的定义是这样的:如果其中一个是字符串,另一个也会被转换为字符串,否则两个运算数都被转换为数字。 而同时,javascript有这样的特性,如果{}既可以被认为是代码块,又可以被认为是对象字面量,那么js会把他当做代码块来看待。
这就很好解释了,{}
被当做了代码块,只有+[]
,根据加法的定义,被转换为0,就得到了结果。
valueOf()
和 toString()
掌握js类型转换,先来学习js原始值转换的抽象操作 toPrimitive相关推荐
- h5 php js实验总结,H5学习_番外篇_PHP数据库操作
1. 文件操作 1.1 打开关闭文件 fopen() resource fopen ( string filename, string mode [, bool use_include_path [, ...
- JS类型转换常见方法
转自:微点阅读 https://www.weidianyuedu.com JS类型转换常见的方法集合 一.类型转换 1.转换成字串 ECMAScript的Boolean值.数字和字串的原始值的有趣之 ...
- 绒毛动物探测器:通过TensorFlow.js中的迁移学习识别浏览器中的自定义对象
目录 起点 MobileNet v1体系结构上的迁移学习 修改模型 训练新模式 运行物体识别 终点线 下一步是什么?我们可以检测到脸部吗? 下载TensorFlowJS-Examples-master ...
- js类型转换的各种玩法
前言 对于object和number.string.boolean之间的转换关系 [ ] Object 与Primitive,需要Object转为Primitive [ ] String 与 Bool ...
- 面向面试题的前端学习-js篇(自用,持续完善中)
前言:初心是记录面试题,慢慢由每个知识点引伸出去,逐渐查缺补漏,构建出更完善的前端知识系统. 题目来源:牛客网 gitnub 目录 HTTP协议 get请求传参长度的误区 补充get和post请求在缓 ...
- 前端学习--js.2
写一个通用的事件侦听器函数 markyun.Event = { //页面加载完成后 readyEvent :function(fn) { if(fn==null) { fn=document; } v ...
- Vue.js实战之系统学习第七节
想看上一节的请点击: Vue.js实战之系统学习第六节 接下来我们要学习第七节了,时间过的好快. 组件详解 组件是Vue.js的核心功能,也是整个框架设计最精彩的地方,当然也是最难掌握的.本章节将带你 ...
- 前端学习——JS基础知识点复习
一. JS复习 1.1 如何使用JS HTML标签内使用JS,要求写在onclick等事件属性或者href属性中(不推荐使用) 页面中的script标签内可以直接写JS代码 script标签的src属 ...
- js类型转换(隐式类型转换显式类型转换)
我们需要了解任何计算都只能在相同的数据类型之间执行.如果我们强制JavaScript执行执行一些操作,例如在字符串中添加一个数字,在这种情况下,js编译器会默认将数字更改为字符串类型,然后将两者连接起 ...
最新文章
- 被业务方投诉了!CTO直摇头:人际关系处理太差,不懂维护“情感账户”
- Target runtime Apache Tomcat v6.0 is not defined.错误解决方法
- Java源码解析:ArrayList 和 Iterator 使用上的不同
- 2019/01/29-Linux常用指令
- 创业者ALL IN区块链的5条建议
- 共享可写节包含重定位_周末去哪?来云浮!来乡村美食(番薯)节!
- Linux下安装、配置、启动Apache
- Eclipse反编译插件(免费无需下载资源)
- Oracle RMAN备份与还原
- python 蒙特卡洛模拟股价_利用python进行蒙特卡罗模拟
- kali Linux破解无线网密码
- 英语中与数字有关的表达方式
- 树莓派安装开源智能家居系统 Domoticz
- h5/web 原生定位、高德、腾讯地图定位
- java foreach循环语句_Javaforeach语句
- sipjs 保存mp4文件_微信视频号视频怎么下载,视频号视频怎么保存到手机
- MacBook pro新手教程
- Python生成声音波形、模拟钢琴音色
- kmcuda: GPU加速 Kmeans
- 【游戏介绍】aiwi体感游戏滑雪
热门文章
- Unity3D在android系统下调试
- 智慧交通运行监测平台TOCC建设方案(附下载)
- ADS1299国产替代方案,完全pin to pin兼容替代Ti ADS1299
- Day042 意志力真好用
- ambari 2.7.6源码编译指南
- js添加元素的三种方法
- Oracle rman备份集上限,利用RMAN的cate限制RMAN备份速度 | 信春哥,系统稳,闭眼上线不回滚!...
- 文法和语法和词法的解释
- python的mkl库_[转]Numpy使用MKL库提升计算性能
- capwap学习笔记——初识capwap(一)(转)