现代 CSS

JavaScript中数据类型转换

特别声明:如果您喜欢小站的内容,可以点击申请会员进行全站阅读。如果您对付费阅读有任何建议或想法,欢迎发送邮件至: airenliao@gmail.com!或添加QQ:874472854(^_^)

最近在项目中使用到字符串转数字。刚开始使用的是Number(),结果可想而知。后来Review代码的时候,应该使用parseInt()。我当时在纳闷,为什么要使用parseInt()呢?结果老板甩过一句话,看规范去。现在项目可算暂告一段落,所以得自己整清楚Number()parseInt()有什么区别。

数据类型

在学习数据类型转换之前,先简单点回忆一下JavaScript中的数据类型。在JavaScript中的每一个值,都属于某一种数据类型。JavaScript的数据类型有七种:

  • Boolean:布尔值,truefalse两个特定值
  • Null:表示无值,即此处的值就是“无”的状态
  • Undefined: 表示“未定义”或不存在,即由于目前没有定义,所以此处暂时没有任何值
  • Number:整数和小数
  • String:字符组成的文本
  • Symbol (这个是ES6新定义的数据类型)
  • Object:各种值组成的集合

其中BooleanNullUndefinedNumberStringSymbol称为原始类型(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

从上面的结果可以看出:

  • NumberStringBoolean值分别返回numberstringboolean
  • Function返回function
  • Undefined和未赋值的变量,返回undefined
  • Null{}[]window返回object

instanceof运算符

typeof方法中,对[]{}显示的结果都是object。那么怎么区分它们呢?JavaScript中引入了另一个运算符instanceof来解决这个问题。instanceoftypeof相似,用于识别正在处理的对象的类型。与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,如果AB的实例则返回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也可以用来检测内置兑现,比如ArrayRegExpObjectFunction

[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的实例,为什么呢?我们来分析一下[]ArrayObject三者之间的关系:从instanceof能够判断出[].__proto__指向Array.prototype,而Array.prototype.__proto__又指向了Object.prototypeObject.prototype.__proto__指向了null,标志着原型链的结束。因此,[]ArrayObject就形成了如下图所示的一条原型链:

从原型链可以看出,[]__proto__ 直接指向Array.prototype, 间接指向Object.prototype, 所以按照 instanceof 的判断规则,[] 就是Object的实例。

instanceof 只能用来判断两个对象是否属于原型链的关系, 而不能获取对象的具体类型

constructor运算符

当一个函数foo被定义时,JavaScript会给foo函数添加prototype原型,然后再在prototype上添加一个constructor属性,并让其指向foo的引用,如下所示:

当执行var bar = new foo()时,foo被当成了构造函数,barfoo的实例对象,此时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中nullundefined是比较特殊的数据类型,也是无效的对象,因此是不会有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

toStringObject原型对象上的一个方法,该方法默认返回其调用者的具体类型,更严格的讲,是 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来强制执行ObjecttoString方法。

简单总结一下:

  • typeof只能检测基本数据类型,对于null还有Bug;
  • instanceof适用于检测对象,它是基于原型链运作的;
  • constructor指向的是最初创建者,而且容易伪造,不适合做类型判断;
  • Object.prototype.toString适用于ECMA内置JavaScript类型(包括基本数据类型和内置对象)的类型判断;
  • 基于引用判等的类型检查都有跨窗口问题,比如instanceofconstructor

总之,如果你要判断的是基本数据类型或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中的数据类型和数据类型检测的方法。那么回到本文的正题,数据类型转换。在JavaScript中,数据类型转换主要有以下几种。

强制转换

强制转换主要是指使用Number()String()Boolean()三个构造函数,手动将各种类型的值,转换成numberstringboolean

  • 使用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函数进行转换。如果该位置即可以是字符串,也可能是数值,那么默认转为数值。

由于自动转换具有不确定性,而且不易除错,建议在预期为布尔值、数值、字符串的地方,全部使用BooleanNumberString函数进行显式转换。

当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会转换为0undefined会转换成NaN。需要注意的是:NaNNaN是不相等的

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

如果,一个对象同时存在valueOftoString时,那么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

其中toPrimitivetoInteger为自定义实现。

// 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中的数据类型、数据类型检测和数据转换相关的知识。文中可能有不对之处,还望在下面的评论中指正。如果你在这方面有不同的见解,欢迎分享

大漠

常用昵称“大漠”,W3CPlus创始人,目前就职于手淘。对HTML5、CSS3和Sass等前端脚本语言有非常深入的认识和丰富的实践经验,尤其专注对CSS3的研究,是国内最早研究和使用CSS3技术的一批人。CSS3、Sass和Drupal中国布道者。2014年出版《图解CSS3:核心技术与案例实战》。

如需转载,烦请注明出处:https://www.w3cplus.com/javascript/data-type-conversion.htmlnike free run 5.0 custom

返回顶部