JavaScript值介紹

數組

和其餘語言不一樣,在JavaScript中,數組能夠擁有不一樣值類型,可使字符串數字對象,還能夠是數組(多維數組就是這樣造成的).java

聲明數組後,能夠直接經過索引的方式進行賦值:node

var arr = [];
  arr.length;  //0

  arr [0]  =  12;
  arr [1]  = "ok";
  arr.length  //2

咱們還可使用delete運算符將單元從數組中移除:
避免冗餘代碼,繼上寫面試

délete arr [0]
  arr.length  //2  這是爲何呢?

  arr[0]   // undefined

咱們來看一下使用delete運算符刪除後的數組究竟是什麼樣子的呢?數組

願數組爲 arr = [1,3,4,5],咱們delete arr [1]
圖片描述函數

咱們發現使用delete刪除數組單元,length屬性並無改變,對應的數組單元中,也確實刪除了,咱們對出現這種狀況的數組,稱之爲稀疏數組.工具

在JavaScript類型介紹中,咱們講過,數組屬於對象的子類型,那麼咱們可不能夠經過對象查找屬性的方式去訪問數組呢?動畫

var arr = [];

  arr["node"] = "ok";  
  arr["node"]  // "ok"

咱們能夠經過對象的鍵值去方位和操做它(但這些並不計算在數組的長度內)!
代碼繼上⬆️spa

arr.length  // 0
   arr    //lenght:0 node:"ok";

這裏有個問題須要特別注意,若是字符串鍵值可以被強制類型轉換爲十進制數字的話,就會被徹底看成數字索引來處理。prototype

var arr = [];
  arr["13"] = 42;
  arr.length   //14

咱們爲arr[」13「]賦值,0-12單元默認爲空(undefined),這說明數組在使用字符串鍵值時會對它進行強制類型轉換,若是不能轉換爲number類型,就只是單純的字符串鍵值。
再來看最後一個例子:code

var obj = {name:"mark"}
 var arr = []
 arr[obj] = "12";

 arr[obj]    //??????
 arr["[object Object]"]  //?????

好了不賣關子了,它們兩個的結果都是"12",咱們只須要記住一句話:數組鍵值如不是number,那麼就遵循:其餘類型->字符串鍵值->數字鍵值 這一規律。這個例子當中,咱們在賦值「12」時,就已經把obj轉換成了字符串"[object Object]",因爲這段字符不能轉換爲number類型因此JavaScript會以字符串鍵值的形式儲存。讀取亦是如此。

類數組

說到它,咱們先來看一張圖:

![圖片描述

咱們發現,類數組和純數組的區別在於純數組當中的原型鏈多了一層Array(咱們稱之爲數組對象),而類數組直接使用了內置的Object對象。

數組對象中包含了咱們常用的數組方法及屬性你們在控制檯中輸出看一下:

那是否是類數組就不可使用純數組當中的方法了呢?類數組當中沒有其數組方法,正常不可使用,可是不要忘記,咱們還可使用call方法。

function foo (){
     Array.prototype.push.call(arguments,2017);
     //爲了方便查看,咱們輸出一下參數
     console.dir(arguments);
  }

 foo(1,2);   //[1,2,2017]

以上直接操做的argumens,也能夠用slice工具函數拷貝新數組:

function foo(){
    var arr = Array.prototype.slice.call(arguments);
    arr.push(2017);
    console.dir(arr);
 }
 foo(1,2); //[1,2,2017]

使用ES6中內置的工具函數from也能夠轉換爲純數組:

var arr = Array.from(arguments);

咱們以後再詳細介紹ES6中的特性。這裏暫且先不說.

數組和字符串很類似,咱們能夠把它們都當作類數組,都有.lengthindexof屬性。咱們能夠把它當作人妖,不男不女。好了,之後若是有人問你類數組是什麼,你就能夠大聲的告訴他了...

可能有些童鞋對類數組的定義仍是有些模糊,小編從犀牛書上找到了一句話,比較不錯,看⬇️

JavaScript有一些特性是其餘對象所沒有的:

  • 當有新的元素添加時,數組length屬性更新

  • 設置length爲一個較小值,將截斷數組

  • 從Array.prototype繼承一些方法

  • 類屬性爲 Array

這些屬性讓JavaScript數組和常規對象喲明顯的區別,可是他們並非定製數組的本質特性。一種經常徹底合理的見解把擁有一個數值length屬性和對應非負整數屬性的對象看作一種類型的數組。

字符串

上面咱們說過,字符串和數組都屬於類數組,字符串內部的實現有沒有使用數組並很差說,但JavaScript中的字符串和字符數組並非一回事,最多隻是看上去類似而已。

例如:
var a = "foo";
   var b = ["f","o","o"];

它們都有length屬性以及indexof和concat方法。

許多數組函數用來處理字符串很方便,雖然字符串沒有這些函數,但能夠經過借用數組的非變動方法來處理字符串:

var a = "foo";
  a.join;  //undefined
  a.map;   //undefined
  
  var c = Array.prototype.join.call(a,"-");
  var d = Array.prototype.map.call(a,function(v){
       return v.toUpperCase()
  }).join(".");
  
  c;       // "f-o-o";
  d;       // "F.O.O";
還有一個不一樣點在於字符串反轉(JavaScirpt面試常見問題),數組有一個字符串字符串沒有的可變動成員函數 reverse();
"".reverse;  //undefined
  [].reverse();   //Function

注意:這裏不能夠用call借用數組的可變動成員函數,由於字符串是不可變的。咱們能夠把字符串作一個轉換,再進行操做:

var a = "string",
    c = "string"
        .split("")
        .reverse()
        .join("");
        
    c;  //gnirts

若是常常要以字符數組的方式的話,還不如直接使用數組,避免來回折騰,有須要時再使用join轉換爲字符.

數字

JavaScript只有一種數值類型number,它沒有真正意義上的整數,這也是他一直爲人詬病的地方.所謂的整數就是沒有小數點的十進制數,因此42.0等同於42。JavaScript的數字類型是基於IEEE754標準實現的,該標準也被稱爲浮點數,使用的是雙精度(即64位2進制);

因爲數字值可使用Number對象進行封裝,所以數字值能夠調用Number.prototype中的方法。例如toFixed方法可指定小數的部分的顯示位數:

var a = 42.59;
  a.toFixed(0);  //42
  a.toFixed(1);  //42.6
  a.toFixed(2);  //42.59
  a.toFixed(3)   //42.590

注意,上例中的參數數值若是大於當前數位,其他部分則用0補充,另外你們也應該看到,toFixed的參數數值若是小於其數字數位就會進行四捨五入。

toPrecision()方法用來指定有效數位的現實位數:

var a = 42.59;
  a.toPrecision(1) //4e+1
  a.toPrecision(2) //43
  a.toPrecision(3) //42.6
  a.toPrecision(4) //42.59

在這裏介紹一種狀況:

42.toFixed();  //SyntaxError

咱們要注意,不可以使用數字常量直接訪問其方法,由於JavaScript會認爲.是常量的一部分,咱們能夠賦給變量進行操做,或者能夠這樣.

var a = 42;
  42.toFixed(1);

  42..toFixed(1);

咱們使用變量和..解決,不過不推薦使用第二種方式,在寫程序時咱們也不會直接拿常量直接使用,在這咱們稍做了解便可.

較小的數值

二進制浮點數最大的問題就在於(全部使用IEEE754規範的語言都是如此),是會出現以下狀況:

0.1 +  0.2  ===0.3   //false

從數學角度來說上面的例子應該返回true,但是會什麼會返回false呢?
是由於二進制浮點數中的0.2和0.3都不是很是精確,它們相加的結果並不是恰好等於0.3,而是一個比較接近的數字:0.000000000004,因此條件判斷爲false。

那麼應該怎樣判斷0.1+0.2是否相等呢?
最多見的方法是設置一個偏差範圍,一般稱爲「機器精度」。
從ES6開始,該值定義在number.EPSILON中,咱們能夠直接拿來用,也能夠爲ES6之間的版本寫一個polyfill:

if(!Number.EPSILON){
       Number.EPSILON = Math.pow(2,-52)
   }

可使用Number.EPSILON來比較兩個數字是否相等(在指定的偏差內);

function numberCloseEnoughToEqual(n1,n2){
       return Math.abs(n1 - n2) < Number.EPSILON;
   var a = 0.1 + 0.2;
   var b = 0.3;
   numberCloseEnoughToEqual(a,b);     //true
   numberCloseEnoughToEqual(0.0000001,0.0000002); //false

可以呈現的最大浮點數大約是1.798e+308(這是一個至關大的數字),它定義在Number.MAX_VALUE中,最小浮點數定義在Number.MIN_VALUE中,大約是5e-334,它不是負數,但無限接近於0!

整數類型檢測

ES6當中新增Number.isInteger方法

Number.isInteger(32)          //true
   Number.isInteger(32.3)       //false

爲該方法添加polyfill:
if(!Number.isInteger){

Number.isInteger = funcion(n){{
           return typeof n === "number" && n  % 1 === 0;
}

}

不是值的值

對於null和undefined,undefined只有一個值爲undefined, null類型也只有一個類型,即null,它們的名稱便是類型也是值。
null (空值)
undefined (未被賦值)

null爲關鍵字,undefined爲標識符.
在咱們非嚴格模式下,是能夠對標識符賦值的:

function foo (){
      undefined = 12;   //爲undefined賦值
   }
   
  foo();
  
  function foo (){
       'use strict'
       undefined  = 12  //Type Error
   }
   
   foo();

咱們只須要了解這一點就能夠,實際使用當中,是絕對不能夠這樣作的.

void運算符
undefined 是一個內置的標識符,咱們能夠用void運算符來定義一個表達式的返回值;

void並不改變表達式的返回值,它只是讓表達式不返回值;
假如咱們如今要寫一個setTimeout計時器,因爲這個方法每次都返回惟一的標識符,那麼咱們就可使用void 掉它;

void  setTimout(function(){})

不是數字的數字

咱們都知道在javaScript數字運算中有一種狀況爲NaN,如:

1/"a"   //NaN
   []/{}    //NaN
   ""/{}    //NaN

咱們發現有兩種狀況爲NaN:數字運算中(出現數字運算符)值非Number類型時,或者沒法正常解析爲10進制或者16進制的有效數字.
可使用全局方法isNaN來判斷是否爲NaN

var s = 1/"a"  
   isNaN(s)        //true

可怕的是NaN連它本身都不想等,這也是JavaScript中惟一一個非自反的值

NaN == NaN      // false
   NaN === NaN   //false
   
   NaN !=  NaN      //true

NaN的寓意是不是一個數字(Not a Number) ,"不是一個數字" 說到咱們不得這個不看一段代碼:

var str = "abc";
   var no = 1/"a";
   
   isNaN(no)    //true
   isNaN(str)     // true --暈

這個bug已經存留好久,咱們在程序中儘可能不要直接使用isNaN方法,能夠polyfill或使用ES6的Number.isNaN

var str = "abc";
   var no = 1/"a";
   
   Number.isNaN(no)     //true;
   Number.isNaN(str)       //false

polyfill有兩種寫法,這裏一塊兒貼代碼給你們:

// v1 
 if(!Number.isNaN){
           Number.isNaN = function(n){
             typeof n === "number"  &&  window.isNaN(n)
         }
 }
 
 //v2
 if(!Number.isNaN){
           Number.isNaN = function(n){
             return n !== n
         }
 }

第二種方法很簡潔,正是利用了咱們上面講過的NaN是js中惟一一個不和本身全等的特性

你們在程序中若是使用isNaN方法,必定要進行二次改造,不然程序有可能會出問題。能夠直接在頁面script里加入咱們js須要添加的polyfill;

無窮數

javaScript中使用有限數字表示法,也就是咱們以前介紹過的IEEE754浮點數,因此它和純數字的數學運算不一樣,JavaScript的運算結果可能會溢出,此時結果爲Infinity或者-Infinity。

var a = Number.MAX_VALUE;  //1.7976931348623157e+308
 
  1/0   //Infinity
  a + Math.pow(2,970) //Infinity
  a + Math.pow(2,969)  //1.7976931348623157e+308
  a  + a   //Infinity

規範規定,若是數學運算的結果超出處理範圍,則由IEEE754規範中的"就近取整"來決定最後的結果,這裏的Math.pow(2,969)更爲接近Number.MAX_VALUE,
因此被向下取整, Math.pow(2,970) + Number.MAX_VALUE與Infinity更爲接近,因此被向上取整。

那若是對Infinity進行數字運算呢?會出現什麼狀況?

Infinity + Infinity // Infinity
  Infinity / Infinity //NaN
  Infinity * Infinity  //Infinity
Infinity - Infinity  //NaN

咱們能夠這樣理解因爲+ 和 * 都無需知道Infinity它是多少值,他們確定比如今的值大,因此必定是Infinity;
若是是- 或者 /運算符,在這樣的條件下他們的值必定小於如今的值,無窮大自己就不是一個有效數字,那麼小於它的值咱們無法判斷,因此JavaScript給出的解釋是NaN;

零值

在js中 0 也有兩種表達方式:-0 和 0
咱們先來看看代碼:

0 *  -3  //-0
    0 / -3  //-0

加法和減法不會產生-0,0全等於-0

""+-0   //"0"
  JSON.stringify(-0) //"0"
  
  +"-0"  // -0

在把-0字符串化後,會轉化爲0;把「-0」轉換爲number時還會恢復過來,是否是很奇怪?

那麼我門在程序中到底如何區分 0 與 -0呢?咱們能夠拿 1/-0 等於 - Infinity 來進行條件判斷;

function isNegZero (n){
         Number(n);
        return ( n === 0 && (1 / n === -Infinity) )
 }
     isNegZero(-0) //true
    isNegZero(0)  //false

拋開學術,咱們爲何須要負零呢?
下面是來自《你不知道的JavaScript 中卷》的一句話;
有些應用程序中的數據須要以級數形式來表示(好比動畫貞的移動速度),數字的符號位用來表明其餘位置信息,
此時若是一個值爲0的變量失去了它的符號位,它的方向就會丟失,因此保留0值就能夠防止相似的事情發生。
以上說的只是一種狀況,在實際開發當中,咱們面對複雜的業務需求,也有可能要使用它,因此這裏咱們要記牢它,以備往後之用。

特殊等式

以上咱們寫了不少的檢驗函數,在ES6中,只有一個很好玩的方法,叫作Object.is,說到這個函數確定會有不少人噴我,
若是早說這個方法就不必寫那些了,其實否則,咱們瞭解的不只是js的特性,也是解決問題的方法.

var a = 1/"asd";   //NaN
  var o = 1 * -0;   //-0
  
  Object.is(a,NaN)   //true
  Object.is("a",a)        //false
  
  Object.is(o,0)  //false
  Object.is(o,-0)  //true

固然少不了polyfill

if(Object.is){
        Object.is = function(v1,v2){
              if(v1 === 0 && v2 === 0){
                 return 1/ v1 === 1/v2
            }
            //爲NaN比較時;
            if(v1 !== v1){
                return v2 !== v2  //以上條件判斷,參數1必定爲NaN,而後再判斷第二個參數,是否爲NaN,
            }
            //若是都不是那麼就作全等比較
            return v1 === v2  
            //
        }
    }
相關文章
相關標籤/搜索