JavaScript中数据类型转换
最近在项目中使用到字符串转数字。刚开始使用的是Number()
,结果可想而知。后来Review代码的时候,应该使用parseInt()
。我当时在纳闷,为什么要使用parseInt()
呢?结果老板甩过一句话,看规范去。现在项目可算暂告一段落,所以得自己整清楚Number()
和parseInt()
有什么区别。
数据类型
在学习数据类型转换之前,先简单点回忆一下JavaScript中的数据类型。在JavaScript中的每一个值,都属于某一种数据类型。JavaScript的数据类型有七种:
- Boolean:布尔值,
true
和false
两个特定值 - Null:表示无值,即此处的值就是“无”的状态
- Undefined: 表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值
- Number:整数和小数
- String:字符组成的文本
- Symbol (这个是ES6新定义的数据类型)
- Object:各种值组成的集合
其中Boolean
、Null
、Undefined
、Number
、String
和Symbol
称为原始类型(Primitive Type),即它们是最基本的数据类型,不能再细分。而Object
称为合成类型(Complex Type),因为一个对象往往是多个原始类型的值的合成,可以看作是一个存放各种值的容器。其中对象又可分成三个子类型:
- 侠义的对象(
object
) - 数组(
array
) - 函数(
function
)
数据类型检测
在JavaScript中有四种方法,可以确定一个值到底是什么类型:
typeof
运算符instanceof
运算符constructor
运算符Object.prototype.toString
方法
typeof运算符
typeof
运算符可以返回一个值的数据类型,可能有以下结果。
typeof 123; // => number
typeof `123`; // => string
typeof false; // => boolean
typeof fn; // => function
typeof undefined; // => undefined
typeof null; // => object
typeof window; // => object
typeof {}; // => object
typeof []; // => object
从上面的结果可以看出:
Number
、String
和Boolean
值分别返回number
、string
、boolean
Function
返回function
Undefined
和未赋值的变量,返回undefined
Null
、{}
、[]
和window
返回object
instanceof运算符
在typeof
方法中,对[]
、{}
显示的结果都是object
。那么怎么区分它们呢?JavaScript中引入了另一个运算符instanceof
来解决这个问题。instanceof
和typeof
相似,用于识别正在处理的对象的类型。与typeof
方法不同的是,instanceof
运算符要求开发者明确地确认对象为某特定类型。
instanceof
运算符用于检查某个对象的原型链是否包含某个构造函数的prototype
属性。例如:
obj instanceof Widget
obj
的原型链上有很多对象(隐式原型),比如obj.__proto__
、obj.__proto__.__proto__
等。如果这些对象里存在一个p === Widget.prototype
,那么instanceof
结果为true
,否则为false
。
来看个示例,比如在JavaScript中,使用instanceof
来判断A
是否为B
的实例对,表达式为A instanceof B
,如果A
是B
的实例则返回true
,否则返回false
。在这里需要特别注意的是:instanceof
检测的是原型,来看段代码:
// 定义构造函数
function L() {};
function R() {};
var L = new L();
var P = new R();
function instance_of(L, R) {//L 表示左表达式,R 表示右表达式
var O = R.prototype;// 取 R 的显示原型
L = L.__proto__;// 取 L 的隐式原型
while (true) {
if (L === null)
return false;
if (O === L)// 这里重点:当 O 严格等于 L 时,返回 true
return true;
L = L.__proto__;
}
}
instance_of(L, R); // => false
在JavaScript原型继承结构里面,用[[Prototype]]
表示对象隐式的原型,在JavaScript中用__proto__
表示,并且在Firefox和Chrome浏览器中是可以访问得到这个属性的,但是IE下不行。所有JavaScript对象都有__proto__
属性,但只有Object.prototype.__proto__
为null
,前提是没有在Firefox或者Chrome下修改过这个属性。这个属性指向它的原型对象。到于显示的原型,在JavaScript里用prototype
属性表示。用张图来表示:
由于instanceof
是通过原型链来检查类型的,所以适用于任何object
的类型检查。下面是instanceof
使用的几个情景:
// 比如直接原型关系
function A () {}
(new A) instanceof A; // => true
// 原型链上的间接原型
function B () {}
B.prototype = new A
(new B) instanceof A // => true
instanceof
也可以用来检测内置兑现,比如Array
、RegExp
、Object
和Function
:
[1, 2, 3] instanceof Array; // => true
/abc/ instanceof RegExp; // => true
({}) instanceof Object; // => true
(function (){}) instanceof Function; // => true
instanceof
对基本数据类型不起作用,因为基本数据类型没有原型链。
3 instanceof Number; // => false
true instanceof Boolean; // => false
`abc` instanceof String; // => false
null instanceof XXX; // => always false
undefined instanceof XXX; // => always false
但可以这样使用:
new Number(3) instanceof Number; // => true
new Boolean(true) instanceof Boolean; // => true
new String('abc') instanceof String; // => true
前面的示例告诉我们,虽然instanceof
能够判断出[]
是Array
的实例,但它认为[]
也是Object
的实例,为什么呢?我们来分析一下[]
、Array
和Object
三者之间的关系:从instanceof
能够判断出[].__proto__
指向Array.prototype
,而Array.prototype.__proto__
又指向了Object.prototype
,Object.prototype.__proto__
指向了null
,标志着原型链的结束。因此,[]
、Array
和Object
就形成了如下图所示的一条原型链:
从原型链可以看出,[]
的 __proto__
直接指向Array.prototype
, 间接指向Object.prototype
, 所以按照 instanceof
的判断规则,[]
就是Object
的实例。
instanceof
只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型。
constructor运算符
当一个函数foo
被定义时,JavaScript会给foo
函数添加prototype
原型,然后再在prototype
上添加一个constructor
属性,并让其指向foo
的引用,如下所示:
当执行var bar = new foo()
时,foo
被当成了构造函数,bar
是foo
的实例对象,此时foo
原型上的constructor
传递到了bar
上,因此bar.constructor == foo
(返回的是一个true
)。
可以看出,JavaScript在函数foo
的原型上定义了constructor
,当foo
被当作构造函数用来创建对象时,创建的新对象就被标记为foo
类型,使得新对象有名有姓,可以追溯。同理,JavaScript中的数据类型也遵守这个规则:
'123'.constructor == String;
123.constructor == Number;
true.constructor == Boolean;
[1, 2, 3].constructor == Array;
{}.constructor == Object;
new Function().constructor == Function;
new Date().constructor == Date;
new Error().constructor == Error;
document.constructor == HTMLDocument;
window.constructor == Window;
null.constructor == Object;
undefined.constructor == Object;
在JavaScript中null
和undefined
是比较特殊的数据类型,也是无效的对象,因此是不会有constructor
存在的,这两种类型的数据需要通过typeof
来判断。另外,JavaScript对象的constructor
是不稳定的,这个主要体现在自定义对象上,当开发者重写prototype
后,原有的constructor
会丢失,constructor
会默认为Object
。
function foo() {}
foo.prototype = {a: 'xxx'}
var bar = new foo()
bar.constructor == foo
bar.constructor
为什么变成了Object
?
prototype
被重新赋值的是一个{}
,{}
是new Object()
的字面量,因此new Object()
会将Object
原型上的constructor
传递给{}
,也就是Object
本身。因此,为了规范,在重写对象原型时一般都需要重新给constructor
赋值,以保证实例对象的类型不被改写。
Object.prototype.toString
toString
是Object
原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 toString
运行时this
指向的对象类型, 返回的类型格式为[object,xxx]
,xxx
是具体的数据类型,其中包括:String
,Number
,Boolean
,Undefined
,Null
,Function
,Date
,Array
,RegExp
,Error
,HTMLDocument
,... 基本上所有对象的类型都可以通过这个方法获取到。
Object.prototype.toString.call('') ; // [object String]
Object.prototype.toString.call(1) ; // [object Number]
Object.prototype.toString.call(true) ; // [object Boolean]
Object.prototype.toString.call(undefined) ; // [object Undefined]
Object.prototype.toString.call(null) ; // [object Null]
Object.prototype.toString.call(new Function()) ; // [object Function]
Object.prototype.toString.call(new Date()) ; // [object Date]
Object.prototype.toString.call([]) ; // [object Array]
Object.prototype.toString.call(new RegExp()) ; // [object RegExp]
Object.prototype.toString.call(new Error()) ; // [object Error]
Object.prototype.toString.call(document) ; // [object HTMLDocument]
Object.prototype.toString.call(window) ; //[object global] window是全局对象global的引用
需要注意的是,必须通过Object.prototype.toString.call
来获取,而不能直接 new Date().toString()
, 从原型链的角度讲,所有对象的原型链最终都指向了Object
, 按照JS变量查找规则,其他对象应该也可以直接访问到Object的toString
方法,而事实上,大部分的对象都实现了自身的toString
方法,这样就可能会导致Object的toString
被终止查找,因此要用call
来强制执行Object
的toString
方法。
简单总结一下:
typeof
只能检测基本数据类型,对于null
还有Bug;instanceof
适用于检测对象,它是基于原型链运作的;constructor
指向的是最初创建者,而且容易伪造,不适合做类型判断;Object.prototype.toString
适用于ECMA内置JavaScript类型(包括基本数据类型和内置对象)的类型判断;- 基于引用判等的类型检查都有跨窗口问题,比如
instanceof
和constructor
。
总之,如果你要判断的是基本数据类型或JavaScript内置对象,使用Object.prototype.toString
; 如果要判断的时自定义类型,请使用instanceof
。
@Todd的《Understanding JavaScript types and reliable type checking》对数据类型判断提供了一个简单的仓库axis.js:
(function (root, factory) {
// 判断是否使用了模块
if (typeof define === 'function' && define.amd) {
// 使用AMD模块
define(factory);
} else if (typeof exports === 'object') {
// 使用CMD模块
module.exports = factory;
} else {
// 没有使用模块,放在全局下
root.axis = factory();
}
})(this, function () {
// 严格模式
'use strict';
var exports = {};
// 将字符串转为数组
var types = 'Array Object String Date RegExp Function Boolean Number Null Undefined'.split(' ');
// 判断类型
var type = function () {
return Object.prototype.toString.call(this).slice(8, -1);
};
// 遍历types,为exports对象添加isArray、isObject...等方法
for (var i = types.length; i--;) {
exports['is' + types[i]] = (function (self) {
return function (elem) {
// type.call(elem)将type方法里的this指针指向elem
return type.call(elem) === self;
};
})(types[i]);
}
return exports;
});
使用方法也很简单:
axis.isArray([]); // true
axis.isObject({}); // true
axis.isString(''); // true
axis.isDate(new Date()); // true
axis.isRegExp(/test/i); // true
axis.isFunction(function () {}); // true
axis.isBoolean(true); // true
axis.isNumber(1); // true
axis.isNull(null); // true
axis.isUndefined(); // true
扩展阅读
- 如何检查JavaScript变量类型?
- Checking Types in Javascript
- Inheritance in JavaScript: understanding the constructor property
- Improving the JavaScript typeof operator
- Type Checking Techniques in JavaScript: Part 1 of 2
- Type Checking Techniques in JavaScript Part 2 of 2
- Understanding JavaScript types and reliable type checking
- JavaScript的变量:变量值的数据类型
数据类型转换
前面我们回忆了JavaScript中的数据类型和数据类型检测的方法。那么回到本文的正题,数据类型转换。在JavaScript中,数据类型转换主要有以下几种。
强制转换
强制转换主要是指使用Number()
、String()
和Boolean()
三个构造函数,手动将各种类型的值,转换成number
、string
和boolean
。
- 使用
Number()
函数,可以将任意类型的值转化成数值 - 使用
String()
函数,可以将任意类型的值转换成字符串 - 使用
Boolean()
函数,可以将任意类型的变量转换为布尔值
Number()
Number()可以将任意类型的值转化成数值。
// 数值:转换后还是原来的值
Number(123); // => 123
// 字符串:如果可以被解析为数值,则转换为相应的数值
Number('123'); // => 123
// 字符串:如果不可以被解析为数值,返回NaN
Number('123abc'); // => NaN
// 空字符串转换为0
Number(''); // => 0
// 布尔值:true转成1,false转成0
Number(true); // => 1
Number(false); // => 0
// undefined: 转换成NaN
Number(undefined); // => NaN
// null: 转成0
Number(null); // => 0
// 对象:将返回NaN,除非是包含单个数值的数组
Number({a: 1}); // => NaN
Number([1, 2, 3]); // => NaN
Number([1]); // => 1
String()
使用String()
,可以将任意类型的值转化成字符串。
// 数值: 转为相应的字符串
String(123); // => '123'
// 字符串: 转换后还是原来的值
String('123'); // => '123'
// 布尔值: true转为'true',false转为'false'
String(true); // => 'true'
String(false); // => 'false'
// undefined: 转为'undefined'
String(undefined); // => 'undefined'
// null: 转为'null'
String(null); // => 'null'
// 对象:返回一个类型字符串
// 数组:返回该数组的字符串形式
String({a: 1}); // => [object Object]
String([1, 2, 3]); // => '1,2,3'
Boolean()
使用Boolean()
,可以将任意类型的变量转为布尔值。
它的转换规则相对简单:除了以下六个值的转换结果为false
,其他的值全部为true
。
Boolean(undefined); // => false
Boolean(null); // => false
Boolean(0); // => false
Boolean(NaN); // => false
Boolean(''); // => false
**注意:**所有对象,包括空对象的转换结果都是true
,甚至连false
对应的布尔对象new Boolean(false)
也是true
:
Boolean({}); // => true
Boolean([]); // => true
Boolean(new Boolean(false)); // => true
所有对象的布尔值都是true
,这是因为JavaScript语言设计的时候,出于性能的考虑,如果对象需要计算才能得到布尔值,对于obj1 && obj2
这样的场景,可能会需要较多的计算。为了保证性能,就统一规定,对象的布尔值为true
。
自动转换
在JavaScript中,除了手动强制转换之外,还存在自动转换,而它的转换是以强制转换为基础的。
遇到下面的情形,JavaScript会自动转换数据类型,即转换是自动完成的,对用户不可见。
// 不同类型的数据互相运算
123 + 'abc'; // => '123abc'
// 对非布尔值类型的数据求布尔值
if ('abc') {
console.log('hello'); // => 'hello'
}
// 对非数值类型的数据使用一元素运算符即+和-
+ {foo: 'bar'}; // => NaN
- [1,2,3]; // => NaN
自动转换的规则是这样的:预期什么类型的值,就调用该类型的转换函数。比如,某个位置预期为字符串,就调用String
函数进行转换。如果该位置即可以是字符串,也可能是数值,那么默认转为数值。
由于自动转换具有不确定性,而且不易除错,建议在预期为布尔值、数值、字符串的地方,全部使用Boolean
、Number
和String
函数进行显式转换。
当JavaScript遇到预期为布尔值的地方(比如if
语句的条件部分),就会将非布尔值的参数自动转换为布尔值。系统内部会自动调用Boolean
函数。
因此除了以下六个值,其他都是自动转为true
。
undefined
null
-0
0
或+0
''
下面这个例子中,条件部分的每个值都相当于false
,使用否定运算符后,就变成了true
。
if ( !undefined
&& !null
&& !0
&& !NaN
&& !''
) {
console.log('true');
} // true
下面两种写法,有时也用于将一个表达式转为布尔值。它们内部调用的也是Boolean
函数。
// 写法一
expression ? true : false
// 写法二
!! expression
当JavaScript遇到预期为字符串的地方,就会将非字符串的数据自动转为字符串。系统内部会自动调用String
函数。字符串的自动转换,主要发生在加法运算时。当一个值为字符串,另一个值为非字符串,则后者转为字符串。
'5' + 1 // '51'
'5' + true // "5true"
'5' + false // "5false"
'5' + {} // "5[object Object]"
'5' + [] // "5"
'5' + function (){} // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"
这种自动转换很容易出错。
var obj = {
width: '100'
};
obj.width + 20 // "10020"
上面代码中,开发者可能期望返回120
,但是由于自动转换,实际上返回了一个字符10020
。
当JavaScript遇到预期为数值的地方,就会将参数值自动转换为数值。系统内部会自动调用Number
函数。除了加法运算符有可能把运算子转为字符串,其他运算符都会把运算子自动转成数值。
'5' - '2' // 3
'5' * '2' // 10
true - 1 // 0
false - 1 // -1
'1' - 1 // 0
'5' * [] // 0
false / '5' // 0
'abc' - 1 // NaN
上面代码中,运算符两侧的运算子,都被转成了数值。
一元运算符也会把运算子转成数值。
+'abc' // NaN
-'abc' // NaN
+true // 1
-false // 0
隐式类型转换
JavaScript的数据类型是非常弱的。在使用算术运算符时,运算符两边的数据类型可以是任意的,比如,一个字符串可以和数字相加。之所以不同的数据类型之间可以做运算,是因为JavaScript在运算之前会悄悄地把他们进行隐式类型转换,如:
3 + true; // => 4
结果是一个数值型。多数情况下,在JavaScript中比如运到-
、*
、/
和%
等算术运算都会把操作数转换成数字的,但是+
和其他的有点不一样,有些情况下,它是算术加号,有些情况下是字符串连接符,具体的看它的操作数。
2 + 3; // => 5
'hello' + ' world'; // => 'hello world'
但是,如果字符串和数字相加,不管数字在+
前还是后,都会转换成字符串,如:
'4' + 8; // => '48'
4 + '8'; // => '48'
此外,需要注意的是,+
的运算符方向是从左到右,如:
1 + 2 + '3'; // => '33'
有关于这方面的可以阅读早前整理的《JavaScript:为什么3+true=4?》一文。
在JavaScript中,隐式类型思考换有时候会隐藏一些错误的,比如null
会转换为0
,undefined
会转换成NaN
。需要注意的是:NaN
和NaN
是不相等的:
var x = NaN;
x === NaN; // => false
虽然在JavaScript中提供了isNaN来检测某个值是否为NaN
,但是,这也不太精确的,在调用isNaN
之前,本知就存在一个隐式转换的过程,它会把那些原本不是NaN
的值转换为NaN
:
isNaN('foo'); // => true
isNaN(undefined); // => true
isNaN({}); // => true
isNaN({a:'xxx'}); // => true
接着再来看看对象的隐式转换:
// 对象可以转换成原始值的,把它转换成字符串
'The Math Objec: ' + Math; // => 'The Math Object:' [object Math]'
'The JSON Object:' + JSON; // => 'The JSON Object:' [object JSON]'
// 对象转换成字符串
Math.toString(); // => '[object Math]'
JSON.toString(); // => '[object JSON]'
// 对象可以转换成数字
'J' + {toString: function (){ return 'S'}}; // => 'JS'
2 * {valueOf: function() {return 3}}; // => 6
如果,一个对象同时存在valueOf
和toString
时,那么valueOf
总是会先被调用:
var obj = {
toString: function() {
return '[object MyObject]';
},
valueOf: function() {
return 1
}
};
'Object: ' + obj; // => 'Object: 1'
但是,多数情况下,这都不是我们想要的,一般的,尽可能使valueOf和toString表示的值相同。
提出来说:转换为数字类型
最初提出的是字符串转换为数字,但其中发现,有时候取到的值是undefined
之类。前面学习了Number()
来转换。但在JavaScript中,除了Number()
之外,还可以通过parseInt()
和parseFloat()
来转换。那这三者之中有何不同呢?
parseInt()
与parseFloat()
只能在String
类型上调用,而Number()
不仅限于String
类型,比如Date
类型上也可以使用。
parseInt()
在判断字符串是否是数字值前,parseInt()
和parseFloat()
都会仔细分析该字符串。
parseInt()
方法首先查看位置 0
处的字符,判断它是否是个有效数字;如果不是,该方法将返回NaN
,不再继续执行其他操作。但如果该字符是有效数字,该方法将查看位置 1
处的字符,进行同样的测试。这一过程将持续到发现非有效数字的字符为止,此时parseInt()
将把该字符之前的字符串转换成数字。
例如,如果要把字符串 “12345red”
转换成整数,那么parseInt()
将返回 12345
,因为当它检查到字符 r
时,就会停止检测过程。
字符串中包含的数字字面量会被正确转换为数字,比如 “0xA”
会被正确转换为数字 10
。不过,字符串 “22.5”
将被转换成 22
,因为对于整数来说,小数点是无效字符。
示例如下:
var iNum1 = parseInt("12345red");// => 12345
var iNum1 = parseInt("0xA"); // => 10
var iNum1 = parseInt("56.9"); // => 56
var iNum1 = parseInt("red"); // => NaN
parseInt()
方法还有基模式,可以把二进制、八进制、十六进制或其他任何进制的字符串转换成整数。基是由parseInt()
方法的第二个参数指定的,所以要解析十六进制的值,需如下调用parseInt()
方法:
var iNum1 = parseInt("AF", 16); // => 175
当然,对二进制、八进制甚至十进制(默认模式),都可以这样调用parseInt()
方法:
var iNum1 = parseInt("10", 2); // => 2
var iNum2 = parseInt("10", 8); // => 8
var iNum3 = parseInt("10", 10); // => 10
如果十进制数包含前导 0
,那么最好采用基数 10
,这样才不会意外地得到八进制的值。例如:
var iNum1 = parseInt("010"); //返回 8
var iNum2 = parseInt("010", 8); //返回 8
var iNum3 = parseInt("010", 10);//返回 10
在这段代码中,两行代码都把字符 “010”
解析成一个数字。第一行代码把这个字符串看作八进制的值,解析它的方式与第二行代码(声明基数为 8
)相同。最后一行代码声明基数为 10
,所以iNum3
最后等于 10
。
parseFloat()
parseFloat()
方法与parseInt()
方法的处理方式相似,从位置 0
开始查看每个字符,直到找到第一个非有效的字符为止,然后把该字符之前的字符串转换成整数。
不过,对于这个方法来说,第一个出现的小数点是有效字符。如果有两个小数点,第二个小数点将被看作无效的。parseFloat()
会把这个小数点之前的字符转换成数字。这意味着字符串 “11.22.33”
将被解析成 11.22
。
使用parseFloat()
方法的另一不同之处在于,字符串必须以十进制形式表示浮点数,而不是用八进制或十六进制。该方法会忽略前导 0
,所以八进制数 0102
将被解析为 102
。对于十六进制数 0xA
,该方法将返回 NaN
,因为在浮点数中,x
不是有效字符。(注释:经测试,具体的浏览器实现会返回 0
,而不是 NaN
。)
此外,parseFloat()
方法也没有基模式。
以下是使用示例:
var fNum1 = parseFloat("12345red");// => 12345
var fNum2 = parseFloat("0xA"); // => NaN
var fNum3 = parseFloat("11.2"); // => 11.2
var fNum4 = parseFloat("11.22.33");// => 11.22
var fNum5 = parseFloat("0102"); // => 102
var fNum1 = parseFloat("red"); // => NaN
Number()
Number()
函数的强制类型转换与parseInt()
和parseFloat()
方法的处理方式相似,只是它转换的是整个值,而不是部分值。
Number()
属于强类型转换,使用强制类型转换可以访问特定的值,即使它是另一种类型。
parseInt()
和parseFloat()
方法只转换第一个无效字符之前的字符串,因此 “1.2.3”
将分别被转换为 “1”
和 “1.2”
。
用Number()
进行强制类型转换,”1.2.3″
将返回 NaN
,因为整个字符串值不能转换成数字。如果字符串值能被完整地转换,Number()
将判断是调用parseInt()
方法还是parseFloat()
方法。
下例使用Number()
来转换 Date
对象为数字值(时间戳):
var date = new Date('Tue Jun 14 2016 00:00:00');
console.log(Number(date));// => 1465833600000
以下代码说明了不同值调用Number()
会发生的情况:
Number(false); // => 0
Number(true); // => 1
Number(undefined); // => NaN
Number(null); // => 0
Number('1.2'); // => 1.2
Number('12'); // => 12
Number('1.2.3'); // => NaN
Number(new Object({}));// => NaN
Number(50); // => 50
巧妙的数据类型转换
前面花了很大的篇幅了解JavaScript的数据类型、数据类型检测和数据转换。在实战中,有些数据类型的转换我们可以使用一些巧妙的方式来调用JavaScript提供的数据类型转换函数来实现。以下是实际可用的JavaScript实现的九种数据类型转换的函数。
toPrimitive
toBoolean
toNumber
toInteger
toInt32
toUint16
toString
toObject
其中toPrimitive
和toInteger
为自定义实现。
// type Primitive = Undefined | Null | Boolean | Number | String
// data Hint = undefined | "string" | "number"
// toPrimitive:: (a,Hint) -> Error String Primitive
function toPrimitive(v,hint) {
// isPrimitive:: a -> Boolean
function isPrimitive(v){
var type = typeof v;
return (type === typeof undefined ||
type === typeof true ||
type === typeof 0 ||
type === typeof "" ||
v === null) ? true : false;
}
if(isPrimitive(v)) {
return v;
}
if(arguments.length == 1 || typeof hint === typeof undefined) {
hint = v instanceof Date ? "string" : "number";
}
var val;
if(hint.toLowerCase() == "string"){
val = v.toString();
if(isPrimitive(val)) {
return val;
}
val = v.valueOf();
if(isPrimitive(val)) {
return val;
}
}else{
val = v.valueOf();
if(isPrimitive(val)) {
return val;
}
val = v.toString();
if(isPrimitive(val)) {
return val;
}
}
throw "TypeError";
}
// toBoolean:: a -> Boolean
function toBoolean(v) {
return !!v;
}
// toNumber:: a -> Number
function toNumber(v) {
return +v;
}
// toInteger:: a -> Integer
function toInteger(v) {
var number = toNumber(v);
if(isNaN(number)) {
return +0;
}
if(number === 0 || !isFinite(number)){
return number;
}
if(number >= 0 ) {
return Math.floor(number);
}else{
return Math.ceil(number);
}
}
// toInt32:: a -> Int32
function toInt32(v) {
return v>>0;
}
// toUint32:: a -> Uint32
function toUint32(v) {
return v>>>0;
}
// toUint16:: a -> Uint16
function toUint16(v) {
return String.fromCharCode(v).charCodeAt(0);
}
// toString:: a -> String
function toString(v) {
return ""+v;
}
// toObject:: a -> Error String Object
function toObject(v){
if(typeof v === typeof undefined || v === null) {
throw "TypeError";
}
return Object(v);
}
扩展阅读
总结
文章以字符串如何转换成数值为引子,介绍了JavaScript中的数据类型、数据类型检测和数据转换相关的知识。文中可能有不对之处,还望在下面的评论中指正。如果你在这方面有不同的见解,欢迎分享
如需转载,烦请注明出处:https://www.fedev.cn/javascript/data-type-conversion.htmlnike free run 5.0 custom