数组

数组在 JavaScript 中,可以容纳任意类型的值,可以是数字、字符、字符串、甚至是另一个数组。JavaScript 中也没有像很多静态语言中数组的限制。他会自动扩容,这更像是 Java 中的容器,因为已经定义好了,可以让我们不用像 Java 一样选择具体的存储方式,比如到底是使用数组还是链表。

    var a = [];
    a[0] = "a";

    a;             //["a"]
    a.length;      //1

    a[2] = 1;

    a[1];          //undefined
    a;             //["a", empty, 1]
    a.length;      //3

关于数组还有几点:

  1. 含有空白或空缺元素的数组,称为稀疏数组。
  2. 使用 delete 可以删除数组中的元素,但是数组的长度并不因此而有变化。它只是被置为空。
  3. 数组也是对象,它可以像对象一样扩充自己的属性,不过如果添加的属性时,使用的键值可以被转换为相应的十进制           索引 ,它会被当作数组的索引使用。
    var a = [];
    a[2] = "B";
    a.length;    //3

类数组

JavaScript 中有很多可以通过索引访问的对象,并且通常也都有 length 属性。不过他们并不是真的数组,它们无法使用 Array.prototype 上面的函数。比如 arguments 对象与很多 DOM 操作返回的 DOM 对象列表。我们可以使用 slice() 方法来创建一个真正的,并且拥有相应元素的数组,另外也可以使用 ES6 新增的 Array.From。

字符串

字符串在很多语言底层都是字符数组,JS中我们不知道它究竟是不是(不过我猜想应该是)。与数组不同,他被设计为不可变的,这和大部分基本类型一样。不过就算是它们的包装类型,也是不可变的。它不会允许你将值的内容改变,它只允许你重新生成并替换。

字符串也是伪数组,它可以使用方括号包装索引的方式来访问其中的元素。不过它依然是不可变的,如果你尝试着修改它,那么所有修改都会静默无效。它本身拥有一些与数组类似的方法。indexOf、concat 等... 

    var a = "abc";
    a[0];            //"a"
    a[0] = "b";     
    a;               //"abc";

我们可以通过 Array.prototype 上的一些方法,来对其中的字符进行操作。如 map join 等... 这些操作的结果必须都是返回一个新的数组,而不会修改原来的数组。如果是在原数组上的操作,那么修改将会无效。如 reverse 操作,如果需要的可以使用 split ("") 来将其转换为对应的字符数组,有需要的话再通过 join("") 转换为对应的字符串 (如果不了解操作是否会影响原数组,最好直接使用这种方式)。

    Array.prototype.map.call("abc", v => v.toUpperCase());    //["A", "B", "C"]
    Array.prototype.join.call("abc", "-");                    //"a-b-c"

    "abc".split("").reverse().join("");                       //"cba"

数值

JS 中只有 number 类型,并没有更细分的类型。它的数字类型是双精度浮点数,也就是一些强类型中的 double,它的字面量有几种写法

    var a = 4.0;    //4
    var b = 4.;     //4
    var c = .4;     //0.4

其中 4. 也是合法的操作,不过容易在一些其他问题上出现问题,像对数字字面量操作属性时

    4.toFixed(2);    //SyntaxError: Invalid or unexpected token

    (4).toFixed(2);  //"4.00"
    4..toFixed(2);   //"4.00"
    4 .toFixed(2);   //"4.00"

在第三个表达式 4..toFixed(2) 中第一的点被看作数字的字面量,而第二个点,才是对象的属性操作符。注意第四个表达式中间有一个空格。另外还有几张字母量的表达方式

    var a = 2.43E2;        //243
    var b = 2.43e2;        //243

    var c = 0xf3           //243
    var d = 0Xf3           //243

    var e = 0363           //243
    var f = 0o363          //243
    var g = 0O363          //243

    var h = 0b11110011     //243
    var i = 0B11110011     //243
    

数字有几个常用的函数

  1. toFixed  用于让数字保持指定的小数位,它会进行四舍五入,并返回字符串。
  2. toExponential 用于将数字转换为的科学计数法。
  3. toPrecision 用于让数字保证指定的位数。
42.1.toFixed(2);            //"42.10"
42.1.toFixed(0);            //"42"
42.6.toFixed(0);            //"43"

500000..toExponential();    //"5e+5"

42.59.toPrecision(1);       //"4e+1"
42.59.toPrecision(2);       //"43"
42.59.toPrecision(6);       //"42.5900"

和大多数浮点数一样,浮点数的计算过程会有机器误差,

0.1 + 0.2 === 0.3;        //false

 理想中它们应该是相等,为什么会有这样的结果呢? 因为 0.1 + 0.2 的值 其实是 0.30000000000000004。所以条件判断的结果为 false。如果是这样的话,我们有没有什么方式可以判断结果是否相等呢?我们可以使用机器误差 它的值被定义在 Number.EPSILON 中。

function eq(n1, n2) {
    return Math.abs(n1 - n2) < Number.EPSILON;
}

eq(0.1 + 0.2, 0.3);        //true

另外还有一些常量

Number.MAX_VALUE (能够表达的最大数)

Number.MIN_VALUE  (能够表达的最小数)

Number.MAX_SAFE_INTEGER (最大的安全整数)

Number.MIN_SAFE_INTEGER  (最小的安全整数)

可以使用 Number.isInteger 来判断一个数是否是整数,Number.isSafeInteger 判断一个数是否是安全整数。

特殊的值

关于数字还有几个特殊的值.

NaN,它通常被译为 Not a Number 但是它其实也是 number 类型

typeof NaN;    //"number"

它是一个不等于任何值的值(包括它自己)即自反性。

NaN !== NaN;    //true

可以通过 Window.isNaN 来判断一个值是否为 NaN,但是这个函数也将非数字的值认为是 NaN,尽管它是一个 "Not a number."

但是它可能并不是一个 NaN。ES6 中新增的 Number.isNaN 对于其他类型则会认定为 NaN,你也可以使用 v !== v 的方式来判断一个值是否是真正的 NaN,因为只有 NaN 是不等于它自身的。

无穷数,在 JavaScript 中,对于除以 0 或者如果数的计算结果溢出,那么它们将会由两个值来替代。Infinity  与 -Infinity 它们分别被定义在 Number.POSITIVE_INFINITY 与 Number.NEGATIVE_INFINITY 它们分别对应于正无穷大与负无穷大。

计算结果一旦溢出为无穷数,就无法再得到有穷。另外还有几点

  1. Infinity / Infinity 的值为 NaN
  2. 有穷正数除以 Infinity 的值为 0

0 与 -0,在一些场景中可能会用到 -0,在乘除运算中可以得到 -0

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

因为 0 与 -0 是相等的如果需要判断是否是 -0。可以通过

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

isNegZero(0);        //false
isNegZero(3 / -0);   //true

ES6 中新增了 Object.is 方法来判断两个值是否相等,它可以处理 -0 与 0 以及 NaN 的情况

Object.is(NaN, NaN);    //true
Object.is(0, -0);       //false

undefined 与 null

undefined 类型只有一个值 undefined 

null 类型也只有一个值 null

它们两者有一些细微的差别,一般 undefined 用来表示从未赋值。而 null 则代表赋值了,但现在是空值。null 是一个关键字,不允许被赋值。而undefined 则是一个标识符,可以被重新定义。

function foo() {
    undefined = 2;
}

foo();

undefined;    //undefined

非严格模式下,可以为全局的 undefined 赋值,好在这并不会影响 undefined 的值。不过如果在一个作用域中声明一个名为 undefined 的变量(这是合法的,纵使是在严格模式下)。那么根据词法作用域的访问规则,结果可能会吓你一跳。

(function(){
    "use strict";
    var undefined = true;

    if ( undefined ) {
        console.log("A");    //"A"
    }

    undefined;               //true
})()

void 操作符

void 操作符可以让表达式的值返回为 undefined,无论后面的内容是什么,无论 void true、void 1 它们的结果都为 undefined。如果想让函数的返回值为 undefined 并且提前结束函数的时候会比较有用。

void true;    //undefined

void 1;       //undefined

值与引用

在其他的一些语言中,可以使用指向指针的指针,也就是引用传递,像 C# 中的 ref 等... 通过这个指针, 我们可以操作指针所指的内容,从而改变另一个变量所指向的内容。而在 JavaScript 中 我们传递的方法,总是值拷贝,只是拷贝的内容可能是一个引用。对于一个新变量的赋值,只是将这个变量所指向的内容给替换掉,并不会影响原来的内容。关于修改另一个变量的值的方式,可以理解为在对所指变量做了一次封装。从而可以改变另一变量的指向。这几乎又和引用类型与值类型的概念类似,只是存储内容的限制被放宽了。

JavaScript 除了 object, 其他内置类型都是值拷贝,而 object 是引用拷贝。注意函数、数组、以及那些自定义的类型。它们都是引用拷贝的方式传递,函数在运行的时候会对参数自动做一次这样的操作。

如果是引用类型,不希望自己被函数的副作用所改变。那么需要将所有引用的内容复制一遍。如果是值类型希望自己被改变,则可以将自己包装成引用类型。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值