在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. Jmeter+ant+jenkins集成

    已有jmeter.*.jmx脚本 一.jmeter+ant 1.下载安装ant(检查是否安装成功) 2.将 JMeter 所在目录下 extras 子目录里的 ant-JMeter-1.1.1.jar ...

  2. ASP MD5

    <% Private Const BITS_TO_A_BYTE = 8 Private Const BYTES_TO_A_WORD = 4 Private Const BITS_TO_A_WOR ...

  3. vue文档全局api笔记1

    全局api方法 1.Vue.extend(options) 请注意,extend创建的是一个组件构造器,而不是一个具体的组件实例.所以他不能直接在new Vue中这样使用: new Vue({comp ...

  4. iptables防火墙规则的添加、删除、修改、保存

    原文地址:https://blog.csdn.net/educast/article/details/52093390 本文介绍iptables这个Linux下最强大的防火墙工具,包括配置iptabl ...

  5. 福州大学软件工程1816 | W班 第8次作业[团队作业,随堂小测——校友录]

    作业链接 团队作业,随堂小测--校友录 评分细则 本次个人项目分数由两部分组成(博客分满分40分+程序得分满分60分) 博客和程序得分表 评分统计图 千帆竞发图 总结 旅法师:实现了更新,导出,查询, ...

  6. 给网站配置免费的HTTS证书

    取经自思否:https://segmentfault.com/a/1190000015231137 https 的网站 搜索引擎 会优先收录,所以就抽时间记录下配置博客的过程,各种找资料,终于给我找到 ...

  7. vue学习的笔记补充

    // vue-router中可以使用 routes:[ { path:'/', name:'index', component:()=>import('./index') } ] // 这种写法 ...

  8. a标签中的onclick和href的使用

    onclick和href 链接的 onclick 事件被先执行,其次是 href 属性下的动作(页面跳转,或 javascript 伪链接):  假设链接中同时存在 href 与 onclick,如果 ...

  9. Azure系列2.1.10 —— CloudBlobClient

    (小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...

  10. Windows 机器上面同时安装mysql5.6 和 mysql5.7 的方法

    1. 自己遇到的两个坑: . mysql 登录的时候 需要使用-P 来指定端口号 不然默认走 呢 . mysql 5.6 和 mysql 5.7 更改用户密码的命令不一样.. 我这边浪费了很长时间: ...