控制 Javascript 范例转换:从划定规矩最先

Javascript 里的范例转换是一个你永久绕不开的话题,不论你是在口试中照样事情写代码,总会遇到这类题目和种种的坑,所以不学好这个那是不可滴。关于范例转换我也看过不少的书和种种博客、帖子,也查过范例和做过种种测试,这里就谈谈我的总结和明白吧。

起首,为了控制好范例转换,我们要明白一个主要的笼统操纵:ToPrimitive

ToPrimitive

为何说这是个笼统操纵呢?由于这是 Javascript 内部才会运用的操纵,我们不会显现挪用到。当须要将对象转换为响应的基本范例值时,ToPrimitive 就会挪用对象的内部要领 [[DefaultValue]] 来完成。

ToPrimitive 操纵吸收两个参数,一个是 input 须要转换的值,第二个是可选参数 hint 代表希冀的转换范例。而且在挪用 [[DefaultValue]] 的时刻 hint 会通报过去。

这里我们起首只须要知道 [[DefaultValue]] 会挪用 valueOf()toString() 来完成基本范例值的转换。然则请注重:valueOf()toString() 的挪用逻辑递次并非牢固的取决于 hint 参数,这个我们下面会讲到。

基本划定规矩

JavaScript 中的范例转换老是返回基本范例值,如字符串、数字和布尔值,不会返回对象和函数。那末这也对应了三种笼统操纵:ToStringToNumberToBoolean,下面就来一一申明。

ToString

var a = {};
console.log(String(a));
// 显式范例转换,输出为:"[object Object]"

以上代码我们一般称为显现范例转换,这内里就包含 ToString 笼统操纵,也就是把非字符串值转换为字符串的操纵。

先来看看非对象的基本范例值的 ToString 转换划定规矩:

输入范例输出效果
Undefined"undefined"
Null"null"
Boolean输入 true,输出 "true"
输入 false,输出 "false"
Number输入 NaN,输出 "NaN"
输入 +0-0,输出 "0"
假如输入小于 0 的数字,如:-2,输出将包含负号:"-2"
输入 Infinity,输出 "Infinity"

接着我们重点来看一下输入是对象的转换划定规矩。

这个时刻 ToPrimitive 就进场了,而且 hint 参数是 String。还记得 ToPrimitive 内部是挪用的[[DefaultValue]]吗,而且这个时刻 hint 是 String 。下面来看下这类状况下 ToPrimitive 的挪用逻辑:

  1. toPrimitive 挪用 [[DefaultValue]] 并通报 hint,然后返回挪用效果
  2. [[DefaultValue]] 依据 hint 是 String 实行以下挪用递次:

    • 假如对象存在 toString() 并返回一个基本范例值,即返回这个值
    • 假如 toString() 不存在或返回的不是一个基本范例值,就挪用 valueOf()
    • 假如 valueOf() 存在并返回一个基本范例值,即返回这个值
    • 假如 valueOf() 不存在或返回的不是一个基本范例值,则抛出 TypeError 非常

那末这里就能够总结为:对象在范例转换为字符串时, toString() 的挪用递次在 valueOf() 之前,而且这两个要领假如都没有返回一个基本范例值,则抛出非常;假如返回了基本范例值 primValue,则返回 String(primValue)

基本范例值的 ToString 效果参看前面谁人表格

我们来测试一下。先看下这节开首的例子:

var a = {};
console.log(String(a));

字面量对象的原型是 Object.prototypeObject.prototype.toString() 返回内部属性 [[Class]] 的值,那末效果就是 [object Object]。OK 没有题目

然后测试一下 ToPrimitive 的挪用逻辑。来看下这段代码:

var a = Object.create(null);

上面的意义是建立一个没有原型的对象(没有原型就没有继续的 toString()valueOf() 了)。接下来:

console.log(String(a));
// Uncaught TypeError: Cannot convert object to primitive value

这里由于没有 toString()valueOf() 所以就抛出 TypeError 非常了。OK,跟前面的总结一致。

下面来测试一下 toString()valueOf() 的挪用递次逻辑,上代码:

a.toString = function() {
  return 'hello';
};

a.valueOf = function() {
  return true;
};

console.log(String(a)); // "hello"

我们到场了 toString()valueOf() ,而且跟前面的总结一致,确实是 toString() 先返回效果。接着做一下变化:

a.toString = function() {
  return {};
};
// 或是直接去掉这个要领,a.toString = undefined;

a.valueOf = function() {
  return true;
};

console.log(String(a)); // "true"

当 toString() 返回的不是一个基本范例值或不存在 toString() 时,返回 valueOf() 的效果,而且遵照基本范例值的 ToString 转换效果。OK,考证没有题目 其他的状况也能够依据前面的总结逻辑本身考证下。

在《Javascript 高等程序设计(第 3 版)》和《你不知道的 Javascript(中卷)》上均未提到范例转换到字符串会与 valueOf() 有关联

ToNumber

起首按例先来看下非对象的基本范例值的 ToNumber 转换划定规矩:

输入范例输出效果
UndefinedNaN
Null0
Boolean输入 true,输出 1
输入 false,输出 0
Number输入 "",输出 0
输入 "Infinity",输出 Infinity
输入有效数字的字符串(包含二、八和十六进制),输出数字的十进制数值
假如输入包含非数字花样的字符串,输出 NaN

字符串转数字上面只说了一些经常使用的状况,更多细节请看
这里

然后来看看对象 ToNumber 的状况。这里与对象转字符串的状况相似,也会挪用 ToPrimitive 来转换(hint 是 Number)。但细节与 ToString 稍有差别,这里直接给出结论:

对象在范例转换为数字时, valueOf() 的挪用递次在 toString() 之前,而且这两个要领假如都没有返回一个基本范例值,则抛出非常;假如返回了基本范例值 primValue,则返回 Number(primValue)

这里考证了 ToPrimitive 内里说到的,[[DefaultValue]] 会依据 hint 参数决议 toString() 和 valueOf() 的挪用递次

接着来用代码措辞:

var a = Object.create(null);
console.log(Number(a));
// Uncaught TypeError: Cannot convert object to primitive value

这里由于没有 toString()valueOf() 所以就抛出 TypeError 非常了。OK,跟前面的总结一致。

我们先到场 valueOf() 要领:

a.valueOf = function() {
  return 123;
}
console.log(Number(a)); // 123

valueOf() 返回了数字 123,所以输出没题目。再修正一下:

a.valueOf = function() {
  return true;
}
console.log(Number(a)); // 1

valueOf() 返回了 true,这也是一个基本范例,然后依据基本范例转换划定规矩 true 转换为 1,也是对的。

再来:

a.valueOf = function() {
  return NaN;
}
console.log(Number(a)); // NaN

NaN 是一个迥殊的数值,所以也是基本范例。OK,也是对的。

这里的效果申清楚明了《Javascript 高等程序设计(第 3 版)》关于对象转换为数字的诠释是有毛病的,书上是这么说的:假如转换的效果是 NaN,则挪用对象的 toString() 要领

再来考证一下 toString() 的挪用递次:

a.valueOf = function() {
  return {};
}
a.toString = function() {
  return '123';
}
console.log(Number(a)); // 123

由于 valueOf() 返回了对象非基本范例值,转而实行 toString(),返回的 “123” 依据字符串转换数字的划定规矩就是 123,关于 valueOf() 和 toString() 的实行递次考证也是 OK 的。

ToBoolean

末了我们来看看转换为布尔值。这个比较简单,一个列表能够悉数归结了:

输入范例输出效果
Undefinedfalse
Nullfalse
Number输入 +0,-0,NaN,输出 false
输入其他数字,输出 true
String输入 length 为 0 的字符串(如:""),输出 false
输入其他字符串,输出 true
Object输入任何对象范例,输出 true

ToBoolean 转换划定规矩比较简单,只要一个须要注重的处所,那就是封箱操纵:

var a = new Boolean(false);
console.log(Boolean(a));
// 输出是 true 不是 false 喔

new Boolean(false) 返回的是对象不是布尔值,所以最好防止举行相似的操纵。

总结

以上等于我总结的 JS 范例转换基本划定规矩,当你显著感知范例转换行将发作时能够拿上面的划定规矩去套(也就是我们一般说的显式范例转换,以上转换划定规矩口试时迥殊有效喔)。

既然划定规矩有了,下一篇预备聊一下隐式范例转换,有了这篇的基本控制隐式转换会轻易许多。

迎接 star 和关注我的 JS 博客:小声比比 Javascript

参考资料

    原文作者:deepfunc
    原文地址: https://segmentfault.com/a/1190000019400583
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞