0x01.犀牛书札记(ch1-3)

本书资源
http://shop.oreilly.com/product/9780596805531.do

ch1 语言介绍

内容 HTML 行为JS 样式CSS
高端、动态、弱语言,非常适合面向对象和函数式编程风格
特点:一等函数(first-class function)、基于原型(prototype-based)

输入输出功能由宿主环境(host enviroment)提供 ,基于浏览器的API统称为客户端JavaScript

函数和对象合写在一起,函数就变成了”方法 method”

ch2 词法结构

标签和属性必须小写.
Js会忽略程序中标识(token)之间的空格,也会忽略换行符。
回车符(\u000D) 加 换行符(\u000A)在一起被解析为一个单行结束符。
Unicode 转义序列 \uXXXX X为16进制数 “café” === ‘caf\u00e9’

直接量( literal)是程序中直接使用的数据值。 (数字、字符串、正则表达式、数组、对象等直接量)
标识符必须以字母、下划线(_)或美元符($)开始。后续的字符可以是字母、数字、下划线或美元符。

只有在缺少了分号就无法正确解析代码的时候,JavaScript才会填补分号。如果当前语句和随后的非空格字符不能当成一个整体来解析的话,JavaScript就在当前语句行结束处填补分号

1
2
3
4
5
6
7
8
9
10
11
/*
var a
a
=
3
console.log(a)
//解析成 var a; a = 3; console.log(a);
var x = 0 // 这里省略了分号
;[x,x+1,x+2].forEach(console.log) // 前面的分号保证了正确地语句解析
*/

ch3 类型、值、变量

数据类型分类:

  • 原始类型(primitive type)
  • 对象类型(object type)

原始类型包括

  • 数字
  • 字符串
  • 布尔值
  • null(空)
  • undefined(未定义)

对象类型(object type) 是属性(property)的集合。

  • 全局对象(global object)
  • 数组(array)带编号的有序集合
  • 函数

函数
如果函数用来初始化(使用new运算符)一个新建的对象,我们称之为构造函数(constructor)。每个构造函数定义了一类(class)对象–构造函数初始化对象组成的集合。类可以看做对象类型的子类型。

  • 数组(Array)类
  • 函数(Function)类
  • 日期(Date)类定义了代表日期的对象。
  • 正则(RegExp)类定义了表示正则表达式的对象,强大通用的文本处理工具。
  • 错误(Error)类定义了那些表示JavaScript程序中运行时错误和语法错误的对象。

js中只有对象才能拥有方法。数字,字符串,布尔值也拥有自己的方法。只有null和undefined是无法拥有方法的值。

  • 可变(mutable)
  • 不可变(immutable)
    对象、数组、函数属于可变类型
    字符串、数字、布尔值、null和undefined属于不可改变的类型。

js的变量是无类型的(untyped),变量可以被赋予任何类型的值,使用var关键字来声明(declare)变量。javascript采用语法作用域,不在任何函数内声明的变量称为全局变量(global variable)它在程序中任何地方都是可见的。

3.1数字

数字均用浮点数值表示。采用64位浮点格式表示数字,实际的操作(数组索引,位操作符)则是基于32位整数。

数字直接量(numeric literal)
十六进制 “0x”或“0X” 八进制 0开头 0377 ECMAScript 6的严格模式下,八进制直接量是明令禁止的

溢出(overflow)
的数字上限(溢出),结果为一个特殊的无穷大(infinity)值,以Infinity表示。当负数的值超过了负数范围,结果为负无穷大以-Infinity表示。
无穷大值:基于它们的加、减、乘和除运算结果还是无穷大值(保留正负号)。
下溢(underflow)
当运算结果无限接近于零并比JavaScript能表示的最小值还小的时候发生的一种情形。返回0。负数发生下溢时,返回“负零”。

被零整除
被零整除并不报错:返回无穷大(Infinity)或负无穷大(-Infinity)。
零除以零运算结果也是一个非数字(not-a-number)值,用NaN表示。无穷大除以无穷大、给任意负数作开方运算或者算术运算符与不是数字或无法转换为数字的操作数一起使用时都将返回NaN。
NaN和任何值都不相等,包括自身。当且仅当x为NaN的时候,表达式x!=x的结果才为true。
函数isNaN(),如果参数是NaN或者是一个非数字值(比如字符串和对象),则返回true。
函数isFinite(),在参数不是NaN、Infinity或-Infinity的时候返回true。

1
2
3
4
5
6
Infinity/0 //Infinity
0/0 //NaN
Infinity/Infinity //NaN
Number.MIN_VALUE/2 //下溢 0
Infinity==-Infinity //=>false 非数值和任何值(包括自身)都不相等。

浮点数表示法精度
二进制浮点数表示法并不能精确表示十进制的分数。

1
2
.3-.2 //=>0.09999999999999998
.2-.1 //=>0.1

3.2 文本

字符串(string)是一组由16位值组成的不可变的有序序列。JavaScript通过字符串类型来表示文本。字符串的长度(length)是其所含16位值的个数。空字符串(empty string)长度为0,JavaScript中并没有表示单个字符的“字符型”。

字符串是固定不变的,一些方法都返回新字符串,原字符串本身并没有发生改变。

1
2
3
4
5
//ECMAScript 5中,字符串直接量可以拆分成数行,每行必须以反斜线(\)结束,反斜线和行结束符都不算是字符串直接量的内容。
//=> "onelongline"
"one\
long\
line"

转义字符(escape sequence)
转义字符 含义
\o NUL字符(\u0000)
\b 退格符(\u0008)
\t 水平制表符(\u0009)
\n 换行符(\u000A)
\v 垂直制表符(\u000B)
\f 换页符(\u000C)
\r 回车符(\u000D)
\” 双引号(\u0022)
\’ 撇号或单引号(\u0027)
\ 反斜线(\u005C)
\xXX 由两位十六进制数XX指定的Latin-1字符
\uXXXX 由4位十六进制数XXXX指定的Unicode字符

3.3 布尔值

任意JavaScript的值都可以转换为布尔值。false和下面6个可以转换成false的值有时称做“假值”(falsy value);所有其他值,包括所有对象(数组)都会转换成true,其他值称做“真值”(truthy value)。

1
2
3
4
5
6
7
8
9
10
11
12
undefined
null
0
-0
NaN
"" // 空字符串
console.log( false == null ) // false
console.log( false == undefined ) // false
console.log( false == 0 ) // true
console.log( false == '' ) // true
console.log( false == NaN ) // false

3.4 null、undefined

两者不包含任何属性和方法。 变量、属性赋值、参数传入 推荐使用null.
null是关键字,描述“空值”。null认为是一个特殊的对象值,含义是“非对象”。null是它自有类型的唯一一个成员,它可以表示数字、字符串和对象是“无值”的。

undefined(未定义的值)表示更深层次的“空值”。

  • 变量没有初始化
  • 查询对象属性或数组元不存在
  • 函数没有返回任何值,则返回undefined
  • 引用没有提供实参的函数形参的值
  • undifined是这个类型的唯一成员
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typeof(null); //=> object
typeof(undifined); //=> undifined
null == undefined; //=> true
```
## 3.5 全局对象(global object)
当JavaScript解释器启动时将创建一个新的全局对象,并定义如下属性
- 全局属性
- 全局函数
- 构造函数
- 全局对象
```javascript
//使用JavaScript关键字this来引用全局对象
var global = this; // 定义一个引用全局对象的全局变量

3.6 包装对象

存取字符串、数字或布尔值的属性时创建的临时对象称做包装对象(一种实现细节)。
只要引用了属性,JavaScript就会将字面量通过调用new String()/Number()/ Boolean()构造函数创建一个临时对象,这些方法的调用均是来自于这个临时对象。
一旦属性引用结束,这个新创建的对象就会销毁。
null和undefined没有包装对象:访问它们的属性会造成一个类型错误。

“==”等于运算符将原始值和其包装对象视为相等, === 全等运算符视为不等

var s = “test”, n = 1, b = true; // 一个字符串、数字和布尔值
//显示创建包装对象
var S = new String(s); // 一个字符串对象
var N = new Number(n); // 一个数值对象
var B = new Boolean(b); // 一个布尔对象

console.log( s == S ); // true
console.log( s === S ); // false
typeof(s); // “string”
typeof(S); // “object”

3.7 不可变的原始值和可变的对象引用

对象(包括数组和函数)称为引用类型(reference type), 对象的比较均是引用的比较:当且仅当它们引用同一个基对象时,它们才相等。

1
2
3
4
var o = { x: 1 }, p = { x: 1 };
o === p; // false
var a = [], b = [];
a === b; // false

3.8 类型转换

值/from 字符串/to 数字/to 布尔值/to 对象/to
undefined “undefined” NaN false throws TypeError
null “null” 0 false throws TypeError
true “true” 1 new Boolean(true)
false “false” 0 new Boolean(false)
“”(空字符串) 0 false new String(“”)
“1.2” 1.2 true new String(“1.2”)
“one” NaN true new String(“one”)
0 “0” false new Number(0)
-0 “0” false new Number(-0)
NaN “NaN” false new Number(NaN)
Infinity “Infinity” true new Number(Infinity)
-Infinity “-Infinity” true new Number(-Infinity)
1 “1” true new Number(1)
{}(任意对象) 明细 明细 true
[] (任意数组) “” 0 true
[9] (1个数字元素) “9” 9 true
[‘a’] (其他数组) join()方法 NaN true
function(){}(任意函数) 明细 NaN true

转换和相等性

== 在判断时进行了类型转换, 一个值转换为另一个值并不意味着两个值相等。

1
2
//undefined转换成false
undefined == false //false

显示类型转换

最简单的方法就是使用Boolean()、Number()、String()或Object()函数。除了null或undefined之外的任何值都具有toString()方法,这个方法的执行结果通常和String()方法的返回结果一致。

  • “+”运算符的一个操作数是字符串,将会把另外一个操作数转换为字符串。
  • 一元“+”运算符将其操作数转换为数字。
  • 一元“!”运算符将其操作数转换为布尔值并取反。
1
2
3
x + "" // String(x)
+x // Number(x) x-0
!!x // Boolean(x)

toString()方法 可以接收表示转换基数(radix)的可选参数,如果不指定此参数,转换规则将是基于十进制。支持进制数(范围在2~36之间)

parseInt()函数 parseFloat()函数(全局函数)

如果字符串前缀是“0x”或者“0X”,parseInt()将其解释为十六进制数,方法会跳过任意数量的前导空格,尽可能解析更多数值字符,并忽略后面的内容。如果第一个非空格字符是非法的数字直接量,将最终返回NaN。
parseInt()可以接收第二个可选参数,这个参数指定数字转换的基数,合法的取值范围是2~36

3.8.3对象转换为原始值

所有的对象(包括数组和函数)都转换为true。 适用于包装对象,new Boolean(false)是一个对象而不是原始值,它将转换为true。

++只适用于本地对象(native object)++ 对象继承了俩个转换方法:

1.toString()

  • 默认的toString()方法返回 “[object Object]”
  • 数组类(Array class)将每个数组元素转换为一个字符串,并在元素之间添加逗号后合并成结果字符串。
  • 函数类(Function class)返回这个函数的实现定义的表示方式。
  • 日期类(Date class)返回了一个可读的(可被JavaScript解析的)日期和时间字符串。
  • RegExp类(RegExp class)将RegExp对象转换为表示正则表达式直接量的字符串。

2.valueOf()
如果存在任意原始值,它就默认将对象转换为表示它的原始值。
对象是复合值,而且大多数对象无法真正表示为一个原始值,因此默认的valueOf()方法简单地返回对象本身,而不是返回一个原始值。

  • 数组、函数和正则表达式 返回对象本身。
  • 日期类 返回它的一个内部表示:1970年1月1日以来的毫秒数。

步骤:对象到字符串(object-to-string)

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

步骤:对象到数字(object-to-number)

  1. 如果对象具有valueOf()方法,后者返回一个原始值,则JavaScript将这个原始值转换为数字并返回这个数字。
  2. 否则,如果对象具有toString()方法,后者返回一个原始值,则JavaScript将其转换并返回。
  3. 否则,JavaScript抛出一个类型错误异常。

数组是对象,调用valueOf方法无法返回原始值,所以调用toString().空数组转换成空字符串,然后空字符串转化成0;含一个元素的数组转换为字符串结果,然后转化为数值。

运算符

“+” 可以数字和字符串连接操作,若果一个操作数时对象,对象转为原始值。
“==” 原始值和对象比较,对象转换为原始值进行比较。

对象到原始值的转换:非日期对象先尝试调用valueOf(),然后调用toString()返回的原始值将被直接使用,不会被强制转换为数字或字符串;日期对象直接转换成字符串。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
"2"+3 //"23"
2+[2] //"22"
2+[2,3] //"22,3"
2+[] //"2"
[2]==2 //true
[2]=='2' //true
[]=='' //true
//日期对象
var now=new Date()
typeof(now+1) //"string"
typeof(now-1) //"number"
now==now.toString() //true
now>(now-1) //true

3.10 变量作用域

变量值初始值时 undefined. 没有块级作用域(block scope)。 函数作用域(function scope):变量在声明它们的函数体以及这个函数体嵌套的任意函数体内都是有定义的。

声明提前(hoisting)
函数里声明的所有变量(但不涉及赋值)都被“提前”至函数体的顶部. 变量声明放在函数体顶部。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var scope = "global";
function f() {
console.log(scope); // 输出"undefined",而不是"global"
var scope = "local"; // 变量在这里赋初始值,但变量本身在函数体内任何地方均是有定义的
console.log(scope); // 输出"local"
}
//等价于
var scope = "global";
function f() {
var scope;
console.log(scope);
scope = "local";
console.log(scope);
}

全局变量(global variable)

当声明一个JavaScript全局变量时,实际上是定义了全局对象的一个属性。

  • 当使用var声明一个变量时,创建的这个属性是不可配置的,无法通过delete运算符删除。
  • 在非严格模式并给一个未声明的变量赋值的话,JavaScript会自动创建一个全局变量,是可配置属性,可以删除。

作用域链(scope chain)

JavaScript是基于词法作用域(lexical scoping)的语言:通过阅读包含变量定义在内的数行源码就能知道变量的作用域。

当JavaScript需要查找变量x的值的过程称做“变量解析”(variable resolution)

在最顶层代码中(也就是不包含在任何函数定义内的代码),作用域链由一个全局对象组成。

在不包含嵌套的函数体内,作用域链上有两个对象,
第一个是定义函数参数和局部变量的对象,
第二个是全局对象。
在一个嵌套的函数体内,作用域链上至少有三个对象。

当定义一个函数时,它实际上保存一个作用域链。当调用这个函数时,它创建一个新的对象来存储它的局部变量,并将这个对象添加至保存的那个作用域链上,同时创建一个新的更长的表示函数调用作用域的“链”。
对于嵌套函数来讲,事情变得更加有趣,每次调用外部函数时,内部函数又会重新定义一遍。因为每次调用外部函数的时候,作用域链都是不同的。内部函数在每次定义的时候都有微妙的差别——在每次调用外部函数时,内部函数的代码都是相同的,而且关联这段代码的作用域链也不相同。

坚持原创技术分享,您的支持将鼓励我继续创作!