愿你坚持不懈,努力进步,进阶成自己理想的人

—— 2017.09, 写给3年后的自己

《Javascript高级程序设计》读书笔记——1-3章

一、ECMAScript与JavaScript

ECMAScript是JavaScript的语言标准。通常而言,被用来表达相同的含义,但是Javascript的含义实际上要更广一些。一个完整的Javascript实现包含:

  • ECMAScript
  • DOM(文档对象模型)
  • BOM(浏览器对象模型)


二、关于 <script>

在HTML文档中嵌入Javascript代码,采用<script>标签来嵌入脚本。script标签有下列常用的属性:

  • async<script src="xx.js" async="async"></script>,表示立即下载脚本,但是并不是马上执行,而是异步执行(可以跳过执行脚本继续解析HTML文档)
  • defer 表示立即下载脚本,但是需要在文档完全解析完成后才开始执行
  • src 指定引用外部JavaScript代码文件的URL,如果指定了该属性,则 包含在<script></script>标签之间的代码会被忽略

1、浏览器解析文档的规则

浏览器会从头到尾解析HTML文档,如果遇到<script>标签,则会先暂停对其他内容的解析,而先执行script标签中的代码。如果没有指定deferasync属性,那么浏览器会按<script>标签出现的顺序解析,上一个解析完了才解析下一个。
所以,因为浏览器的这种规则,对于script标签,放在文档的后面,可以避免因为解析执行js代码带来的延迟问题
注意: 对于内嵌代码的script标签,defer和async属性是无效的

2、async和defer的区别

两者都可以延迟脚本的执行。但是defer是在HTML文档加载完毕后执行,而async则是异步执行,即解析的时候会先跳过继续往下执行,等到一定的时机时再执行,使用async的时候,不要在加载期间修改DOM

3、script中嵌入代码与引用外部js文件的区别

相比直接在script标签中嵌入代码,引用外部js文件具有以下的好处:

  • 可维护性:js代码与HTML文档分离,便于维护,且方便复用
  • 可缓存:如果有多个HTML页面引用同一个js文件,那么js文件只需要下载一次
  • 适应未来:无需使用XHTML中针对内嵌代码的注释、hack方法,使得XHTML和HTML中使用JS的用法是一致的


三、文档模式

文档模式,有

  • 混杂模式(Quirks Mode)
  • 标准模式(Standards Mode)
  • 准标准模式(Almost Standards Mode)

这些模式会影响CSS的呈现,也会在某些情况下影响JS的解释执行。HTML5中开启标准模式的方法:<!doctype html>

四、Javascript中的关键字和保留字

Javascript中的关键字主要有:

  • 流程:if、else、switch、case、break、default
  • 函数:function、return
  • 循环:do、while、for、continue
  • 变量:var
  • 对象:this、typeof、instanceof、delete、in、with
  • 错误:try、catch、finally、throw
  • 其他:void、debugger

Javascript中的保留字主要有:

  • 面向对象:class、interface、static、super、extends、implements、abstract、private、public、protected
  • 数据类型:int、short、boolean、byte、long、char、float、double
  • 限定符号:const、final
  • 模块管理:import、export
  • 流程相关:goto
  • 线程相关:synchronized、transient、volatile
  • 其他:native、enum

注意:ES5中规定关键字和保留字虽然不能作为变量标识符,但是可以作为对象的属性名。但是一般不推荐使用关键字和保留字作为属性名和变量名,此外,ES5限制严格模式下evalarguments也不能用作标识符和属性名

五、数据类型

Javascript中的数据类型主要有:

  • 原始类型:number、boolean、string、null、undefined
  • 引用类型:object

1、typeof

typeof可以用来检测给定变量的数据类型:

typeof 123; // number
typeof true; // boolean
typeof "Hello"; // string
typeof {}; // object
typeof []; // object
typeof null; // object
typeof undefined; // undefined
typeof Math.max; // function
typeof x; // 变量x是一个未定义的变量,返回undefined


2、undefined和null

undefinednull是两个特殊的类型,这两个特殊的类型,各自都只有一个值。
关于undefined
1、当一个变量声明了未赋值的时候,这个变量的值就是undefined
2、当函数定义了参数,但是参数没有传入值的时候,参数的值就是undefined
3、一个变量没有声明就使用,和一个变量声明了没使用,使用typeof都是得到undefined,但是没有声明就使用的话,则会报错
关于null
1、null主要用来表示空指针对象,当一个变量打算将来用来保存变量的时候,初始值宜设为null
2、标准规定undefined == null返回true

3、boolean类型

1、转化规则:

  • 返回false的情形:false、0、''、NaN、null、undefined
  • 除了上述情况,其他情况下都返回true

2、可以使用!!来强制转化为boolean类型

4、number类型

1、JS中采用IEEE754格式来表示整数和浮点数
2、几种进制的表示:

55; // 十进制
077;// 八进制,但是这种字面量在严格模式下无效,会报错。
088;// 十进制,因为0后面跟着的不是0~7的数,所以前导0会被忽略 
0xF;// 十六进制

3、浮点数的表示

  • 如果小数点后跟着的0的个数>=6个,则会转为科学计数法表示,如:0.000001是表示为0.0000010.0000001则表示为1e-7
  • 类似于0.1 + 0.2 == 0.3会返回false,这是IEEE754格式计算的通病

4、JS中可以表示的数值范围为Number.MIN_VALUE ~ Number.MAX_VALUE,如果超过这个范围,则会表示为-Infinity或者Infinity,如果要测试一个数是否是有穷的,可以使用isFinite()函数来判断
5、NaN是一个特殊的number类型的值,它表示Not a Number,而且,NaN是不等于本身的,即NaN == NaN是返回false的。可以用isNaN()来判断
6、number数值转化规则:

Number("Hello, World"); // NaN
Number(""); // 0
Number("00011"); // 11
Number(true); // 1
Number(undefined); // NaN
Number(null); // 0

对于字符串,遵守以下规则:

  • 只包含数字的情况下,会转为十进制数值。如果包含的是有效的浮点数值如1.1,则转为对于的浮点数;如果有前导0的话,都会被忽略
  • 如果包含的是十六进制的字符串,如0xf,则会转为相应的十进制数值
  • 如果是空串,如'',会转为0
  • 除上述外的,都转为NaN

7、如果是对象的话,则先调用valueOf()方法再转化,若仍然返回NaN,则再调用toString()方法
8、使用parseInt()进行更灵活的转化,如parseInt('123aaa')返回123,而Number('123aaa')返回NaN。此外,parseInt()可以 传入第二个参数,用于表示要转化的进制
10、使用parseFloat()进行浮点数的转化,该函数只接受10进制数,对于非10进制数,一律转为0。

5、string类型

1、string类型是由0至多个16位Unicode字符组成的字符序列,即字符串。字符串用''或者""包围(和PHP不同,JS中这两种表示是等效的)
2、\xnn以十六进制代码nn表示一个字符,而\xnnnn以十六进制代码nnnn表示一个Unicode字符(这种表示下,算1个字符)
3、string是不可变的,所以一经创建,值便不可改变。如果要改变值,则需要销毁原来的字符串,再创建新的字符串
4、除了nullunderfined,其他的类型都可以调用toString()方法来转化为字符串。toString()方法接受一个参数,表示要输出的进制。如:

var num = 25;
num.toString(16); // 输出19

5、String 构造函数也可以进行类型转化。而且比toString()更灵活的是,它还可以转化underfiendnull,如:

String(123);        // "123"
String(null)        // "null"
String(undefined);  // "undefined"
String(false);      // "false"
String(true);       //"true"

6、String构造函数执行以下的规则:

  • 如果值有toString()方法,则调用该函数的输出结果
  • 如果值为null或者undefined,则返回"null"或者"undefined"

7、可以使用形如123 + ''的形式,强行转化为字符串

6、object类型

创建Object类型实例的方式为:
var o = new Object(),在不传给构造函数参数的情况下,可以省略圆括号,如:var o = new Object;
Javascript中的一切对象(除了宿主对象外,都继承自Object类),Object的每个实例均有以下方法:

  • constructor 保存着用于创造当前对象的构造函数
  • hasOwnProperty(propertyName) 判断当前实例本身是否有属性propertyName(而不是在原型链上有)
  • obj1.someisPrototypeOf(obj2) 用于检查obj1是否是obj2的原型
  • propertyIsEnumerable(propertyName) 检查某个属性是否可枚举(如果可以枚举,则可以用for-in来枚举出来),如[1, 2, 3].propertyIsEnumerable('length')返回的是false
  • toLocaleString() 返回对象的字符串表示,字符串与执行环境的地区对应
  • toString() 返回对象的字符串表示
  • valueOf() 返回对象的字符串、数值或者布尔值表示


六、操作符

1、+-++--这些操作符,会先将操作对象转化为number类型,再执行操作
2、任意类型+一个字符串,转为结果为string类型
3、使用&&或者||这两个逻辑运算符的时候,具有短路特性。而且如果两个操作数中有一个不是布尔值,那么逻辑操作就不一定返回布尔值,如:

1 && 2; // 返回 2
1 || 2; // 返回 1
[1, 2, 3] || true; // 返回[1, 2, 3]
true && [1, 2, 3]; // 返回[1, 2, 3]

4、在关系运算中,如果比较对象有一个为数值,一个不为数值,则另一个不为数值的对象会被转为数值。如:

'23' < 3; // false,'23'会被转为23,再与3比较
'a' < 3; // false,'a'会被转为NaN,任何操作数与NaN进行关系比较,结果都是false

5、=====
1)对于==,执行的是“相等”比较,会先进行类型转换再比较。不相等用!=
2)对于===,执行的是“全等”比较,直接进行比较,不会转换。不全等用!==


七、函数

1、JavaScript中,不要求函数定义时的参数个数和实际传入的时候要一致。即JS中是没有函数签名这种限制的
2、函数内部有一个arguments对象,它类似于数组(使用下标0~n调用,有length属性),但是不是数组(所谓的Array-Like Object)
3、arguments的值是和参数保持同步的,即:

function fn(a, b) {
    a = 5;
    console.log(arguments[0]);
}
fn(1); // 输出 5

但是,这并不代表访问两个值读取的是同一内存单元,事实上,它们的内存单元是独立的,仅仅只是值保持同步。类似于例子中的a参数和b参数,被称为命名参数,没有传递值的命名参数,默认值是undefined

注意:在严格模式下,arguments的值不会和命名参数保持同步

4、JavaScript中是没有重载的,如果要实现重载,则可以通过arguments参数进行模拟