JS的強制類型轉換

来源:https://www.cnblogs.com/gzhjj/archive/2018/05/11/9023612.html
-Advertisement-
Play Games

將值從一種類型轉換為另一種類型通常稱為類型轉換,這是顯式的情況,隱式的情況稱為強制類型轉換。 JavaScript中的強制類型轉換總是返回標量基本類型值,如字元串、數字和布爾值,不會返回對象和函數。 類型轉換髮生在靜態類型語言的編譯階段,而強制類型轉換則發生在動態類型語言的運行時。 我們能夠從代碼中 ...


將值從一種類型轉換為另一種類型通常稱為類型轉換,這是顯式的情況,隱式的情況稱為強制類型轉換。
JavaScript中的強制類型轉換總是返回標量基本類型值,如字元串、數字和布爾值,不會返回對象和函數。
類型轉換髮生在靜態類型語言的編譯階段,而強制類型轉換則發生在動態類型語言的運行時。
我們能夠從代碼中看出哪些地方是顯式強制類型轉換,而隱式強制類型轉換則不那麼明顯,通常是某些操作產生的副作用。

1.字元串、數字和布爾值之間類型轉換的基本規則

1.1 ToString

基本類型值的字元串化規則為:null轉換為"null",undefined轉換為"undefined",true轉換為"true"。

對於普通對象來說,除非自定義,否則toString()返回內部屬性[[Class]]的值,如"[object Object]"。

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

toString()可以被顯式調用,或者在需要字元串化時自動調用。

JSON.stringify(..)在將JSON對象序列化為字元串時也用到了ToString。

JSON.stringify(42);//"42"
JSON.stringify("42");//""42""
JSON.stringify(null);//"null"
JSON.stringify(true);//"true"

所有安全的JSON值都可以使用JSON.stringify(..)字元串化。安全的JSON值是指能夠呈現為有效JSON格式的值。
不安全的JSON值包括undefined、function、symbol和包含迴圈引用的對象。

如果要對含有非法JSON值的對象做字元串化,或者對象中的某些值無法被序列化時,就需要定義toJSON()方法來返回一個安全的JSON值。
如果對象中定義了toJSON()方法,JSON字元串化時會首先調用該方法,然後用它的返回值來進行序列化。
toJSON()返回的應該是一個適當的值(一個能夠被字元串化的安全的JSON值),可以是任何類型,然後再由JSON.stringify(..)對其進行字元串化。

var a = {
    b : 42,
    c : "42",
    d : [1,2,3]
};
console.log(JSON.stringify(a,["b","c"]));//"{"b":42,"c","42"}"
console.log(JSON.stringify(a,function(k,v){if(k != "c"){return v;}}));//"{"b":42,"d",[1,2,3]}"

1.2 ToNumber

ES5規範定義了抽象操作ToNumber用於將非數字值轉換為數字值。
其中true轉換為1,false轉換為0。undefined轉換為NaNnull轉換為0。

對象(包括數組)會首先被轉換為相應的基本類型值,如果返回的是非數字的基本類型值,則再遵循以上規則將其強制轉換為數字。
為了將值轉換為相應的基本類型值,抽象操作ToPrimitive會首先檢查該值是否有valueOf()方法,如果有並且返回基本類型值,就使用該值進行強制類型轉換。如果沒有就使用toString()的返回值(如果存在)來進行強制類型轉換。

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

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

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

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

1.3 ToBoolean

假值

  • undefined
  • null
  • false
  • +0、-0和NaN
  • ""

假值的布爾強制類型轉換結果為false

所有的對象都是真值,假值對象除外。
假值對象不是包裝了假值的封裝對象。

var a = new Boolean(false);
var b = new Number(0);
var c = new String("");

var d = Boolean( a && b && c );
console.log(d);//true
//d為true,說明a、b、c都為true。

瀏覽器在某些特定情況下,在常規JavaScript語法基礎上自己創建了一些外來(exotic)值,這些就是“假值對象”。

真值

真值就是假值列表之外的值。

var a = "false";
var b = "0";
var c = "''";

var d = Boolean( a && b && c );
console.log(d);//true
//所有字元串都是真值。
var a = [];//空數組
var b = {};//空對象
var c = function(){};//空函數

var d = Boolean( a && b && c );
console.log(d);//true
//[]、{}和function(){}都不在假值列表中,因此它們都是真值。

2.顯式強制類型轉換

我們在編碼時應儘可能地將類型轉換表達清楚,以免給別人留坑。類型轉換越清晰,代碼可讀性越高,更容易理解。

2.1 字元串和數字之間的顯式轉換

var a = 42;
var b = String(a);//將數字轉換為字元串

var c = "3.14";
var d = Number(c);//將字元串轉換為數字

console.log(b);//"42"
console.log(d);//3.14

var e = 5+ +c;//+c顯式地將c轉換為數字
console.log(e);//8.14

日期顯式轉換為數字

var d = new Date("Mon, 18 Aug 2014 08:53:06 CDT");
console.log(+d);//1408369986000

我們不建議對日期類型使用類型轉換,應該使用Date.now()來獲得當前的時間戳,使用new Date(..).getTime()來獲得指定時間的時間戳。

奇特的~運算符

//~x大致等同於-(x+1)。
~42;//-(42+1) ==> -43
//~和indexOf()一起可以將結果強制轉換為真/假值。
//JavaScript中字元串的indexOf(..)方法在字元串中搜索指定的子字元串,如果找到就返回子字元串所在的位置(從0開始),否則返回-1。
var a = "Hello World";

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

if(~a.indexOf("lo")){//true
    //找到匹配!
}

//~-1的結果為0。
~a.indexOf("ol");//0 <-- 假值!
!~a.indexOf("ol");//true

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

字位截除

一些開發人員使用~~來截除數字值的小數部分,~~只適用於32位數字。
我們在使用~~~進行此類轉換時需要確保其他人也能夠看得懂。

2.2 顯式解析數字字元串

var a = "42";
var b = "42px";

Number(a);//42
parseInt(a);//42

Number(b);//NaN
parseInt(b);//42

2.3 顯式轉換為布爾值

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

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

Boolean(a);//true
Boolean(b);//true
Boolean(c);//true

Boolean(d);//false
Boolean(e);//false
Boolean(f);//false
Boolean(g);//false

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

!!d;//false
!!e;//false
!!f;//false
!!g;//false
//在if(..)..這樣的布爾值上下文中,如果沒有使用Boolean(..)和!!,就會自動隱式地進行ToBoolean轉換。

3.隱式強制類型轉換

隱式強制類型轉換的作用是減少冗餘,讓代碼更簡潔。

3.1 字元串和數字之間的轉換

var a = "42";
var b = "0";

var c = 42;
var d = 0;

a + b;//"420"
c + d;//42

var e = [1,2];
var f = [3,4];

e + f;//"1,23,4"

var g = 42;
var h = g + "";

h;//"42"

var i = "3.14";
var j = i - 0;

j;//3.14

3.2 布爾值到數字的轉換

function onlyOne(){
    var sum = 0;
    for(var i = 0; i<arguments.length; i++){
        if(arguments[i]){
            //下麵等同於 sum += Number(!!arguments[i]);
            sum += arguments[i];
        }
    }
    return sum == 1;
}
var a = true;
var b = false;

console.log(onlyOne(b,a));//true
console.log(onlyOne(b,a,b,b,b));//true
console.log(onlyOne(b,b));//false
console.log(onlyOne(b,a,b,b,b,a));//false

3.3 隱式強制類型轉換為布爾值

下麵的情況會發生布爾值隱式強制類型轉換:

  1. if(..)語句中的條件判斷表達式。
  2. for(..;..;..)語句中的條件判斷表達式。
  3. while(..)do..while(..)迴圈中的條件判斷表達式。
  4. ? :中的條件判斷表達式。
  5. 邏輯運算符||(邏輯或)與&&(邏輯與)左邊的操作數。

3.4 || 和&&

和其他語言不同,在JavaScript中||&&的返回值是兩個操作數中的一個(且僅一個)。即選擇兩個操作數中的一個,然後返回它的值。

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就返回第一個操作數的值,如果為false就返回第二個操作數的值。
對於&&來說,如果條件判斷結果為true就返回第二個操作數的值,如果為false就返回第一個操作數的值。


4.寬鬆相等和嚴格相等

寬鬆相等==檢查值是否相等,嚴格相等===檢查值和類型是否相等。
==允許在相等比較中進行強制類型轉換,而===不允許。

4.1 抽象相等

字元串和數字之間的相等比較

var a = 42;
var b = "42"

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

其他類型和布爾類型之間的相等比較

var a = "42";

//不要這樣用,條件判斷不成立
if(a == true){
    //..
}
//也不要這樣用,條件判斷不成立
if(a === true){
    //...
}
//這樣的顯式用法沒問題
if(a){
    //..
}
//這樣的顯式用法更好
if(!!a){
    //..
}
//這樣的顯式用法也很好
if(Boolean(a)){
    //..
}

null和undefined之間的相等比較

var a = null;
var b;

a == b;//true
a == null;//true
b == null;//true

a == false;//false
b == false;//false
a == "";//false
b == "";//false
a == 0;//false
b == 0;//false

對象和非對象之間的相等比較

var a = "abc";
var b = Object(a);

a === b;//false
a == b;//true
//a == b結果為true,因為b通過ToPromitive進行強制類型轉換(也稱為"拆封"),並返回標量基本類型值"abc",與a相等。
var a = null;
var b = Object(a);
a == b;//false

var c = undefined;
var d = Object(c);
c == d;

var e = NaN;
var f = Object(a);
e == f;
//因為沒有對應的封裝對象,所以null和undefined不能夠被封裝。
//NaN能夠被封裝為數字封裝對象,但拆封之後NaN == NaN返回false,因為NaN不等於NaN。

4.2 比較少見的情況

假值的相等比較

極端情況

安全運用隱式強制類型轉換

  • 如果兩邊的值中有true或者false,千萬不要使用==
  • 如果兩邊的值中有[]""或者0,儘量不要使用==

這時最好用===來避免不經意的強制類型轉換。這兩個原則可以讓我們避開幾乎所有強制類型轉換的坑。

5.抽象關係比較

var a = [42];
var b = ["43"];

a < b;//true
b < a;//false

var c = ["42"];
var d = ["043"];
c < d;//false

var e = [4,2];
var f = [0,4,3];

e < f;//false
//e轉換為"4,2",f轉換為"0,4,3",按字母順序進行比較
var a = {b:42};
var b = {b:43};

a < b;//false
a == b;//false
a > b;//false

a <= b;//true
a >= b;//true
//根據規範a <= b被處理為b < a,然後將結果反轉,因為b < a的結果是false,所以a <= b的結果是true。

參考資料:《你不知道的JavaScript》(中捲) 第四章


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一.創建私有庫的流程簡介 創建一個項目,留著後面的流程3製作私有庫 在可以創建私有庫的地方創建一個code repository, code repository是代碼倉庫,我們把代碼上傳到這個倉庫。 在可以創建私有庫的地方創建一個spec repository, spec repository是配 ...
  • 函數預設值是一個很提高魯棒性的東西(就是讓程式更健壯)MDN關於函數預設參數的描述:函數預設參數允許在沒有值或undefined被傳入時使用預設形參。 ES5 使用邏輯或||來實現 眾所周知,在ES5版本中,並沒有提供的直接方法供我們我們處理函數預設值所以只能夠自己去增強函數的功能,一般會這麼來做: ...
  • 轉自:http://www.jb51.net/article/71615.htm 侵刪 Document --> ...
  • 鄙人最近才剛剛開始學習一些關於移動端的知識,還只是個小白,文中可能有許多理解錯誤,望指出,請多多見諒。 響應式 什麼是響應式頁面呢? 顧名思義響應式頁面就是能做出響應的頁面,它的頁面效果不是定死的,會隨著用戶的改變而改變。 如何著手響應式有以下幾個思考的方向 1. 找一份設計圖 2. 使用Media ...
  • 在angular 6中使用 less 新項目 已有的項目 修改 文件及引用處尾碼名為 併在 文件中設置以下內容 ...
  • var EventUtil={ //三個參數 第一個是element元素 第二個參數 type(事件類型 例如 click),第三個回掉函數 addEvent:function(element,type,fn){ //相容處理 if(element.addEventListener){ //IE8以 ...
  • 一.兩個日期大小比較 1.格式:(yyyy-mm-dd) function duibi(a, b,flag) { var arr = a.split("-"); var starttime = new Date(arr[0], arr[1], arr[2]); var starttimes = st ...
  • 用來確定字元串A是否包含字元串B,ES6有提供了三種新方法: 需要註意的是,這三個方法都接受第二個參數-一個數字n。前兩個均表示從第n個開始查詢,而,endsEith()是指針對前n個字元。 repeat() 將原字元串重覆n次。 字元串對象,一共有四個方法可以使用正則表達式:match()、rep ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...