不可不知的javascript类型转换

120次阅读
没有评论

共计 4930 个字符,预计需要花费 13 分钟才能阅读完成。

JavaScript 中有七种类型,它们互相之间可以转换,但要搞清楚其中的转换关系可不简单。

JavaScript 类型

类型种类

在 JS 中,有 6 种基本类型和一种引用类型,分别是:

基本类型

  • null
  • undefined
  • boolean
  • number
  • string
  • symbol(ES6 新增)

引用类型
object

类型检测

一般来说,我们可以用 typeof 来检测某个值的数据类型,比如:

typeof undefined     === "undefined"; // true
typeof true          === "boolean";   // true
typeof 24            === "number";    // true
typeof "24"          === "string";    // true
typeof {age: 24}  === "object";    // true

// added in ES6!
typeof Symbol()      === "symbol";    // true

但是有一个例外: null, 这也是一个 bug

typeof null === "object"; // true

如果想检测某个值是否是 null,则可以这样:

var a = null;
(!a && typeof a === "object"); // true

需要注意的是,function 和 array 其实也是 object,但它们有所区别:

typeof function a(){ /* .. */} === "function"; // true
typeof [1,2,3] === "object"; // true

如果要检测 a 是否是数组,可以用 instanceof

var a = [123];
a instanceof Array; // true

类型转换抽象操作

ToString

当一个非 String 类型的值要转换为 String,我们可以用 ToString 操作。

toString()

对于基本类型来说,它们有自然的转换关系。如:null 变成 ”null”,undefined 变成 ”undefined”,true 变成 ”true”,number 自然转换为数字字符串,但如果对于非常大的数,则会转换为指数形式。

对于 object 来说,toString()(代表着 Object.prototype.toString()) 将会返回 [[class]] 原型,比如说 ”object Object”; 但如果是数组,则重写了 toString() 方法,会返回一个以逗号分隔数组值的字符串。比如:

var a = [1,2,3];
a.toString(); // "1,2,3"

JSON.stringify()

另一种转换为字符串的方法就是 JSON.stringify,对大多数基本类型,它的转换方法和 toString 是一样的:

JSON.stringify(42);    // "42"
JSON.stringify("42");    // ""42"" (外面多加一层引号)
JSON.stringify(null);    // "null"
JSON.stringify(true);    // "true"

但不同的是,JSON.stringify 会忽略掉 undefined、function 和 symbol。请看下面的例子:

JSON.stringify(undefined);    // undefined
JSON.stringify(function(){});    // undefined

JSON.stringify([1,undefined,function(){},4] );    // "[1,null,null,4]"
JSON.stringify({ a:2, b:function(){}} );    // "{"a":2}"

如果 JSON.stringify 调用了循环引用的 object,则会抛出 Error。如果 JSON.stringify 调用的对象有toJSON() 方法,则会对 toJSON()的返回值再进行 stringify。

var a = {b: 111};
a.toJSON = function() {return { b: this.b};
};

JSON.stringify(a); // "{"b":111}"

var c = {val: [1,2,3],

    toJSON: function(){return this.val.slice( 1);
    }
};
JSON.stringify(c); // "[2,3]"

ToNumber

转换为 number,我们可以用 ToNumber 操作。

Number()

对于基本类型,转换规则为:true -> 1,false -> 0,undefined -> NaN,null -> 0,字符串如果包含字母则转换为 NaN。

对于将某值转换为基本数据类型,通常会调用 ToPrimitive 操作,首先看该值有没有 valueof()方法,如果没有则调用 toString()方法,如果二者都没有,则抛出 TypeError。

比如:

var a = {valueOf: function(){return "12";}
};

var b = {toString: function(){return "12";}
};

var c = [1,2];
c.toString = function(){return this.join( "");    // "12"
};

Number(a);            // 12
Number(b);            // 12
Number(c);            // 12
Number("");            // 0
Number([] );            // 0
Number([ "abc"] );    // NaN

ToBoolean

将一个值转换为 Boolean 值,我们先看一个 false 表:

undefined
null
false
+0, -0, and NaN“”

任何不在这个表上的值都为 true。
比如:

var a = new Boolean(false);
var b = new Number(0);
var c = new String("");
Boolean(a && b && c);  // true
/***************/
var a = "false";
var b = "0";
var c = "''";
Boolean(a && b && c);  // true
/***************/
var a = [];
var b = {};
var c = function(){};
Boolean(a && b && c);  // true

显式转换

之前提到过一些显式转换,但其实还有以下几种:

字符串与数字的转换

var a = 42;
var b = a.toString();

var c = "3.14";
var d = +c;

b; // "42"
d; // 3.14

日期转换为数字

Date 转换为的数字为从 1 January 1970 00:00:00 UTC 到 Date 的毫秒数。

var d = new Date("Wed, 2 Aug 2017 08:53:06 CDT");

+d; // 1501681986000

Date.now()方法就是用的这种转换:

if (!Date.now) {Date.now = function() {return +new Date();
    };
}

~ 操作符

Js 里有 ”~” 操作符,它首先将值转换为 32bit 的数字,然后在对它进行取补码,也就是说,”~x” 相当于 ”-(x+1)”。

于是,~有一个用处就是判断 -1,比如我们对字符串使用 indexOf()时如果找不到则返回 -1,我们可以这样写:

var a = "Hello World";

~a.indexOf("lo");            // -4   <-- truthy!

if (~a.indexOf( "lo")) {    // true
  // 找到了
}

~a.indexOf("ol");            // 0    <-- falsy!
!~a.indexOf("ol");        // true

if (!~a.indexOf( "ol")) {    // true
    // 没有找到
}

除此之外,~~可以用来对小数进行取整,但要注意的是,它是舍弃小数位数,而不是四舍五入,相当于 Math.ceil():

Math.floor(-49.6);    // -50
Math.ceil(-49.6);  // -49
~~-49.6;           // -49

parseInt()方法

该方法可以将字符串转换为数字,而且可以接受第二个参数,表示要转换的进制。但要注意的是,它有几个特别的地方:

parseInt(0.000008);        // 0   ("0" from "0.000008")
parseInt(0.0000008);        // 8   ("8" from "8e-7")
parseInt(false, 16);        // 250 ("fa" from "false")
parseInt(parseInt, 16);    // 15  ("f" from "function..")

parseInt("0x10");            // 16
parseInt("103", 2);        // 2

所以,要谨慎使用 parseInt。

转换为 Boolean

我们已经知道 Boolean() 方法可以将值转换为 Boolean,但还有一个更快的方法,就是使用 !! 操作符:

var a = "0";
var b = [];
var c = {};

var d = "";
var e = 0;
var f = null;
var g;

!!a;    // true
!!b;    // true
!!c;    // true

!!d;    // false
!!e;    // false
!!f;    // false
!!g;    // false

隐式转换

数字转换为字符串

因为字符串可以用 + 连接,所以当我们把数字和字符串用 + 连接时,数字会强制转换为字符串:

var a = 122;
var b = a + '';
b;  // "122"

字符串转换为数字

因为 - 只在数字运算符中才有定义,所以对字符串使用 - 会被强制转换为数字:

var a = "122";
var b = a - 0;
b;  // 122

数组转换为数字

同样的,如果数组中只有一个值,使用 - 时,会先把数组转换为字符串,再转换为数字:

var a = [3];
var b = [1];
a - b; // 2

操作符的妙用

操作符 || 和 &&

我们都知道 || 代表‘或’,&& 代表‘和’,但是与 Java、C++ 等语言不同的是,使用这两个操作符时,它们返回的不是 true 或 false,而是本身的值,举个例子:

var a = 42;
var b = "abc";
var c = null;

a || b;        // 42
a && b;        // "abc"

c || b;        // "abc"
c && b;        // null

于是我们就可以利用这两个操作符进行一些赋值操作:

a || b;
// 等价于:a ? a : b;

a && b;
// 等价于:a ? b : a;

操作符 == 与 ===

这两个符号我们应该很熟悉了,==代表值的比较,如果二者类型不同,会进行强制转换;===则是二者值与类型都相同才为 true。这里需要注意一些问题:

NaN 不等于它本身
+ 0 等于 -0

字符串与数字比较

二者比较时,使用 === 结果肯定为 false,因为二者类型不同,但如果使用==,则需要进行转换,简单来说就是把字符串转换为数字再对二者的值进行比较:

var a = 22;
var b = "22";

a === b;    // false
a == b;        // true

任何值与 Boolean 比较

当任何值与 Boolean 使用 == 比较时,首先会把 Boolean 转换为数字,然后再进行比较。也就是说:

var x = true;
var y = "42";

x == y; // false

所以,在任何时候,都不要使用 == true 或者 == false 这样的语句。

null 与 undefined 比较

当使用 == 比较 nullundefined时,结果总为 true。

Object 与非 Object 比较

object/function/arrayString或者 Number 进行 == 比较时,会先把 Object 转换为 StringNumber,然后再对值进行比较,而 Boolean 值会被转换为 Number 再进行比较。

一些值得注意的比较

"" == [null];    // true
[] == ![]; // true
0 == "\n"; // true
"0" == false;    // true
false == 0;        // true
false == "";    // true
false == [];    // true
"" == 0;        // true
"" == [];        // true
0 == [];        // true

总结

需要特别注意的就是隐式转换,将对象转换为基本类型时,会先调用 valueOf() 方法,没有才调用 toString() 方法,如果我们给自定义的对象添加 valueOf() 方法,并自己给返回值,也能能起到转换的效果。还有就是,在进行等于比较时,还是用 === 比较安全。

参考资料:You-Dont-Know-JS

正文完
 
西蒙
版权声明:本站原创文章,由 西蒙 2017-08-02发表,共计4930字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
验证码