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  
            //
        }
    }
相关文章
相关标签/搜索