在Js中, 强制类型转化分为两种情况: 一种是引用类型转化基本类型, 如数组转化成数字;一种是两种不同基本类型之间的转化,如字符串转化为数字。你不能将基本类型转化成引用类型,比如,不可能把数字转化为数组。 基本类型之间的转化相对容易,引用类型转化为基本类型则要复杂的多,转化又分为两种情况,转化为字符号或转化为数值

  当引用类型转化为字符串的时候,JS会先调用引用类型的toString 方法,看它能不能返回基本类型,如果能,则使用该基本类型,如果不能,则再调用引用类型的valueOf()方法,如果valueOf方法能返回基本数据类型则使用该基本数据类型 ,如果不能,就会抛出TypeError错误。你可能还记得 字符串 "[object object]"

var arr = [5, 5];
console.log(arr + ''); // "5, 5" 调用数组的toString()方法

  当引用类型转化为数值的时候,JS则先调用引用类型的valueOf()方法,同样是看它能不能返回基本类型,如果能就用,如果不能,则继续调用toString()方法,如果toString()方法也不能返回基本类型,则抛出TypeError错误。

console.log(+ new Date());  // 时间毫米数1513860979488, 数值类型

  知道了转化规则,我们就可以利用它来转化我们自定义的对象,但有的时候,转化并没有我们上面看到的那么简单,看下面的代码

var Money = function(val, sym) {
this.currentSysmbol = sym;
this.cents = val;
}
var dollar = new Money(100, '$'); console.log(+dollar); // NaN
console.log("Total" + dollar); // '[object, object]'

  得到的结果并没有什么意义,我们来给它提供toString, valueOf()方法

Money.prototype.toString = function() {
return this.currencySymbol + (this.cents / 100).toFixed(2);
}
Money.prototype.valueOf = function() {
return this.cents
}
console.log(+dollar); // number 100
console.log("" + dollar); // string 100

  这时你会发现一个问题:  " " +dollar, 按理说,它应该调用toString 方法,返回$1.00, 但它却返回了100, 证明它这里调用的是valueOf()方法,而不是toStirng()方法,这和我们的规则出现了不一致。 但是当我们把dollar 用数组包起来的时候,它返回调用的是toString()方法

console.log("" + [dollar])  // $1.00

  这时要看一下js的标准,

  

  转化成基本类型的抽象方法ToPrimitive 接受一个必选的参数(input argument) ,就是一个引用类型object和一个可选的参数(PreferredType), 然后把引用类型转化成基本类型。如果一个引用类型能够返回不止一个基本类型时,它就可能需要PreferredType 来决定返回哪一个。这个方法是怎么把引用类型转化成基本类型的?

  

  转化成基本类型,就是标准中所说的return a default value, 需要调用引用类型内置的方法,然后给它传递可选的参数(hint PreferredType). 如果再深入挖掘标准, 你会发现所说的方法,就是toString()和valueOf(), 返回字符串或数值, 到底是返回哪种基本类型取决于传入的可选参数hint PreferredType. 如果hint参数没有传递的话,它默认返回数值number。请下面的标准

  

  这也就解释了("" + dollar)为什么没有调用我们定义的toString()方法,而是调用valueOf()方法了, 因为我们没有提供hint PreferredType参数,默认返回了数值。基本操作符并不能直接用来计算引用类型,它只能计算基本类型, 当计算引用类型的时候,它进行强制类型转化,而这种转化到底转化成哪种基本类型,是js自己做决定。那我们能不能提供一个hint Preferred 参数,把决定权拿回到我们手里。很不幸,js并不没有提供这样的机制,也就是说,我们不能提供一个hint 参数给我们自己定义的对象

  但是当我们把dollar用数组括起来,它却调用了我们自定义的toString()方法. "" + [dollar] 返回 $1.00, 这又怎么解释呢? 这涉及了Js的内置对象。

  

    对于内置对象的来说, 它必须返回一个基本类型。我们把dollar用数组包括起来,但由于涉及到加号操作,所以[dollar] 要转化成基本类型,根据规则,它调用的valueOf()方法,但是数组的valueOf方法返回数组本身,不是基本类型。所以再调用数组的toString()方法,数组的toString()方法就是数组的每一项都调用toString()方法,然后再拼接起来,形成一个大的字符串,所以这里调用的是dollar 对象的toString()方法。

  我们可以模拟一个ToPrimitive的方法 

var ToPrimitive = function(obj) {
var funct, functions, val, _i, _length; functions = ['valueOf', 'toString']; if(typeof obj === 'object') {
// js 对Date日期对象作了区别处理, 先调用toString, 再调用toValue
if (obj instanceof Date) {
functions = ['toString', "valueOf"];
}
for(_i = 0, _length=functions.length; _i < _length; _i++){
funct = functions[_i];
// valueof 或 toString 方法都是函数时才调用
if (typeof obj[funct] === 'function') {
val = obj[funct]();
if (typeof val === 'string' || typeof val === 'number' || typeof val === 'boolean') {
return val;
}
}
}
// 如果两个方法都不能转化成基本数据类型,则抛出错误
throw new Error('DefualtValue is ambuiguos')
}
return obj; // 如果传递进来的参数不是引用类型,则返回
}

  现在我们已经明白了js的类型转化,再做一个复杂的例子加深一下印象, 下面这行代码输出多少

console.log(++[[]][+[]]+[+[]])

  1, 先计算数组内的元素+[], 前面的加号肯定是要数组转化成基本类型,数组转化成基本类型,只能调用它的toString()方法,空数组转化为空字符串'', +'' 表示对空字符串转化为数字,它这里调用的是Number()函数,所为转为化0, 现在变成了

console.log(++[[]][0]+[0])

  2, 加号左边[[]][0], 表示它取的是[[]] 里面的第0个位置的元素,[[]] 表示它是一个二维数组,数组里面包括数组,所以它的第0个位置上的元素还是数组,变成了

console.log(++[]+[0])

  3 , 左边是++[], 还是对数组进行基本类型转化,上面说了 [] 转化为空字符串,++‘’ 则变成了数字1,

console.log(1+[0])

  4, 右侧还是要做类型转化, 数组[0] 调用toString,则变成了字符串‘0’

console.log(1+'0')

  5, 最终的结果就是字符串‘10’

JS 强制类型转化的更多相关文章

  1. Python03 字符串类型、强制类型转化、列表、元组、字典、集合

    1 字符串类型 在python中字符串类型用str表示,字符串的连接用 + 1.1 创建字符串对象 ·创建一个字符串对象有两种方式,一种方式是直接用字符串进行赋值,另外一种是利用str类实例化对象:具 ...

  2. c++四种强制类型转化

    c++ 数据类型转换: static_cast dynamic_cast reinterpret_cast const_cast C++ 类型转换(C风格的强制转换): (1)将浮点型数据赋值给整型变 ...

  3. Delphi强制类型转化和类型约定

    强制类型转换时一种技术,通过它能够使编译器把一种类型的变量当做另一种类型. 由于Pascal有定义新类型的功能,因此编译器在调用一个函数时候对形参和实参类型匹配的检查是非常严格的.因此为了能够通过编译 ...

  4. C++之强制类型转化

    在C++语言中新增了四个关键字static_cast.const_cast.reinterpret_cast和dynamic_cast.这四个关键字都是用于强制类型转换的.我们逐一来介绍这四个关键字. ...

  5. Asp.net 面向接口可扩展框架之类型转化基础服务

    新框架正在逐步完善,可喜可贺的是基础服务部分初具模样了,给大家分享一下 由于基础服务涉及面太广,也没开发完,这篇只介绍其中的类型转化部分,命名为类型转化基础服务,其实就是基础服务模块的类型转化子模块 ...

  6. PHP之类型转化

    类型转化的判别 PHP在变量定义中不需要(或者不支持)明确的类型定义:变量类型是根据使用该变量的上下文所决定的, 也就是说,如果把一个string值付给变量$var,$var就成了一个string,如 ...

  7. C++四种类型转化

    2018-08-02 (星期四)C++类型转换:static_cast提供编译时期静态类型检测:    static_cast <type-id> (expression)    1)完成 ...

  8. static_cast, dynamic_cast, const_cast 三种类型转化的区别

    强制转化四种类型可能很多人都常常忽略就象我一样,但是有时还是比较有用的.不了解的建议看看,一些机制我也不是十分了解,只是将一些用法写出来让大家看看.                           ...

  9. js把其他类型转化成字符串

    js把其他类型转化成字符串 一.总结 一句话总结:类型转换中的强制类型转换分为类型转换函数和类型名强制.js后一种和其它语言不同,是类型类的构造方法.String() 二.js把其他类型转化成字符串 ...

随机推荐

  1. Generative Adversarial Nets[AAE]

    本文来自<Adversarial Autoencoders>,时间线为2015年11月.是大神Goodfellow的作品.本文还有些部分未能理解完全,不过代码在AAE_LabelInfo, ...

  2. 比起Windows,怎样解读Linux的文件系统与目录结构?

    比起Windows,怎样解读Linux的文件系统与目录结构? Linux 和Windows的文件系统有些不同,在学习使用 Linux 之前,若能够了解这些不同,会有助于后续学习. 本文先对Window ...

  3. 响应式卡片抽奖插件 CardShow

    GitHub: https://github.com/nzbin/CardShow/ Demo: https://nzbin.github.io/CardShow/ 前言 这个小项目(卡片秀)是一个卡 ...

  4. 基于注解处理器开发自动生成getter和setter方法的插件

    昨天无意中,逛到了lombok的网站,并看到了首页的5分钟视频,视频中的作者只是在实体类中写了几个字段,就可以自动编译为含setter.getter.toString()等方法的class文件.看着挺 ...

  5. mongo中的模糊查询

    以下是一个mongo查询的综合应用,即介绍一个生产中实际应用的模糊查询,当然其实也很简单,主要用到mongo中的模糊查询和$or查询,以及并的关系,下面是一个mongo中的一条记录 { "_ ...

  6. SQLite 实现删除表中前一天的数据

    注意点1 要注意SQLite datatime()函数为何获取不到系统本地时间?这个问题,坑死我了. 解决方法详见这篇文章:SQLite datatime()函数为何获取不到系统本地时间? 注意点2: ...

  7. 豆瓣读书爬虫(requests + re)

    前面整理了一些爬虫的内容,今天写一个小小的栗子,内容不深,大佬请忽略.内容包括对豆瓣读书网站中的书籍的基本信息进行爬取,并整理,便于我们快速了解每本书的中心. 一.爬取信息 每当爬取某个网页的信息时, ...

  8. 微软Ignite2018——微软宣布新的学习平台:Microsoft Learn

    Ignite 2018 首日感受 头一次参加美国的微软 Ignite 大会,确实规模比国内的大不少.23日是 MVP & RD 的 Pre Day(MVP即Most Valuable Prof ...

  9. python三:循环语句练习--小白博客

    # 打印0-10去掉5 count = - : count += : continue print(count) # 打印0-10的偶数 count = : print(count) count+= ...

  10. 【kindle笔记】之 《鬼吹灯》-9-20

    [kindle笔记]读书记录-总 9-20 日常吐槽 连着几天,基本是一口气读完了鬼吹灯. 想来,也算是阴差阳错了.本来是想看盗墓的,读了几页开头,心想坏了,拷贝错了,这是鬼吹灯-- 讲真的,每每读小 ...