《你不知道的Javascript--中卷 學習總結》(原生函數、強制類型轉換)

原生函數

一、常見的原生函數有:正則表達式

  • String()
  • Number()
  • Boolean()
  • Array()
  • Object()
  • Function()
  • RegExp()
  • Date()
  • Error()
  • Symbol() --- ES6中新加入的

二、全部typeof返回值爲"object"的對象(如數組)都包含一個內部屬性[Class]。咱們能夠經過Object.prototype.toString()來查看。(對象的內部[[Class]]屬性和建立該對象的內建原生構造函數相對應)數組

Object.prototype.toString.call([1,2,3]) // "[object Array]"
    
    Object.prototype.toString.call(null) // "[object Null]"
    
    Object.prototype.toString.call(undefined) // "[object Undefined]"
複製代碼

三、若是想要自行封裝基本類型值,可使用Object()函數(不帶new關鍵字)安全

var a = "abc";
    var b = new String(a);
    var c = Object(a);
    
    typeof a; // "string"
    typeof b; // "object"
    typeof c; // "object"
    
    b instanceof String // true
    c instanceof String // true
    
    Object.prototype.toString.call(b) // "[object String]"
    Object.prototype.toString.call(c) // "[object String]"
複製代碼

四、若是想要獲得封裝對象中的基本類型值,可使用valueOf()函數。bash

var a = new String('abc');
    var b = new Number(42);
    var c = new Boolean(true);
    var d = a + ""; // 隱式拆封
    a.valueOf() // "abc"
    b.valueOf() // 42
    c.valueOf(); // true
    
    typeof d // "string"
複製代碼

五、Array構造函數只帶一個數字參數的時候,該參數會被做爲數組的預設長度,而非只充當數組中的一個元素函數

var a = new Array(1,2,3)
    
    a // [1,2,3]
複製代碼

六、咱們將包含至少一個"空單元"的數組稱爲稀疏數組ui

七、建立數組的不一樣的方式會有所區別this

var a = new Array(3);
    var b = [undefined,undefined,undefined]
    
    a.join("-"); // "--"
    b.join("-"); // "--"
    
    a.map(function(v,i){return i});  // [undefined * 3]
    b.map(function(v,i){return i});  // [0,1,2]
    
    
    function fakeJoin(arr,connector){
        var str = "";
        for(var i = 0;i<arr.length;i++){
            if(i>0){
                str += connector
            }
            
            if(arr[i]!==undefined){
                str += arr[i]
            }
        }
        return str;
    }
複製代碼

八、new Object() 能夠建立對象,可是沒法像常量形式那樣一次設定多個屬性。new Function() 好比動態定義函數參數函數體的時候能夠建立函數。 new RegExp() 能夠動態定義正則表達式spa

var c = new Object();
    
    var e = new Function("a","return a*2;") // 至關於var f = function(a){return a * 2}
    
    var name = 'xxx'
    var namePattern = new RegExp("\\b(?:"+name+")+\\b","ig");
    
    var matches = someText.match(namePattern)
    
複製代碼

九、Symbolprototype

  • 符號是具備惟一性的特殊值(並不是絕對),用它來命名對象屬性不容易致使重名。
  • ES6中有一些預約義符號,以Symbol的靜態屬性形式出現,如Symbol.createSymbol.iterator
// 能夠自定義對象的迭代器,for..of能夠遍歷值
    obj[Symbol.iterator] = function(){}
複製代碼
var mysym = Symbol('symbol')
    mysym // Symbol(symbol)
    mysym.toString() //"Symbol(symbol)"
    typeof mysym // "symbol"
    
    var a = {}
    a[mysym] = 'foobar'
    
    Object.getOwnPropertySymbols(a) // [Symbol(symbol)]
複製代碼

強制類型轉換

值類型轉換

一、將值從一種類型轉換爲另外一種類型一般稱爲類型轉換,這是顯式的狀況;隱式的狀況稱爲強制類型轉換code

二、Javascript中的強制類型轉換老是返回標量基本類型值,如字符串、數字和布爾值,不會返回對象和函數。

三、類型轉換髮生在靜態類型語言的編譯階段,而強制類型轉換髮生在動態類型語言的運行時(runtime)

ToString

一、抽象操做ToString,它負責處理非字符串到字符串的強制類型轉換。null轉換爲"null",undefined轉換爲"undefined",true轉換爲"true"。

二、對普通對象來講,除非自行定義,不然toString()返回內部屬性[[class]]的值,如"[object Object]"

三、若是對象有本身的toString()方法,字符串化時就會調用該方法並使用其返回值。

四、數組的默認toString()方法通過了從新定義,將全部單元字符串化之後在用,鏈接起來

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

JSON字符串化

一、JSON字符串化(JSON.stringify)並不是嚴格意義上的強制類型轉換。安全的JSON值均可以使用JSON.stringify字符串化。安全的JSON值是指可以呈現爲有效的JSON格式的值。

二、不安全的JSON值:

  • undefined
  • symbol
  • function
  • 包含循環引用(對象之間相互引用,造成一個無限循環)的對象。

三、JSON.stringify()在對象中遇到undefined、function和symbol時會自動將其忽略。在數組中則會返回null(以保證單元位置不變)。對包含循環引用的對象執行JSON.stringify()會出錯。

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}"
複製代碼

四、若是對象中定義了toJSON()方法,JSON字符串化時會首先調用該方法,而後用它的返回值來進行序列化。(若是含有非法JSON值的對象作字符串化,或者對象中的某些值沒法序列化時,就須要定義toJSON()方法來返回一個安全的JSON值

var o = {}
    var a = {
        b:41,
        c:o,
        d:function(){}
    }
    
    // 循環引用
    o.e = a;
    
    JSON.stringify(a) // 產生錯誤
    
    a.toJSON = function(){
        // 序列化僅包含b
        return {b:this.b}
    }
    
    JSON.stringify(a) // "{"b":42}"
複製代碼

五、toJSON() 返回的應該是一個適當的值,能夠是任何類型,而後在由JSON.stringify()對其進行字符串化。(也就是說返回一個可以被字符串化的安全的JSON值,而不是返回一個JSON字符串

var a = {
        val:[1,2,3],
        toJSON:function(){
            return this.val.slice(1);    
        }
    }
    
    JSON.stringify(a); // "[2,3]"
複製代碼

六、能夠向JSON.stringify()傳遞一個可選參數replacer,它能夠是數組或者函數。用來指定對象序列化過程當中哪些屬性應該會處理,哪些應該被排除,和toJSON很像。

  • 若是replacer是一個數組,它必須是一個字符串數組,其中包含序列化要處理的對象的屬性名稱
  • 若是replacer是一個函數,它會對對象自己調用一次,而後對對象中的每一個屬各調用一次,每次傳遞兩個參數,。若是要忽略某個鍵就返回undefined,不然返回指定的值。
var a = {
        b:42,
        c:"42",
        d:[1,2,3]
    }
    JSON.stringify(a,["b","c"]) // "["b":42,"c":"42"]"
    
    JSON.stringify(a,function(k,v){
        if(k!=="c") return v
    })
    // "{"b":42,"d":[1,2,3]}"
複製代碼
  • JSON.stringify還有一個可選參數space(第三個參數),用來指定輸出的縮進格式。space爲正整數時是指定每一級縮進的字符數,還能夠是字符串,此時最前面的十個字符被用於每一級的縮進。(感受沒啥大用)

ToNumber

一、true轉換爲1,false轉換爲0。undefined轉換爲NaN,Null轉換爲0。

二、對象(包含數組)轉換爲基本的類型值,會按照以下規則:

  • 檢查該值是否有valueOf的方法。若是有而且返回基本類型值,就使用該值進行強制類型轉換。
  • 若是沒有的話就使用toString的返回值(若是存在)來進行強制類型轉換。
  • 若是上面兩個均不返回基本類型值,會產生TypeError錯誤。

三、使用Object.create(null)建立的對象[[Prototype]]屬性爲null,而且沒有valueOf和toString方法,所以沒法進行強制類型轉換

ToBoolean

一、如下這些是假值:

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

二、假值對象(瞭解如下吧)

document.all

顯示強制類型轉換

字符串和數字之間的轉換

一、字符串=>數字

  • Number()
  • +(一元運算符)

二、數字=>字符串

  • String()
  • toString()
var a = 42;
    var b = a.toString()
    
    var c = "3.14"
    var d = +c;
    
    b // "42"
    d // 3.14
複製代碼

三、一元運算符+的另外一個常見用途是將日期(Date)對象強制類型轉換爲數字,返回結果爲Unix時間戳,以毫秒爲單位。

var d = +new Date()
    d // 1560354322864
    
    // 別的方式獲取時間戳
    
    var timestamp = new Date().getTime()
    
    // Date.now
    if(!Date.now){
        Date.now = function(){
            return +new Date();
        }
    }
複製代碼

~運算符(非)

  • ~x == -(x+1) (記住這一個就好了)
  • 使用場景,if(~a.indexOf(..)),若是if判斷的結果爲false,證實不存在,不然就是存在。

顯示解析數字字符串

一、parseInt解析容許字符串中含有非數字字符,解析從左到右的順序,若是遇到非數字字符就中止。而轉換不容許出現非數字字符,不然會失敗並返回NaN。(解析浮點數可使用parseFloat())

var a = "42"
    var b = "42px"
    Number(a) // 42
    parseInt(b) // 42
複製代碼

二、早期版本的parseInt()有一個問題,若是沒有第二個參數來指定的基數,parseInt會根據字符串的第一個字符來自行決定基數。若是第一個字符是x或X,則轉換爲十六進制數字。若是是0,則轉換爲八進制數字。(注意ES5以後默認轉換爲十進制數。若是第二個參數不傳或者false值,按照十進制處理。)

顯示轉換爲布爾值

一、一元運算符 ! 顯式地將值強制類型轉換爲布爾值。可是它同時還將 真值反轉爲假值(或者將假值反轉爲真值)。因此顯式強制類型轉換爲布爾值最經常使用的方法是 !!,由於第二個 ! 會將結果反轉回原值。

隱式強制類型轉換

字符串和數字之間的隱式強制類型轉換

一、根據 ES5 規範 11.6.1節,若是某個操做數是字符串或者可以經過如下步驟轉換爲字符串 的話,+ 將進行拼接操做。若是其中一個操做數是對象(包括數組),則首先對其調用 ToPrimitive 抽象操做(規範 9.1 節),該抽象操做再調用 [[DefaultValue]](規範 8.12.8 節),以數字做爲上下文。 二、若是 + 的其中一個操做數是字符串(或者經過以上步驟能夠獲得字符串), 則執行字符串拼接;不然執行數字加法。

var a = [1,2];
     var b = [3,4];
    a + b; // "1,23,4"
複製代碼

三、咱們能夠將數字空字符串 ""相 + 來將其轉換爲字符串

var a = 42;
    var b = a + "";
    b; // "42"
複製代碼

四、a + ""(隱式)和前面的String(a)(顯式)之間有一個細微的差異須要注意。根據 ToPrimitive抽象操做規則,a + ""會對a調用valueOf()方法,而後經過ToString抽象 操做將返回值轉換爲字符串。而 String(a) 則是直接調用 ToString()

var a = {
         valueOf: function() { return 42; },
         toString: function() { return 4; }
     };
     a + "";         // "42"
     String( a );    // "4"
複製代碼

五、-是數字減法運算符,所以a - 0會將a強制類型轉換爲數字。也可使用a * 1和a / 1。

var a = "3.14";
    var b = a - 0;
    b; // 3.14
    
    var a = [3];
    var b = [1];
    a - b; // 2
複製代碼

布爾值到數字的隱式強制類型轉換

一、可使用!!來將值轉換爲布爾值,再經過 Number(..) 顯式強制類型轉換爲 0 或 1。

隱式強制類型轉換爲布爾值

一、下面的狀況會發生 布爾值隱式強制類型轉換:

  • if (..)語句中的條件判斷表達式。
  • for ( .. ; .. ; .. )語句中的條件判斷表達式(第二個)。
  • while (..) 和 do..while(..) 循環中的條件判斷表達式。
  • ? :中的條件判斷表達式。
  • 邏輯運算符 ||(邏輯或)和 &&(邏輯與)左邊的操做數(做爲條件判斷表達式)。

|| 和 &&

一、&& 和 || 運算符的返回值並不必定是布爾類型,而是兩個操做數其中一個的值。 二、使用|| 和 &&注意如下幾點:

  • || 和 && 首先會對第一個操做數(a 和 c)執行條件判斷,若是其不是布爾值(如上例)就 先進行 ToBoolean 強制類型轉換,而後再執行條件判斷。
  • 對於 || 來講,若是條件判斷結果爲 true 就返回第一個操做數(a 和 c)的值,若是爲 false 就返回第二個操做數(b)的值。
  • && 則相反,若是條件判斷結果爲 true 就返回第二個操做數(b)的值,若是爲 false 就返 回第一個操做數(a 和 c)的值。
var a = 42;
     var b = "abc";
     var c = null;
    a || b; a && b;
    c || b; c && b;
    // 42
    // "abc"
    // "abc"
    // null
複製代碼

符號的強制類型轉換

一、ES6 容許 從符號到字符串的顯式強制類型轉換,然而隱式強制類型轉換會產生錯誤。 二、符號不可以被強制類型轉換爲數字(顯式和隱式都會產生錯誤),但能夠被強制類型轉換 爲布爾值(顯式和隱式結果都是 true)

var s1 = Symbol( "cool" );
    String( s1 );     // "Symbol(cool)"
    var s2 = Symbol( "not cool" );
    s2 + "";      // TypeError
複製代碼

寬鬆相等和嚴格相等

一、常見的誤區是「== 檢查值是否相等,=== 檢查值和類型是否相等」。正確的解釋是:「== 容許在相等比較中進行強制類型轉換,而 === 不容許。」

抽象相等(挺重要的!!)

一、字符串數字之間的相等比較

ES5 規範 11.9.3.4-5 這樣定義:

  • 若是 Type(x) 是數字,Type(y) 是字符串,則返回 x == ToNumber(y) 的結果。
  • 若是 Type(x) 是字符串,Type(y) 是數字,則返回 ToNumber(x) == y 的結果。
var a = 42;
    var b = "42";
    a === b;    // false  不進行強制類型轉換比較
    a == b;     // true   進行強制轉換後進行比較
複製代碼

二、其餘類型和布爾類型之間的相等比較

ES5 規範 11.9.3.6-7 這樣定義:

  • 若是 Type(x) 是布爾類型,則返回 ToNumber(x) == y 的結果。
  • 若是 Type(y) 是布爾類型,則返回 x == ToNumber(y) 的結果。
var a = "42";
    var b = true;
    a == b; // false
複製代碼

三、null 和 undefined 之間的相等比較

ES5 規範 11.9.3.2-3 這樣定義:

  • 若是 x 爲 null,y 爲 undefined,則結果爲 true。
  • 若是 x 爲 undefined,y 爲 null,則結果爲 true。

在 == 中 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
    
複製代碼

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

ES5 規範 11.9.3.8-9 這樣定義:

  • 若是 Type(x) 是字符串或數字,Type(y) 是對象,則返回 x == ToPrimitive(y) 的結果;
  • 若是 Type(x) 是對象,Type(y) 是字符串或數字,則返回 ToPromitive(x) == y 的結果。
var a = 42;
    var b = [ 42 ];
    a == b; // true
    
    
    var a = 'abc'
    var b = Object(a)
    
    a===b // false
    a==b // true
複製代碼

五、極端狀況

[] == ![] // true
複製代碼

讓咱們看看 ! 運算符都作了些什麼?根據 ToBoolean 規則,它會進行布爾 值的顯式強制類型轉換(同時反轉奇偶校驗位)。因此[] == ![]變成了[] == false。 []=>''=>0,而false=>0 ,因此兩邊天然就相等了。

抽象關係比較

ES5 規範 11.8.5 節定義:

  • 「抽象關係比較」(abstract relational comparison),分爲兩個部 分:比較雙方都是字符串(後半部分)和其餘狀況(前半部分)。

一、比較雙方首先調用 ToPrimitive,若是結果出現非字符串,就根據 ToNumber 規則將雙方強 制類型轉換爲數字來進行比較。(感受這個有點問題)

var a = [ 42 ];
    var b = [ "43" ];
    
    a < b;  // true
    b < a;  // false
複製代碼

二、若是比較雙方都是字符串,則按字母順序來進行比較

var a = [ "42" ];
     var b = [ "043" ];
    a < b; // false
複製代碼

三、下面的例子有點奇怪

var a = { b: 42 };
     var b = { b: 43 };
     a < b;  // false
     a == b; // false   對象比較 值不一樣直接是false
     a > b;  // false
     a <= b; // true
     a >= b; // true
複製代碼

規範規定,<= 應該是「小於或者等於」。實際上 JavaScript 中 <= 是 「不大於」的意思(即 !(a > b),處理爲 !(b < a))。同理 a >= b 處理爲 b <= a

相關文章
相關標籤/搜索