前言

首先抛出几个问题:

console.log(Boolean({}));
console.log(Number([]));
console.log(Number([6]));
console.log(([]   []).length);
console.log(({}   {}).length);

打印结果都是啥?不知道各位能答对几题。文章末尾,我们会揭晓答案。这篇文章建议大家耐心阅读,相对来说比较绕而且乏味 - -。

三种算法

JavaScript 将对象转换为原始值时遵循的算法规则比较复杂,这些规则冗长、晦涩,我们先简单了解一下,具体实现后面再详细展开。

对象转换成原始值有三种基本算法:

  • 偏字符串算法。该算法返回原始值,而且只要可能就返回字符串。
  • 偏数值算法。该算法返回原始值,而且只要可能就返回数值。
  • 无偏好算法。该算法不倾向于任何原始值类型,而是由类定义自己的转换规则。JavaScript 内置类除了 Date 类,其他都实现了偏数值算法。Date 类实现了偏字符串算法。

对象转换成布尔值

对象到布尔值的转换最简单:所有对象都转换为true。这个转换不需要使用前面介绍的转换算法,直接适用于所有对象,包括空数组、包装对象:

console.log(Boolean([])); // => true

const wrapperObject = new Boolean(false); // 这是一个对象,而不是原始值
console.log(Boolean(wrapperObject)); // => true

对象转换成字符串

在将对象转换成字符串时,首先使用偏字符串算法将它转换为一个原始值,然后将得到的原始值再转换为字符串。

这种转换会发生在把对象传给一个接收字符串参数的内置函数时,比如将String()作为转换函数,或者将对象插入模板字面量中时就会发生这种转换:

console.log(String({})); // => '[object Object]'
console.log(String([])); // => ''
console.log(String(function () {})); // => 'function () {}'

对象转换成数值

当需要把对象转换为数值时,首先使用偏数值算法将它转换为一个原始值,然后将得到的原始值再转换为数值。

接收数值参数的内置函数和方法都以这种方式将对象转换为数值,除数值操作符之外的多数操作符也按照这种方式把对象转换为数值:

console.log(Number([])); // => 0
console.log(Number({})); // => NaN
console.log( []); // => 0

上面的栗子了解一下即可,具体的转换算法后面会详细解释。

转换时使用的方法

toString()valueOf(),所有对象都会继承这两个在对象到原始值转换时使用的方法,在接下来解释偏字符串、偏数值、无偏好转换算法之前,我们必须先了解这两个方法。

toString()

toString()的任务是返回对象的字符串表示。

默认情况下,toString()方法会返回特殊值:

const obj = {
    x: 1,
    y: 2,
}
obj.toString(); // => '[object Object]'

但是很多类都定义了自己特有的toString()版本。

比如,Array类的toString()方法会将数组的每个元素转换为字符串,然后再使用逗号作为分隔符将它们拼接起来:

const array = [1, 2, 3];
array.toString(); // => '1', '2', '3'

Function类的toString()方法会将用户定义的函数转换为 JavaScript 源代码的字符串:

const f = function () {};
f.toString() // => 'function () {}'

Date类定义的toString()方法返回一个对人类友好的日期和时间字符串。

RegExp类定义的toString()方法会将RegExp对象转换为一个看起来像RegExp字面量的字符串。

valueOf()

valueOf()方法的设计意图是返回对象的原始值表示。

然而大多数对象都没有缺省的原始值表示,为此valueOf()的默认实现是返回对象本身,内置的函数、数组等类型都是如此:

const obj = {x: 666};
const arr = [1, 2, 3];
const fn = function () {};

obj.valueOf(); // => {x: 666}
arr.valueOf(); // => [1, 2, 3]
fn.valueOf(); // => ƒ () {}

极少数对象才具有有意义的原始值表示,比如StringNumberBoolean这样的包装类定义的valueOf()方法会简单地返回被包装的原始值:

const wrapperObj1 = new String(666);
const wrapperObj2 = new Number(888);
const wrapperObj3 = new Boolean(false);

wrapperObj1.toString(); // => '666'
wrapperObj2.toString(); // => '888'
wrapperObj3.toString(); // => 'false'

还有Date对象定义的valueOf()方法返回时间戳:

const d = new Date(2022, 6, 24);
d.valueOf(); // => 1658592000000

了解完toString()valueOf()方法后,接下来我们看看转换算法是如何实现的。

转换算法

偏字符串算法

偏字符串算法首先尝试toString()方法。如果这个方法有定义且返回原始值,则使用这个原始值,即使这个值不是字符串。如果toString()方法不存在,或者存在但返回对象,则尝试valueOf()方法。如果valueOf()方法存在且返回原始值,就使用该值。否则,转换失败,报 TypeError。

偏数值算法

偏数值算法与偏字符串算法类似,只不过是先尝试valueOf()方法,再尝试toString()方法。

无偏好算法

无偏好算法取决于被转换的对象。如果是一个Date对象,则使用偏字符串算法。如果是其他类型的对象,就使用偏数值算法。

以上规则适用于所有的内置 JavaScript 类型。

练习题

文章开头列举的五个问题,下面我们逐一揭晓答案。

console.log(Boolean({})):对象转换成布尔值时,所有对象都转换为true,所以打印true

console.log(Number([])):对象转换成数值,首先使用偏数值算法把对象转换为一个原始值,然后再把得到的原始值转换为数值。偏数值算法会先尝试valueOf(),将toString()作为备用。Array类继承了默认的valueOf()方法,所以不会返回原始值,因此最终会调用toString()方法。空数组会被转换成空字符串,而空字符串转换成数值为 0,所以打印 0。

console.log(Number([6])):同样,使用偏数值算法,最终会调用toString()方法。因为数组中只包含一个数值,所以该数值首先会被转换成字符串 '6',再转换回数值 6,打印结果为 6。

console.log(([] []).length):两个数组相加,首先会将数组转换为字符串,使用偏字符串算法,空数组会转换为空字符串,空字符串相加还是空字符串,长度为 0,打印结果为 0。

console.log(({} {}).length):两个对象相加,首先会将对象转换成字符串,使用偏字符串算法,对象转换成字符串后是'[object Object]',两个'[object Object]'拼接后的长度是 30,打印结果为 30。

到此这篇关于浅析JavaScript对象转换成原始值的文章就介绍到这了,更多相关JS对象转换内容请搜索Devmax以前的文章或继续浏览下面的相关文章希望大家以后多多支持Devmax!

浅析JavaScript对象转换成原始值的更多相关文章

  1. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  2. HTML5数字输入仅接受整数的实现代码

    这篇文章主要介绍了HTML5数字输入仅接受整数的实现代码,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  3. amaze ui 的使用详细教程

    这篇文章主要介绍了amaze ui 的使用详细教程,本文通过多种方法给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  4. html5简介_动力节点Java学院整理

    这篇文章主要介绍了html5简介,用于指定构建网页的元素,这些元素中的大多数都用于描述网页内容,有兴趣的可以了解一下

  5. ios 8 Homescreen webapp,关闭和打开iPad停止javascript

    我有一个适用于iPad的全屏HTML5网络应用程序,并且刚刚安装了IOS8来试用它,它一切正常,直到你关闭并重新启动iPad.一旦web应用程序重新启动javascript就会停止并加载新页面不会重新启动它.在iPad上的Safari中打开同一页面时,关闭和打开iPad会继续按预期工作.其他人注意到了这个或想出了一个解决方案吗?解决方法这似乎是我在iOS8.1.1更新中解决的.

  6. iOS 6 javascript与object.defineProperty的间歇性问题

    当访问使用较新的Object.defineProperty语法定义属性的对象的属性时,有没有其他人注意到新iOS6javascript引擎中的间歇性错误/问题?https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Object/defineProperty我正在看到javascript失败的情况,说

  7. ios – 如何使用JSExport导出内部类的方法

    解决方法似乎没有办法将内部类函数导出到javascript.我将内部类移出并创建了独立的类,它起作用了.

  8. 静音iOS推送通知与React Native应用程序在后台

    我有一个ReactNative应用程序,我试图获得一个发送到JavaScript处理程序的静默iOS推送通知.我看到的行为是AppDelegate中的didReceiveRemoteNotification函数被调用,但是我的JavaScript中的处理程序不会被调用,除非应用程序在前台,或者最近才被关闭.我很困惑的事情显然是应用程序正在被唤醒,并且它的didReceiveRemoteNotifi

  9. ios – 内存泄漏与UIWebView和Javascript

    清楚地包含一个Javascript文件到我的HTML是使UIWebView泄漏内存.当我重复使用相同的UIWebView对象时,或者每当我有内容实例化一个新的漏洞时,会出现泄漏的事实,导致我认为必须有一些JavaScript文件被loadHTMLString处理,导致泄漏.有人知道如何解决这个问题吗?

  10. iOS应用程序的UI自动化测试如何与乐器和Javascript

    从WWDC2010视频会议中了解iOS应用程序的自动化UI测试,但没有实践.从代码项目project,我们可以有一个例子.这个问题在这里听到有涉及这个的人.任何限制?解决方法我建议从AlexWollmer开始使用thisblogpost.他创建了一个非常有用的JavaScript库:tuneup_jswithtest()函数,它允许测试分离和有用的帮助者以及为自动化仪器编写测试的断言.

随机推荐

  1. js中‘!.’是什么意思

  2. Vue如何指定不编译的文件夹和favicon.ico

    这篇文章主要介绍了Vue如何指定不编译的文件夹和favicon.ico,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

  3. 基于JavaScript编写一个图片转PDF转换器

    本文为大家介绍了一个简单的 JavaScript 项目,可以将图片转换为 PDF 文件。你可以从本地选择任何一张图片,只需点击一下即可将其转换为 PDF 文件,感兴趣的可以动手尝试一下

  4. jquery点赞功能实现代码 点个赞吧!

    点赞功能很多地方都会出现,如何实现爱心点赞功能,这篇文章主要为大家详细介绍了jquery点赞功能实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  5. AngularJs上传前预览图片的实例代码

    使用AngularJs进行开发,在项目中,经常会遇到上传图片后,需在一旁预览图片内容,怎么实现这样的功能呢?今天小编给大家分享AugularJs上传前预览图片的实现代码,需要的朋友参考下吧

  6. JavaScript面向对象编程入门教程

    这篇文章主要介绍了JavaScript面向对象编程的相关概念,例如类、对象、属性、方法等面向对象的术语,并以实例讲解各种术语的使用,非常好的一篇面向对象入门教程,其它语言也可以参考哦

  7. jQuery中的通配符选择器使用总结

    通配符在控制input标签时相当好用,这里简单进行了jQuery中的通配符选择器使用总结,需要的朋友可以参考下

  8. javascript 动态调整图片尺寸实现代码

    在自己的网站上更新文章时一个比较常见的问题是:文章插图太宽,使整个网页都变形了。如果对每个插图都先进行缩放再插入的话,太麻烦了。

  9. jquery ajaxfileupload异步上传插件

    这篇文章主要为大家详细介绍了jquery ajaxfileupload异步上传插件,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

  10. React学习之受控组件与数据共享实例分析

    这篇文章主要介绍了React学习之受控组件与数据共享,结合实例形式分析了React受控组件与组件间数据共享相关原理与使用技巧,需要的朋友可以参考下

返回
顶部