# 值和变量

计算机程序的运行需要対值进行操作。在编程语言中，能够表示并操作的值的类型称作数据类型，编程语言最基本的特性就是能够支持多种数据类型。 当程序需要将值保存起来以备将来使用时，便将其赋值给一个变量。变量是一个值的符号名称，可以通过名称来获得对值的引用。变量的工作机制是编程语言的另一个基本特性。

javascript 能表示的最大值是 `±1.7976931348623157×10^308`，最小值是 `±5×10^-324`。

按照 javascript 中数字的格式，能够表示的整数范围是 `-2^53 ～ 2^53`。

### 整型直接量

javascript 的十六进制的直接量是指以“0x”或“0X”为前缀，其后跟随十六进制数串的直接量。下面为一个十六进制例子：

```javascript
0xff // 15*16 + 15 = 255 (十进制)
```

尽管 ECMAScript 标准不支持八进制直接量，但 javascript 的某些实现可以允许采用把八进制形式表示整数。八进制直接量以数字 0 开始，其后跟随一个由 0 ～ 7 之间的数字组成的序列，例如：

```javascript
0377 // 3*64 + 7*8 + 7 = 255(十进制)
```

由于某些 javascript 的实现支持八进制直接量，而有些不支持，因此最好不要使用以 0 为前缀的整型直接量。

### 浮点型直接量

浮点数语法表示 `[digits][.digits][(E|e)[+|-]digits]`，例如：

```javascript
6.02e23 //6.02 × 10^23
1.4738223e-32 //1.4738223 × 10^-32
```

### JavaScript 中的算术运算

javascript 的运算通过作为 Math 对象的属性定义的函数和常量来实现：

```javascript
Math.pow(2, 53) // => 9007199254740992: 2的 53次幂
Math.round(0.6) // => 1.0: 四舍五入
Math.ceil(0.6) // => 1.0: 向上求整
Math.floor(0.6) // => 0.0: 向下求整
Math.abs(-5) // => 5: 求绝对值
Math.max(x, y, z) // 返回最大值
Math.min(x, y, z) // 返回最小值
Math.random() // 生成一个大于等于0小于1.0的伪随机数
Math.PI // Π: 圆周率
Math.E // e: 自然对数的底数
Math.sqrt(3) // 3的平方根
Math.pow(3, 1 / 3) // 3的立方根
Math.sin(0) // 三角函数: 还有Math.cos，Math.atan等
Math.log(10) // 10的自然底数
Math.log(100) / Math.LN10 // 以10为底100的对数
Math.log(512) / Math.LN2 // 以2为底512的对数
Math.exp(3) //e的三次幂
```

javascript 中的算术运算在溢出、下溢或被零整除时不会报错。当数字运算结果超过了 javascript 所能表示的数字上限，结果为一个特殊的无穷大(infinity)值，在 javascript 中以 `Infinity` 表示。同样地,当负数的值超过了 javascript 所能表示的负数范围，以`-Infinity` 表示，基于无穷大值的加、减、乘、除运算结果还是无穷大值。

下溢是当运算结果无限接近于零并比 javascript 能表示的最小值还小的时候发生的一种情形。这种情况下，javascript 将返回 `0`。

在 javascript 中被零整除并不会报错：他只是简单的返回无穷大(Infinity)或负无穷大(-Infinity)。但有一个例外，零除以零是没有意义的，运算结果以 NaN 表示。无穷大除以无穷大、给任意负数作开方运算或者算术运算符与不是数字或无法转换为数字的操作数一起使用都将返回 `NaN`。

javascript 中的非数字有一点特殊，他和任何值都不相等，包括自身。判定 `X` 是否是 `NaN` 可用`X!=X`来判断，当且仅当 `X` 为 `NaN` 的时候，表达式的结果才为 `true`。

### 二进制浮点数和四舍五入错误

javascript 在某些情况不能精确的表述：

```javascript
var x = 0.3 - 0.2 // 30美分减去20美分
var y = 0.2 - 0.1 // 20美分减去10美分
x == y // => false,两值不相等！
x == 0.1 // => false: .3-.2 不等于 .1
y == 0.1 // => true .2-.1 等于 .1
```

鉴于以上情况，在进行重要的金融计算是应使用大整数。

### 转义字符

javascript 转义字符：

```
    \o                   NUL字符
    \b                   退格符
    \t                   水平制表符
    \n                   换行符
    \v                   垂直制表符
    \f                   换页符
    \r                   回车符
    \"                   双引号
    \'                   撇号或单引号
    \\                   反斜线
    \xXX                 由两位十六进制数XX指定的Latin-1字符
    \uXXXX               由4位十六进制数XXXX指定的Unicode字符
```

如果`"\"`字符位于没有在上面列出的字符前，则忽略`"\"`。比如，`"\##"`和`"##"`等价

### 字符串的使用

在 javascript 中的字符串是固定不变的，类似 `replace()`和 `toUpperCase()`的方法都返回新的字符串，原来字符串本身并没有发生变化。

### 布尔值

任意 javascript 的值都可以转换为布尔值。下面这些值会被转换成`false`:

```javascript
undefined
null
0 - 0
NaN
;('') //空字符串
```

### null 和 undefined

`null`是 javascript 语言的关键字，常用来描述“空值”。对`null`执行`typeof`运算，结果返回字符串`“object”`。通常认为`null`是它自有类型的唯一一个成员，它可以表示数字、字符串和对象是“无值”的。

`undefined`用未定义的值表示更深层次的“空值”。表明变量没有初始化，如果要查询的对象属性或数组元素的值是返回`undefined`则说明这个属性或元素不存在。如果函数没有返回任何值，则返回`undefined`。引用没有提供实参的函数形参的值也只会得到`undefined`。

`null`和`undefined`是不同的，两者可以互换。判断相等运算符 `“==”`认为两者是相等的(要使用严格相等的运算符 `“===”` 来区分它们)。

可以理解为`undefined`表示系统级的、出乎意料的或类似错误的值的空缺、而`null`是表示程序级的、正常的或意料之中的值的空缺。

### 全局对象

当 javascript 解释器启动时(或者任何 Web 浏览器加载新页面的时候)，它将创建一个新的全局对象，并给它一组定义的初始属性：

1. 全局属性，比如`undefined`、`infinity`和`NaN`
2. 全局函数，比如`isNaN()`、`parseInt()`和`eval()`
3. 构造函数，比如`Date()`、`RegExp()`、`String()`、`Object()`和`Array()`
4. 全局对象，比如`Math`和`JSON`

### 包装对象

javascript 对象是一种复合值：它是属性或已命名值的集合。通过`“.”`符号来引用属性值。当属性值是一个函数的时候，称其为方法。

我们发现字符串也同样具有属性和方法：

```javascript
var s = 'hello world'
var word = s.substring(s.indexOf(' ') + 1, s.length)
```

只要引用了字符串 `s` 的属性，javascript 通过调用 `new String(s)`的方式转换成对象， 这个对象继承了字符串的方法，并用来处理属性的引用。一但属性引用结束，这个新创建的对象就会被销毁。

同字符串一样，数字和布尔值也有各自的方法：`Number()`和 `Boolean()`。

解析以下代码执行结果：

```javascript
var s = 'test'
s.len = 4
var t = s.len
```

得到 `t`的值为 `undefined`。第二行代码创键一个临时字符串对象，并给 `len` 属性赋值为 `4`，随即销毁这个对象。第三行通过原始的字符串创建一个新的字符串对象，尝试读取器 `len` 属性，这个属性自然不存在。

### 值和对象

javascript 中的原生值(`undefined`、`null`)、布尔值、数字和字符串是不可更改的：任何一个方法都无法更改一个原始值。

原始值的比较是值的比较：只有在他们的值相等时他们才相等。对于字符串当且仅当他们长度相等且每个索引的字符都相等时才相等。

对象的值是可变的，对象的比较非值的比较：即使两个对象包含同样的属性以相同的值，它们也是不相等的。各个索引相等的两个数组也不相等。

通常称对象为引用类型，以此来和 javascript 的基本类型区分开来。对象的比较均是引用值的比较：当仅当它们引用同一个基对象时，它们才相等。

```javascript
var a = [] //定义一个引用空数组的的变量a
var b = a //变量b引用同一个数组
b[0] = 1 //通过变量b来修改引用的数组
a === b //=> true：a和b引用同一个数组，因此它们相等
```

### 类型转换

javascript 类型转换

```javascript
值          转换得字符串    数字       布尔值    对象
undefined   "undefined"     NaN        false     error
null         "null"         0          /         erroe
true         "true"         1          /         new Boolean(ture)
false        "false"        0          /         new Boolean(false)
NaN          "NaN"                     false     new Number(NaN)
Infinity     "Infinuty"                false     new Number(Infinity)
[]           ""             0          true
[9]          "9"            9          true
```

### 显示类型转换

在代码中常见的类型转换惯用方法：

```javascript
x + '' //等价于 String(x)
;+x //等价于 Number(x)
!!x //等价于 Boolean(x)
```

Number 类定义的 `toString()`方法可以接收表示转换基数(radux)的可选参数，默认十进制。

如果需要自己控制输出中小数点位置和有效数字位数，或者决定是否需要指数计数法。Number 类为这种数字到字符串的类型转换定义了三个方法。所有这三种方式均会适当的进行四舍五入或填充 0。

`toFixed()`根据小数点后的指定位数将数字转换为字符串，它从不使用指数计数法；

`toExponential()`使用指数计数法将数字转换为指数形式的字符串，其中小数点前只有一位，小数点后的位数则由参数指定(有效位数比指定的位数多一位)；

`toPrecision()`根据指定的有效数字位数将数字转换成字符串。如果有效数字的位数小于整数部分的位数，则转换成指数形式。

```javascript
var n = 123456.789
n.toFixed(2) //"1234556.78"
n.toExponential(3) //"1.235e+5"
n.toPrecision(4) //"1.235e+5"
n.toPrecision(7) //"123456.8"
```

`parseInt()`和 `parseFloat()`都会跳过任意数量的前导空格，尽可能解析更多数值字符，并忽略后面的内容。如果独一个非空格字符是非法的数字直接量，将最终返回 `NaN`：

```javascript
pareInt('3 blind mice') // => 3
parseFloeat('3.14 meters') // => 3.14
parseInt('.1') // =? NaN：整数不能以"."开始
parseFloat('$72.47') // => NaN：数字不能以"$"开始
```

`parseInt()`可以接收第二可选选参数，这个参数指定数字转换的基数，合法的取值范围是 `2-36`，例如：

```javascript
parseInt('11', 2) // => 3 (1*2+1)
parseInt('ff', 16) // => 255 (15*16+15)
```

### 对象转换为原始值

所有对象转布尔值都为 true。包装对象亦是如此：`new Boolean(false)`是一个对象而不是原始值，将转换为`true`。

对象的两个转换方法，`toString()`和`valueOf()`。默认`toString()`方法返回：

```javascript
;({ x: 1, y: 2 }.toString()) // "[object Object]"
```

数组类的`toString()`将每个数组元素转换成一个字符串，并在元素之间添加逗号后合并成结果字符串。函数类的将返回这个函数的实现定义的表示方式。日期类定义的将返回一个可读的日期和时间字符串。`RegExp`类定义的`toString()`将`RegExp`对象转换为表示正则表达式直接量的字符串。

另一个`valueOf()`。对象如果存在任意原始值，它将对象转换它的原始值。但大多数对象无法真正表示为一个原始值，因此默认的`valueOf()`方法简单的返回对象本身，而不是返回一个原始值。数组、函数和正则表示式简单继承这个默认方法，调用这些类型的实例的`valueOf()`方法返回对象本身。日期类的`valueOf()`方法返回它的一个内部表示：1970 年 1 月 1 日以来的毫秒数。

javascript 中对象到字符串的转换经过如下步骤：

1. 如果对象具有 toString()方法，则调用这个方法。如果它返回原始值，javascript 将这个值转换字符串，并返回这个字符串结果。
2. 如果对象没有 toString()方法，或者这个方法并不返回一个原始值，那么 javascript 会调用 valueOf()方法。有则调用，如果返回的是原始值，javascript 将这个值转换为字符串，并返回这个字符串。
3. 否则，javascript 无法从 toString()或 valueOf()获得一个原始值，因此这时它将跑出一个类型错误异常。

在对象到数字的转换过程中，javascript 做了同样的事，只是它会将首先尝试使用`valueOf()`方法。

数组继承了默认的`valueOf()`方法，这个方法返回一个对象而不是一个原始值，因此，数组到数字的转换则调用`toString()`方法。空数组转换成空字符串，空字符串转换成数字`0`。含有一个元素的数组转换成字符串的结果和这个元素转换字符串的结果一样。如果数组只包含一个数字元素，这个数字转换为字符串，在转换为数字。

一般非日期转换基本上是对象到数字的转换,日期对象和`“+”`、`“-”`、`“==”`以及`“>”`的运行结果与一般的不完全一致：

```javascript
var now = new Date() // 创建一个日期对象
typeof (now + 1) // => "string"：“+”将日期转换为字符串
typeof (now - 1) // => "number"：“-”使用对象到数字的转换
now == now.toString() // => true：隐式的和显式的字符串转换
now > now - 1 // => true：“>”将日期转换成数字
```

### 函数作用域和声明提前

javascript 的函数作用域是指函数内声明的所有变量在函数体内始终是可见的。这意味着变量在声明之前甚至已经可用。javascript 的这个特性被非正式的称为声明提前，即 javascript 函数里声明的所有变量都被“提前”至函数体的顶部，示例代码如下：

```javascript
var scope = 'global'
function f() {
  console.log(scope) // 输出"undefined"
  var scope = 'local' // 变量在这里赋初始值
  console.log(scope) // 输出"local"
}
```

### 作为属性的变量

如果没有使用严格模式并给一个未声明的变量赋值的话 javascript 会自动创建一个全局变量。以这种方式创建的变量是全局对象的正常的可配置属性，并可以删除它们：

```javascript
var truevar = 1 // 声明一个不可删除的全局变量
fakevar = 2 // 创建全局对象的一个可删除的属性
this.fakevar2 = 3 // 同上
delete truevar // => false：变量并没有被删除
delete fakevwr // => true：变量被删除
delete this.fakevar2 // => true：变量被删除
```

javascript 全局变量是全局对象的属性，这是 ECMAScript 规范中强制规定的。
