1. 从基本包装类型讲起

讨论基本包装类型的前提是了解基本数据类型(也可以称为原始类型, 简单数据类型等)。然后通过基本数据类型调用方法的行为, 引出基本包装类型的概念和作用.

1.1 基本数据类型

已经知道 JavaScript 中共有6种基本数据类型,分别是:string,number,boolean,null,undefined,symbol.

基本类型既不是对象, 也没有方法可供调用. 然而经常见到基本类型的变量调用方法的情况, 类如:

let index = 'ABCDE'.indexOf('CD');
console.log(index); // 2

上例中 'ABCDE' 是一个字符串的基本类型, 这个字符串直接调用了indexOf 方法, 将该方法的返回值保存在变量 index 中, 然后在第二行输出. 可以看到这个例子能够运行并且结果正确.

既然上面说原始类型没有方法可供调用, 那么字符串 'ABCDE' 在调用 indexOf 方法时为什么没有出错呢? 而且从运行结果来看, indexOf 这个方法确实被调用了, 那么是谁调用了这个方法并且返回了正确的结果呢? 答案就是基本包装类型. 下面引入基本包装类型的相关内容.

1.2 基本包装类型

关键词: 包装, 基本包装类型, 基本包装类型的对象

上一节讨论到其实调用方法的并不是字符串本身 , 而是基本包装类型. 下面就应该具体讨论基本包装类型的相关内容了.

为了基本类型可以正常调用方法, 后台会为这个基本类型的值自动创建一个对应的对象, 这个对象的类型就称为基本包装类型, 然后用这个对象去调用方法, 在调用完方法之后, 这个对象就会被销毁( 用完就销毁 )了. 这个从基本数据类型生成基本包装类型对象的过程称为包装( box ).

简单来说, 在基本类型调用方法的时候, 方法的真正调用者其实不是我们直接定义的基本类型, 而是后台给我们创建的基本包装类型的 对象 . 而且这个对象是临时的、不会一直存在的、用完就会被销毁的.

这个对象还有一个特点, 他是与基本类型的值相对应的. 然而:

并不是每一种基本类型都有对应的包装类型

上节中提到的六种基本类型中的四种有其对应的包装类型, 分别是:

string(字符串) -> String, number(数值) -> Number,boolean(布尔) -> Boolean,symbol(符号) -> Symbol

其中符号 -> 表示对应. 同时: 注意首字母的大写( 对象名的首字母习俗默认大写 ).

注意: 本文只讨论 string,number,boolean 三种基本类型及其对应的包装类型.

还需要了解的是, 不仅仅是系统可以隐式的创建包装对象, 用户也可以手动、显式的创建一个基本包装类型的对象, 方法为: 用关键字 new 加上对应的包装类型的构造函数, 参数传入基本类型的值即可, 例如:

let n = new Number(22);             // n 是 数值22对应的包装对象
let str = new String('example'); // str 是字符串 'example' 对应的包装对象
let flag = new Boolean(false); // flag 是布尔值 false 对应的包装对象

至此, 再看第一节的这个例子, 可以再次想象系统创建包装对象的大致过程:

let index = 'ABCDE'.indexOf('CD');
console.log(index); // 2

可以发现第一行代码中后台发生了包装行为: 后台根据字符串类型的 'ABCDE' 包装出了一个对象. 即: 在调用 indexOf 方法时, 后台发现想调用这个方法的是一个基本类型的值, 但是这个值没有这个方法可供调用, 于是为它生成了对应的包装对象( 操作 1 ), 然后通过这个包装对象来调用了 indexOf 方法( 操作 2 ), 而后将方法的返回值赋给了变量 index. 最后, 把这个包装对象销毁( 操作 3 ).

根据以上思路,可以大致模拟出上述过程的对应的代码:

// step 1. 创建 'ABCDE' 对应的基本包装类型的对象:
let temp = new String('ABCDE'); // step 2. 用包装类型的对象 temp 调用 indexOf 方法, 并将返回值赋给 index 变量:
let index = temp.indexOf('CD'); // step 3. 将 temp 对象销毁
temp = null;

1.3 总结

当一个基本数据类型想要调用方法时, 后台会为它生成一个临时的包装对象, 利用这个对象去调用方法, 再将方法执行的结果返回, 随后这个临时对象被销毁.

1.4 包装对象的"拆包装" box <-> unbox

从上面的内容了解到 包装(box) 是根据一个基本类型的值生成一个对应类型的对象的过程,

与这个过程大致相反, 存在一种根据包装对象生成基本类型值的过程, 可称为 拆包装 (unbox). 这个过程同样即可以由后台隐式的完成, 也可以手动的调用方法 valueOf 来做.

下一节开始讨论 valueOf 这个方法, 同时引出另外一个同样重要的方法 toString.

2. 对象的两个重要方法 valueOftoString

2.1 基本包装类型的拆包装( unbox ) 用到的 valueOf 方法

基本包装类型的拆包装操作用到了包装对象中的 valueOf 函数, 这个函数可以将一个对象转换成一个基本类型的值.

对于 Boolean, Number 和 String 三者的基本包装对象来说, 调用 valueOf 的返回值是各自对应的基本数据类型的值:

let n = new Number(22);     // 包装基本数值数据 22
// 拆包装出来的结果是对应的基本数据类型的值
console.log(n.valueOf() === 22); // true let str = new String('example'); // 包装基本字符串数据 'example'
// 拆包装出来的结果是对应的基本数据类型的值
console.log(str.valueOf() === 'example'); // true, let flag = new Boolean(false); // 包装基本布尔数据 false
// 拆包装出来的结果是对应的基本数据类型的值
console.log(flag.valueOf() === false); // true

有时会发生后台隐式拆包装的情况, 包装类型的对象会在后台调用 valueOf 方法, 例如:

let a = new Number(1);
let b = a + 1; //---> 这一行发生了隐式拆包装操作: let b = a.valueOf() + 1; console.log(b); // b 为 2 console.log(typeof a); // object
console.log(typeof b); // number, b 的类型为 基本数据类型, 而不是包装类型

甚至一行代码中会发生包装和解包装两种操作, 例如:

let num = 3.14159;
console.log(num.valueOf()); // 3.14159

在上面代码块的第二行代码中变量 num 要调用函数 valueOf , 此时 num 会被先包装为 基本包装类型的对象,而这个对象在调用 valueOf 方法时就发生了解包装的操作.

2.2 其他对象的 valueOf 方法

不仅仅是基本包装类型有 valueOf 方法, 许多 JavaScript 内建(build-in)对象都有该函数, 为使执行的结果与对象本身相符合, 大多对象都重写了这个方法. 下面看一些其他对象的 valueOf 方法的行为有什么特点.

以下列出常用内置对象的 valueOf 方法的返回值:

对象 返回值
Boolean, Number 和 String 三者 各自相对应的基本类型的值
Array,Function,Object 三者 其本身
Date 当前时间距 1970.01.01 午夜的毫秒数
Math 和 Error 没有 valueOf 方法

下面是实验结果:

// 数组调用 valueOf, 返回数组本身
let array = [1, 'hello', false];
console.log(array.valueOf() === array); // true // 函数调用 valueOf, 返回函数本身
function foo(){}
console.log(foo.valueOf() === foo); // true // 对象调用 valueOf, 返回对象本身
let obj = {
name: 'doug',
age : 22
};
console.log(obj.valueOf() === obj); // true // 当前时间距1970年1月1日午夜的毫秒数
console.log(new Date().valueOf()); // 1551684737052

总结: valueOf 方法可以将一个对象转换为基本数据类型, 并不是每个对象都有此方法(例如: Math 和 Error 对象).

对于布尔、数值和字符串三者的基本包装类型来说,调用此函数返回其对应的基本类型的值;

对象调用此函数的返回值是其本身 ( 由于数组和函数本质上也是对象, 所以也返回其自身 ) .

提到 valueOf 方法就不得不想起另外一个对于类型转换十分重要的方法 toString, 下节将会讨论它.

2.3 可以将对象表示为字符串的方法 toString()

每个内置的对象都有此方法,是从 Object 对象继承而来的. 为使执行的结果与对象本身相符合, 大多数内置对象都重写了该函数. 常见的对象调用 toString 方法的返回值如下:

  • 对于用户创建的对象, 返回'[object object]'. (存在一个例外, 见最后部分)

  • 对于 Math 对象, 返回 "[object Math]":

// 自定义的对象
console.log({name: 'doug'}.toString()); // '[object Object]' // Math 对象
console.log(Math.toString()); // '[object Math]'
  • 对于 第一部分中提到的 3 个基本包装类型的对象:
  1. 对于布尔对象, 返回字符串 "true" 或 "false", 根据其对应的基本数据类型的值而定.
  2. 对于数值对象, 返回在指定基数下该数的字符串形式, 默认基数是 10, 即默认返回 十进制 的数用引号包裹而成的字符串.
  3. 对于字符串对象, 返回对应基本数据类型的字符串(和调用 valueOf 方法得到的结果相同) .
// 布尔值的包装类型的对象
console.log(new Boolean(false).toString()); // 'false' // 数值包装类型对象的对象
console.log(new Number(3.14159).toString()); // '3.14159' // 字符串包装类型对象的对象
console.log(new String('str').toString()); // 'str'
  • 对于数组,返回所有项组成的字符串, 各项之间用 "," 连接.
// 数组
console.log([1, 'hello', false].toString()); // '1,hello,false'
  • 对于 函数,toString方法返回一个字符串,其中包含用于定义函数的源文本段.
// 函数
function foo(){console.log('hello foo');}
console.log(foo.toString());
// 'function foo(){console.log('hello foo');}'
  • 其他对象
  1. 对于 RegExp 对象,返回该正则表达式的字符串.
  2. 对于 Date 对象, 返回表示特定时间的字符串.
  3. 对于 Error 对象,返回包含错误内容的字符串.
// 正则对象
console.log(new RegExp("a+b+c").toString()); // "/a+b+c/" // 日期对象
console.log(new Date().toString());
// Mon Mar 04 2019 17:07:54 GMT+0800 (中国标准时间) // Error 对象
console.log(new Error('fatal error').toString());
// 'Error: fatal error'

并非每个对象都有 toString() 方法, 例如通过 Object.create 函数传入null 为参数创建出来的对象, 由于它的 prototypenull, 所以没有 toStringvalueOf 方法

2.4 总结

夲节讨论了两个重要的函数 valueOftoString , 前者返回调用者的基本类型的值, 后者可以将一个对象转化为字符串.

这两个函数将在强制类型转换过程中起到重要的作用.

注: 包装和拆包装过程也有其他名称, 例如封装(wrap)和解封(unwrap), 只是同一个过程的不同说法.

谈 JavaScript 中的强制类型转换 (1. 基础篇)的更多相关文章

  1. 谈 JavaScript 中的强制类型转换 (2. 应用篇)

    这一部分内容是承接上一篇的, 建议先阅读谈 JavaScript 中的强制类型转换 (1. 基础篇) 前两章讨论了基本数据类型和基本包装类型的关系, 以及两个在类型转换中十分重要的方法: valueO ...

  2. 详细理解javascript中的强制类型转换

    将值从一种类型转换为另一种类型通常称为类型转换,这是显式的情况:隐式的情况称为强制类型转换,JavaScript 中的强制类型转换总是返回标量基本类型值,如字符串.数字和布尔值. 如何理解: 类型转换 ...

  3. 浅谈JavaScript中的闭包

    浅谈JavaScript中的闭包 在JavaScript中,闭包是指这样一个函数:它有权访问另一个函数作用域中的变量. 创建一个闭包的常用的方式:在一个函数内部创建另一个函数. 比如: functio ...

  4. C#中的强制类型转换与as转换的区别

    C#中的强制类型转换 例如有ClassA与ClassB两个类创建两个类的对象进行转换 1 2 ClassA a = new ClassA();  ClassB b = new ClassB(); 如果 ...

  5. JS在if中的强制类型转换

    JS在if中的强制类型转换 众所周知,JS在很多情况下会进行强制类型转换,其中,最常见两种是: 1.使用非严格相等进行比较,对==左边的值进行类型转换 2.在if判断时,括号内的值进行类型转换,转化为 ...

  6. 浅谈JavaScript中的null和undefined

    浅谈JavaScript中的null和undefined null null是JavaScript中的关键字,表示一个特殊值,常用来描述"空值". 对null进行typeof类型运 ...

  7. 浅谈JavaScript中的正则表达式(适用初学者观看)

    浅谈JavaScript中的正则表达式 1.什么是正则表达式(RegExp)? 官方定义: 正则表达式是一种特殊的字符串模式,用于匹配一组字符串,就好比用模具做产品,而正则就是这个模具,定义一种规则去 ...

  8. JavaScript基础&实战(2)js中的强制类型转换、运算符、关系运算符、逻辑运算符、条件运算符

    文章目录 1.强制类型转换Number 1.1 代码 1.2 测试结果 2.进制表示 2.1 代码 2.2 测试结果 3.强制类型转换为Boolea 3.1 代码 3.2 测试结果 4.运算符 4.1 ...

  9. 【总结】浅谈JavaScript中的接口

    一.什么是接口 接口是面向对象JavaScript程序员的工具箱中最有用的工具之一.在设计模式中提出的可重用的面向对象设计的原则之一就是“针对接口编程而不是实现编程”,即我们所说的面向接口编程,这个概 ...

随机推荐

  1. hdu 1358 Period 最小循环节

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1358 分析:已知字符串,求其由最小循环节构成的前缀字符串. /*Period Time Limit: ...

  2. Java IO 类一览表

    下表列出了大多数(非全部)按输/输出,基于字节或字符划分的 Java IO 类.

  3. Access时间日期函数大全

    这里特别推荐WeekdayName() 函数.MonthName() 函数,将日期转换为中文星期名与月份,如"星期一"."五月"一.Date() 函数.Now( ...

  4. Python教你找到最心仪的对象

    规则 单身妹妹到了适婚年龄,要选对象.候选男子100名,都是单身妹妹没有见过的.百人以随机顺序,从单身妹妹面前逐一经过.每当一位男子在单身妹妹面前经过时,单身妹妹要么选他为配偶,要么不选.如果选他,其 ...

  5. Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer)

    Java基础-虚拟内存之映射字节缓冲区(MappedByteBuffer) 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.映射字节缓冲区 1>.什么是虚拟内存 答:虚拟内 ...

  6. 浅谈fhq treap

    一.简介 fhq treap 与一般的treap主要有3点不同 1.不用旋转 2.以merge和split为核心操作,通过它们的组合实现平衡树的所有操作 3.可以可持久化 二.核心操作 代码中val表 ...

  7. Yii 自定义模型路径

    例如现有两个 Yii 项目,分别是 test1 和 test2.在 test1 中,已经有模型了,test2 直接调用 test1 中的模型,其实添加个别名,然后修改下配置即可. 先在 index.p ...

  8. Java 多线程(Thread) 同步(synchronized) 以及 wait, notify 相关 [实例介绍]

    场景描述 有一家很大的商场,在某市有几个商品配送中心,并有几家分店,这家商场经营很多的商品,平时运营情况是这样的: 根据各分店的商品销售情况,给分店配送相应需求量的商品:并上架到分店指让的位置,供客户 ...

  9. 在OS X 10.9配置WebDAV服务器联合NSURLSessionUploa…

    CHENYILONG Blog   在OS X 10.9配置WebDAV服务器联合NSURLSessionUploadTask实现文件上传iOS7推出的NSURLSession简化了NSURLConn ...

  10. HDU 3371 Connect the Cities 最小生成树(和关于sort和qsort的一些小发现)

    解题报告:有n个点,然后有m条可以添加的边,然后有一个k输入,表示一开始已经有k个集合的点,每个集合的点表示现在已经是连通的了. 还是用并查集加克鲁斯卡尔.只是在输入已经连通的集合的时候,通过并查集将 ...