Javascript 中的数据类型

一、JS 中的两类数据类型

JS 中只有两类数据类型:基本数据类型 和 Object 类型。核心区别只有一点:基本数据类型是值传递的,而 Object 类型是引用传递。

基本类型只有 boolean、number(含 NaN)、string、null、undefined。

其他的,如我们常用的 Array、Date、Object 等都是 Object 类型。

二、原始类型的自动装箱

原始类型中的 boolean、number、string 三类,JS 标准库提供了包装对象:

boolean ---- Boolean

number ----- Number

string ----- String

在需要的时候,原始类型会自动转换成对应的包装对象,这个过程就叫自动装箱。

我们用一段很常用的代码来举个例子:

var str = 'string';
console.log(str.length);
// 6

对于原始类型来说,自然没有 length 这样的属性,但是我们就是能够拿到 length 属性的值。这里实际上就是一个自动装箱的过程。

自动装箱过程并不会影响原来的变量,我们来看扩展一下上面的代码:

var str = 'string';
console.log(str.length);
// 6
var copy_str = str;
copy_str = 'new_string';
console.log(str, copy_str);
// 'string' 'new_string'

通过这段代码我们看到变量 str 依旧是一个原始类型( 因为很明显看到这里是一个值传递 )。说明自动装箱过程并不影响变量本身,变量本身不发生任何变化。

三、通过包装对象实现强制类型转换

上面的三个包装对象可以充当构造函数,直接 new 一个包装对象来使用,来实现强制类型转换。来看下面的一个小例子:

var StrObject = new String("str");
var str = 'str';
console.log(typeof StrObject, typeof str, StrObject == str, StrObject === str);
// 'object' 'string' true false

四、类型转换中,避不开的两个函数: valueOf() 和 toString()

valueOf() -- 返回这个对象逻辑上对应的原始类型的值。如 String 包装对象的 valueOf 返回对应字符串。

toString() -- 返回这个对象的字符串表示。即用一个字符串描述这个对象的内容。

这两个方法都是定义在 Object.prototype 上的方法,所有的 Object 类型都会继承到这两个方法。(实际上 boolean number string 通过自动装箱过程也可以得到这两个方法)

/**
 * valueOf 实例
 */
var array = [1];
console.log(array.valueOf());
// [1]   -- 返回对象本身(对象类型)
var boolObj = new Boolean(true);
console.log(boolObj.valueOf());
// true  -- 返回对应的 bool 值(原始类型)
var date = new Date('8/10/2018');
console.log(date.valueOf());
// 1533830400000  -- 返回从 UTC 1970 年 1 月 1 日午夜开始计算,到所封装的日期所经过的毫秒数(原始类型)
var func = function() { return true; }
console.log(func.valueOf());
// ƒ () { return true; } -- 返回函数本身(对象类型)
var numObj = new Number(10);
console.log(numObj.valueOf());
// 10  -- 返回对应的数值(可能是 NaN)(原始类型)
var obj = { key: 'key' };
console.log(obj.valueOf());
// {key: "key"}   -- 对象本身(对象类型)
var str = new String('abc');
console.log(str.valueOf());
// abc -- 返回 字符串值(原始类型)

/**
 * toString() 总是返回一个原始 string 类的值
 */

五、JS 内部用于实现类型转换的 4 个函数

这四个函数是用的 JS 引擎内部的,所以不用关注这些函数本身,只需要关注结果就可以了。

/**
 * ToPrimitive(input[, PreferredType])
 * 将 input 转化为原始类型的值。 PreferredType 的值只能是 Number 或 String。
 * 
 * 如果 PreferredType 的值是 Number, 则按如下规则执行:
 * 1、如果 input 是原始类型,则直接返回 input.
 * 2、调用 input.valueOf(),如果结果是原始类型,则返回该结果
 * 3、调用 input.toString(),如果结果是原始类型,则返回该结果
 * 4、抛出 TypeError 异常
 * 
 * 如果 PreferredType 的值是 String, 则按如下规则执行:
 * (其实和上面的区别是交换了 2/3 步的顺序)
 * 1、如果 input 是原始类型,则直接返回 input.
 * 2、调用 input.toString(),如果结果是原始类型,则返回该结果
 * 3、调用 input.valueOf(),如果结果是原始类型,则返回该结果
 * 4、抛出 TypeError 异常
 * 
 * 如果 PreferredType 的值未传入
 *     如果 input 是 Date 类型,则视为把 PreferredType 的值视为 String 操作
 *     否则 PreferredType 视为 Number 操作。
 */

/**
 * ToBoolean(argument)
 * 实际上 if 后面表达式的值就是会按照这个函数操作。具体规则如下:
 *     (Argument Type)            (Result)
 *     Undefined                  false
 *     Null                       false
 *     Boolean                    参数本身对应的 bool 值
 *     Number                     仅当 argument 为 +0, -0, NaN 是返回 false, 其余返回 true
 *     String                     仅当 argument 为空字符串(长度为0)是,返回 false, 其余返回 true
 *     Symbol                     true
 *     Object                     true
 */

/**
 * ToNumber(argument)
 * ToNumber的转化并不总是成功,有时会转化成NaN,有时则直接抛出异常
 * 规则如下:
 *     (Argument Type)            (Result)
 *     Undefined                  NaN
 *     Null                       +0
 *     Boolean                    true -- 1; false -- +0
 *     Number                     对应的 number 原始类型
 *     String                     将字符串中的内容转化为数字(比如"23"->23),如果转化失败则返回NaN(比如"23a"->NaN)
 *     Symbol                     抛出 TypeError 异常
 *     Object                     先primValue = ToPrimitive(argument, Number),再对primValue 使用 ToNumber(primValue)
 */

/**
 * ToString(argument)
 * 
 * 规则如下:
 *     (Argument Type)            (Result)
 *     Undefined                  "undefined"
 *     Null                       "null"
 *     Boolean                    true -- "true"; false -- "false"
 *     Number                     用字符串显示数字
 *     String                     直接返回对应 string 原始类型
 *     Symbol                     抛出 TypeError 异常
 *     Object                     先primValue = ToPrimitive(argument, Number),再对primValue 使用 ToString(primValue)
*/

六、隐式类型转换

什么是隐式类型转换?

当 JS 期望得到某种类型的值,而实际上这里的值是其他类型的,就会发生隐式类型转换。隐式类型转换涉及到上面说的 4 种方法:

ToBoolean, ToPrimitive, ToNumber, ToString

这里举几个隐式类型转换的例子:

1、期望得到 Number 的相关操作

isNaN

递增递减操作符 ( 前置/后置 ++ -- ) 和 一元正负符号操作符 ( 前置/后置 +=, =+ )

计算符,如 *(乘号) /(除号) ( + 号比较特殊,会根据前后的类型判断 string 还是 number。优先 string)

2、期望得到 Boolean 的相关操作

if 后面的表达式

七、显式类型转换

通过包装对象(Boolean、Number、String)强制返回一个期望类型的值。

猜你喜欢

转载自blog.csdn.net/Jackie_Rose/article/details/81811352