周大俠啊 進擊的 JavaScript(一) 之 型別轉換
說起 js 型別轉換,都是頭疼吧,暈暈的,但是不行啊,這東西很重要滴!
基礎知識
JavaScript的資料型別分為六種,分別為null, undefined, boolean, string, number, object。
object是引用型別,包含陣列,其它的五種是基本型別或者是原始型別(原始值)。
我們可以用typeof方法列印來某個是屬於哪個型別的。不同型別的變數比較或者運算,要先轉型別,叫做型別轉換。
注意,typeof null
返回 "object"
,它是一個特殊的物件值,含義是“非物件”。實際上,我們通常認為null
是自有型別的唯一成員。
一、顯式轉換
parseInt()和parseFloat() 字串轉數字
js提供了parseInt()
和parseFloat()
兩個轉換函式。前者把值轉換成整數,後者把值轉換成浮點數。只有對String型別呼叫這些方法,這兩個函式才能正確執行;對其他型別返回的都是NaN(Not a Number)
。
parseInt()
:
parseInt("1234blue"); //1234
parseInt("0xA"); //10
parseInt("22.5"); //22
parseInt("blue"); //NaN
parseInt()
方法還有第二個引數,可以把二進位制、八進位制、十六進位制或其他任何進位制的字串轉換成整數。所以要解析十六進位制的值,需如下呼叫parseInt()
parseInt("AF", 16); //175
當然,對二進位制、八進位制,甚至十進位制(預設模式),都可以這樣呼叫parseInt()
方法:
parseInt("10", 2); //2
parseInt("66", 8); //54
parseInt("10", 10); //10
parseFloat
字串轉浮點數字,沒有第二個引數。
下面是使用parseFloat()
方法的示例:
parseFloat("1234blue"); //1234.0 parseFloat("0xA"); //NaN parseFloat("22.5"); //22.5 parseFloat("22.34.5"); //22.34 parseFloat("0908"); //908 parseFloat("blue"); //NaN
toFixed() 數字轉成字串
根據引數保留小數點後幾位 會四捨五入,如果無參,預設為0; 例:
(66.55).toFixed(); //"67"
(66.64).toFixed(1); //"66.6"
toExponenttial() 數字轉成字串
根據引數保留小數點後幾位 指數形式 會四捨五入 這個我不就不舉例了,感興趣的,自己百度下把。
Number物件的 toString() 方法, 數字轉字串
根據2 8 16 (範圍2 - 36)分別轉為二進位制 八進位制 十六進位制字串,, 不帶參,就預設為10, 轉十進位制。 例:
(6).toString(2); //"110"
(66).toString(8); //"102"
(66).toString(16); //"42"
下面三個建構函式,當沒有使用 new 時,表示型別轉換函式,使用new 時,表示轉物件(建立一個對應物件),即轉換得到的值 建立一個對應的物件。
Boolean()
它會把 “真值” 轉為 true
, “假值” 轉為 false
。
Boolean()方法的示例:
Boolean(""); //false “假值”
Boolean("zdx"); //true “真值”
Boolean(66); //true “真值”
Boolean(null); //false “假值”
Boolean(0); //false “假值”
Boolean(new Object()); //true “真值”
Number()
有以下規律:
false
、null
、""
、[]
,轉為0true
, 轉1- 數字轉數字
- 全是數字的字串轉數字 //(如果是有效十六進位制 會 轉十進位制數字)例:Number("0xf") //15
- 陣列內全是數字(不能有逗號)轉數字
- 陣列內字串全是數字(不能有逗號)轉數字
- 其他都是
NaN
其實從 第五條那個開始,嚴謹一點是: 物件型別,先呼叫valueOf() 方法,然後按照前四點轉換返回的值。如果返回的值不是原始型別,則呼叫toString()方法,再按前四點轉換返回的值。
大栗子:
Number(false); //0
Number(null); //0
Number(""); //0
Number([]); //0
Number(true); //1
Number("66"); //66
Number("66f"); //NaN
Number(new Object()); //NaN
Number([66]); //66
Number(["66"]); //66
Number([6,6]); //NaN
Number(["6f6"]); //NaN
String()
String()可把任何值轉換成字串。它就是呼叫傳進引數的 toString()
方法。使用String()
轉換成字串和呼叫toString()
方法的唯一不同之處在於,對null
或undefined
值轉換可以生成字串而不引 發錯誤:
String()方法的示例:
String(null); //"null"
var null = null;
null.toString(); //報錯
String(undefined); //"undefined"
Object()
這個函式,使用 和 不使用 new 是一樣的。
它會把原始值,根據它的型別,使用對應的建構函式,建立一個物件。null
和 undefined
和建立一個空物件。
Object(66); //數字物件,等於 new Number(66)
Object("66"); //字串物件,等於 new String("666")
Object(true); //布林物件, 等於 new Boolean(true)
Object(null); //空物件,等於 new Object()
Object(undefined); //空物件,等於 new Object()
二、隱式轉換
(一)、所有型別 轉為 布林
JavaScript 的基礎型別中 有布林型別,這個型別的值,只有兩個值---- true 和 false
任意的JavaScript 的值都可以轉換為布林值。但只有下面這六個值會轉為false:
""
0
-0
null
undefined
NaN
其他所有值,包括所有物件(陣列)都會轉換為 true。布林值 false,和上面6個能轉為false 的值,我們一般稱為“假值”,其他值稱為“真值”。(“真值”等價true,“假值”等價false)
注意!!!在JavaScript 中 ,任何希望使用布林值的地方,都會將運算元當作 “真假” 或 “假值” 對待(即把“真值”當true,“假值”當false)。這句話你現在不懂沒事,看完下面的,或許你就懂了,哈哈。
(二)、原始值 轉為 數字
字串 轉 數字
當字串裡,全為數字時,轉數字,其他都為NaN。空字串就轉0
+ "666"; //666
+ "66f"; //NaN
+ ""; //0
布林轉數字
這個比較簡單了。 true 轉 1;false 轉 0;
+ true; //1
+ false; //
null 轉數字
null 轉 0。
+ null; //0
undefined 和 NaN 轉數字
undefined 和 NaN 都轉 NaN。
+ undefined; //NaN
+ NaN; //NaN
(三)、原始值 轉為 字串
這個也比較簡單,原始值 到 字串,就原封不動的轉(加個雙引號)。
"zdx" + true; //"zdxtrue"
(四)、 引用型別( 物件 )轉為 原始值
物件 轉 布林
物件 轉 布林 都為 true;等同於 Boolean()
![]; //false 這裡取反了,注意,取反會把操作值轉布林
!{}; //false
物件 轉 數字
物件 轉 數字 ,首先呼叫 valueOf()
,如果返回的是原始值,再轉數字(需要的話),並返回;否則呼叫 toString()
, 如果返回的是原始值,再轉數字,並返回;否則 丟擲一個型別錯誤。
+ []; //0
//[].valueOf(); 返回陣列本身[],所以呼叫 [].toString(); 返回 空字串"",""再轉數字 0;
+ (new Date()); //1526008864094
//呼叫 (new Date()).valueOf(); 返回1526008864094
物件 轉 字串
物件 轉 字串 ,跟轉數字的規則一樣。只不過是轉字串。
首先呼叫 valueOf()
,如果返回的是原始值,再轉字串(需要的話),並返回;否則呼叫 toString()
, 如果返回的是原始值,再轉字串,並返回;否則 丟擲一個型別錯誤。
"66" + []; //"66"
"66" + {}; //"66[object Object]"
總結:物件對原始值,除了布林型別,其他都是先呼叫valueOf,然後根據需要呼叫toString。
想知道,js 每個內建物件的valueOf()
和 toString()
方法,可以翻到最下面,附錄
。
三、隱式轉換 發生的地方
隱式轉換通常發生在表示式 和 運算子 。
(1)加減乘除:
加號 +
二元運算子用法(兩個運算元)
可以對數字做加法, 也可以做字串連線操作。 當兩個運算元 都是 數字 或 字串時,計算是顯然的。其他情況下,有如下規則
- 物件轉原始值,除了
Date
物件 直接呼叫toString
,其他物件,呼叫自身的valueOf
方法,但有的物件自身沒有valueOf
,或者得到的不是原始值,此時呼叫toString
。 - 第一步轉換後,如果其中一個是字串的話,另一個運算元也轉字串,進行字串連線。
- 否則,都轉為數字(或者NaN),進行加法。
栗子來了:
1 + new Date(); //"1Fri May 11 2018 14:20:50 GMT+0800 (中國標準時間)"
1 + new Number(2); //3 (new Number).valueOf(); 返回2, 和1 做加法
"66" + 6; //666 6 轉 "6"
1 + {}; //"1[object Object]" ({}).toString()
true + false; //1 都轉數字
1 + null; //1 null 轉數字
1 + undefined; //NaN undefined 轉 NaN
實際程式碼中,經常這樣
var x = 66;
x + ""; //"66" 等價於 String(x)
注意:兩點!
- 不要把物件字面量形式的值放在前面。
- 從左到右的進行 + 運算。
//物件字面量形式放在前面的結果比較複雜,不建議使用。(下面的結果不是唯一的)
{} + 1; //1
{} + "1"; //1
{} + {}; //"[object Object][object Object]"
{x:1} + {}; //NaN
//從左到右,逐個做 + 運算
1 + 2 + ""; //"3"
1 + "" + 2; //"12"
一元運算子用法(一個運算元)
把運算元轉換為 數字(或者NaN),並返回它。
+ "666"; //666 等價於 Number("666")
+ undefined; //NaN
減號 -
都是轉數字,同一元加法,但是它會將結果轉為 負數。
- "666"; //-666
- "66f"; //NaN
1 - null; //1
乘號 *
使用 Number(),強制轉數字
1 * "666"; //666
1 * null; //0
除號 /
使用 Number(),強制轉數字
"666" / 1; //666
1 / true; //1
求模 %
使用 Number(),強制轉數字
"666" % 666; //0
1 / true; //0
(2)比較運算子 (> < >= <=)
比較運算子用來檢測兩個運算元(數字或字串)的大小關係(數值大小或者字串首個字元的16位Unicode的大小 )。
比較運算子的運算元可能是任意型別。但只有數字和字串才能比較。因此,它會把別的運算元進行型別轉換,規則如下:
- 物件轉原始值,如果valueOf()返回原始值,直接比較,否則,呼叫toString()進行轉換。
- 轉原始值後,如果兩個運算元都是字串,那麼將按字串首個字元的16位Unicode的大小 進行比較。
- 否則都轉數字比較。Infinity比任何數字都大(除了自身),-Infinity 相反。如果一個運算元是NaN(或轉NaN),結果返回false。
11 < 3;
"11" < "3"; //true "11" 首個字串 "1" 的16位Unicode 值比 "3"的16位Unicode 小
//"11".charCodeAt(0).toString(16) 31
//"3".charCodeAt(0).toString(16) 33
"11" < 3; //false "11" 轉 11,false
{} < 3; //false {}轉原始值字串,字串轉NaN, false
null < 3; //true null 轉數字
最後要注意的是,<= 和 >= 比較時,並不根據 == 和 === 的規則(在下方)比較,它就僅僅表示 數值 或 字串 之間的比較。
null >= undefined //false
(3)in運算子
把左運算元轉 字串
in 運算子希望它的左運算元是一個字串或可以轉換為字串,右運算元是一個物件。如果,右側的物件擁有一個名為左側運算元值的屬性名,那麼表示式返回true。
var point = { x:1, y:2};
"x" in point; //true point 有一個 x 的屬性名
var arr = [a,b,c];
1 in arr; //true 陣列的索引就相當於 屬性名
(4)! 和 !!
! 它會把操作值 轉為 布林值(“真值”為true,“假值”為false),對布林值求反。(結果只有true,false)
例:
console.log(!""); //true
console.log(!0); //true
console.log(!-0); //true
console.log(!null); //true
console.log(!undefined); //true
console.log(!NaN); //true
console.log(!false); //true
!! 得到操作值 等價的 布林值(“真值”為true,“假值”為false) 等同於 Boolean(),經常稱!! 為強制轉換。 例:
console.log(!!""); //false
console.log(!!0); //false
console.log(!!-0); //false
console.log(!!null); //false
console.log(!!undefined); //false
console.log(!!NaN); //false
console.log(!!false); //false
總結:“假值” 取反都是true, “真值”取反為false;“假值” 強制轉換 都是 false, “真值”強制轉換為 true
(5)== 和 ===
都知道 == 是判斷 左右值 是否想等的。而 === 不僅判斷 右右值是否想等,還要判斷,型別是否一樣。結果返回布林值
== 的用法
NaN是JavaScript中唯一一個不等於任何值的(包括它自己)。(NaN == NaN) // false
一般對NaN的判斷:
function isNaN(num){
return typeof num === "number" && num !== num;
}
注意,跟js 自帶的 isNaN 方法 不一樣。
左右兩邊型別相同
1、原始值的比較
它們的比較,就是值的直接比較。 比如:
console.log(null == null); //true
console.log(undefined == undefined); //true
console.log(666 == 666); //true
console.log(666 == 1); //false
console.log("周大俠啊" == "周大俠啊"); //true
console.log("周大俠啊" == "大佬"); //false
console.log(true == true); //true
console.log(true == false); //false
2、物件的比較
物件和原始值不同,首先,它們是可變的-----它們的值是可修改的:
var o = { x:1 }; //定義一個物件
o.x = 2; //修改x的值
var a = [1,2,3]; //陣列也是可修改的
a[0] = 0; //修改陣列第一個元素
物件的比較並非值的比較,而是引用(記憶體地址)的比較。
var o1 = { x:1 };
var o2 = { x:1 };
console.log( o1 == o2 ); //false
//即使 對像的屬性,值完全相同, 也不相等
var o3 = o1;
console.log( o1 == o3 ); //true
//o3 和 o1 引用的是同一物件。(即指向的是同一塊儲存地址)
//陣列同上
左右兩邊型別不同
如果 == 兩邊的 型別不同,則比較時,有以下兩個個規則:
- undefined等於null
- 其他都轉數字比較
為什麼undefined == null 呢?實際上,undefined 是派生自 null 的。
物件通過valueOf 或 toString 轉換為原始值,原始值在對應轉數字。
總結:左右兩邊型別不同, == 在比較時,除了(null == undefined),NaN,其他都是轉為數字比較, 從來不會轉為布林值!
舉個大栗子:
//1. undefined等於null
undefined == null; //ture
//2. 字串和數字比較時,字串轉數字
"0" == 0; //true
"f" == 0; //false
//字串轉數字時,只有在字串是純數字時,轉對應數字,其他都轉為 NaN。
// 3. 字串和布林比較時,都轉為數字
"0" == false; //true
"1" == true; //true
//4. 數字和布林比較時,布林轉數字
1 == true; //true
0 == false; //true
//true 轉 1, false 轉0;
//5.物件 和 字串,數字比較, 都轉數字。
new String("66") == "66"; //true
new String("zdx") == "zdx"; //false
new String("66") == 66; //true
=== 的用法
這個比較,首先,看兩邊型別是否一致,不一致, 直接false,一致的話,再根據 == 的使用規則, 進行比較。
(6)!= 和 !==
這兩個 運算 跟 取反(!) 操作是 不一樣 的!,注意區分。
這兩個運算,是在 == 和 === 比較過後的結果,進行取反(就是對 true 和 false 取反,因為,== 和 === 的返回值 只有 true 和 false)。
簡單栗子:
"0" == 0; //true
"f" === 0; //false
"0" != 0; //false
"f" !== 0; //true
(7)&&、||
&& 邏輯與
- 如果兩側都是布林值, 進行布林(AND)運算。
- 否則它會先計算左側表示式,如果為 “假值”,返回這個值,如果是“真值”,計算右側表示式,並返回計算結果。
看:
true && false; //false
1 && 2; //2
null && 2; //null
1-1 && 2; //0
2-1 && 0; //0
所以,有時候就會這樣寫程式碼:
if( a==b ) start();
a == b && start(); //效果同上
|| 邏輯或
它跟 && 的行為是一樣的,只是它的做的是布林(OR)運算,返回的情況相反。
- 如果兩側都是布林值, 進行布林(OR)運算。
- 否則它會先計算左側表示式,如果為 “真值”,返回這個值,如果是“假值”,計算右側表示式,並返回計算結果。
true || false; //true
1 || 2; //1
null || 2; //2
1-1 || 2; //2
2-1 || 0; //1
(8)if 語句
它會計算運算元(括號裡)的值,把結果轉為布林型別。“真值” 表現為true , “假值” 表現為false。
if(3-2){
console.log(666)
}
//666
附錄
一、Object
1、valueOf 返回物件本身。
({x:1,y:2}).valueOf(); //{x: 1, y: 2},返回的是物件!
2、toString 返回 "[object type]",其中type是物件的型別。
//這裡使用函式的call方法,指定 this的指向
var toString = Object.prototype.toString;
toString.call(new Date); // [object Date]
toString.call(new String); // [object String]
toString.call(Math); // [object Math]
toString.call(undefined); // [object Undefined]
toString.call(null); // [object Null]
二、Boolean
1、valueOf 返回布林值。
(true).valueOf(); //true , 返回的是原始值,Boolean型別
2、toString 返回該物件的字串形式。
(true).toString(); //"true",返回的是原始值,string型別
三、Date
1、valueOf 返回儲存的時間是從 1970 年 1 月 1 日午夜開始計的毫秒數 UTC。
(new Date()).valueOf(); //1525943413141 一串數字
2、toString 返回一個美式英語日期格式的字串.
(new Date()).toString(); //"Fri May 11 2018 10:26:16 GMT+0800 (中國標準時間)" 原始值,string型別
四、Number
1、valueOf 返回數字值。
(66).valueOf(); //66 返回的是原始值,Number型別
2、toString 返回的是原始值,String型別 根據2 8 16 (範圍2 - 36)分別轉為二進位制 八進位制 十六進位制字串,, 不帶參,就預設為10, 轉十進位制。 例:
(66).toString(2); //"1000010"
(66).toString(8); //"102"
(66).toString(16); //"42"
五、String
1、valueOf 返回字串值。
("666").valueOf(); //"666" 返回的是原始值,String型別
("zdx").valueOf(); //"zdx" 返回的是原始值,String型別
2、toString 和valueOf 效果一樣,返回字串值。
("666").toString(); //"666" 返回的是原始值,String型別
("zdx").toString(); //"zdx" 返回的是原始值,String型別
六、Array
1、valueOf 自身沒有該方法,繼承Object.prototype.valueOf。返回的是陣列物件!
([1,2,3]).valueOf(); //(3) [1, 2, 3],
2、toString 返回表示該陣列的字串,跟使用 Array.prototype.join(","),效果等同
([1,2,3]).toString(); //"1,2,3", 原始值,string型別
([1,2,3]).join(","); //"1,2,3",
七、Function
1、valueOf 自身沒有該方法,繼承Object.prototype.valueOf。 返回的是函式,使用typeof 返回 function,但注意原始值沒有function型別
function a(){ console.log(666) };
a.valueOf(); //ƒ a(){ console.log(666) };
2、toString 返回當前函式原始碼的字串。
function a(){ console.log(666) };
a.toString(); //"function a(){ console.log(666) }";返回的是原始值,string型別
八、Error
1、valueOf 自身沒有該方法,繼承Object.prototype.valueOf。 返回Error 物件本身
(new Error("fatal error")).valueOf(); //Error: fatal error
2、toString 返回一個指定的錯誤物件(Error object)的字串表示。
var e = new Error("fatal error");
print(e.toString()); // "Error: fatal error"
九、Math
它是全域性物件, 不屬於函式。 1、valueOf 自身沒有該方法,繼承Object.prototype.valueOf。
Math.valueOf(); //返回Math 物件本身
2、toString 自身沒有該方法,繼承Object.prototype.toString。
Math.toString(); //"[object Math]"