JavaScript高级程序设计 - 读书笔记

目录

JavaScript高级程序设计 - 读书笔记 by JerryChan

第二章 在HTML中嵌入JavaScript

2.5 小结

把JavaScript插入到HTML页面中要使用<script>元素。使用这个元素可以把JavaScript嵌入到HTML页面中,让脚本与标记混合在一起;也可以包含外部的JavaScript文件。而我们需要注意的地方有:

  • 在包含外部JavaScript文件时,必须将src属性设置为指向相应文件 的 URL。而这个文件既可以是与包含它的页面位于同一个服务器上的文件,也可以是其他任何域中的文件。
  • 所有<script>元素都会按照它们在页面中出现的先后顺序依次被解析。在不使用defer和async属性的情况下,只有在解析完前面<script>元素中的代码之后,才会开始解析后面<script>元素中的代码。
  • 由于浏览器会先解析完不使用defer属性的<script>元素中的代码,然后再解析后面的内容,所以一般应该把<script>元素放在页面最后,即主要内容后面,</body>标签前面。
  • 使用defer属性可以让脚本在文档完全呈现之后再执行。延迟脚本总是按照指定它们的顺序执行。
  • 使用async属性可以表示当前脚本不必等待其他脚本,也不必阻塞文档呈现。不能保证异步脚本按照它们在页面中出现的顺序执行。

另外,使用<noscript>元素可以指定在不支持脚本的浏览器中显示的替代内容。但在启用了脚本的情况下,浏览器不会显示<noscript>元素中的任何内容。

第三章 基本概念

3.1.4 严格模式

ECMAScript 5引入了严格模式(strictmode)的概念。严格模式是为JavaScript定义了一种不同的解析与执行模型。在严格模式下,ECMAScript 3中的一些不确定的行为将得到处理,而且对某些不安全的操作也会抛出错误。要在整个脚本中启用严格模式,可以在顶部添加如下代码:

"use strict";

在函数内部的上方包含这条编译指示,也可以指定函数在严格模式下执行:

functiondoSomething(){
    "usestrict";
    //函数体
}

严格模式是一个编译指示,目的是为了兼容 ECMAScript 3语法。

3.3 变量

虽然省略var操作符可以定义全局变量,但这也不是我们推荐的做法。因为在局部作用域中定义的全局变量很难维护,而且如果有意地忽略了var操作符,也会由于相应变量不会马上就有定义而导致不必要的混乱。给未经声明的变量赋值在严格模式下会导致抛出ReferenceError错误。

省略var可声明全局变量,但不推荐使用。

3.4 数据类型

ECMAScript中有5种简单数据类型(也称为基本数据类型):Undefined、Null、Boolean、Number和String。

使用操作符typeof可以检测变量的数据类型。

3.4.3 Null类型

实际上,undefined值是派生自null值的,因此ECMA-262规定对它们的相等性测试要返回true:

alert(null == undefined); //true

无论在什么情况下都没有必要把一个变量的值显式地设置为undefined,可是同样的规则对null却不适用。换句话说,只要意在保存对象的变量还没有真正保存对象,就应该明确地让该变量保存null值。这样做不仅可以体现null作为空对象指针的惯例,而且也有助于进一步区分null和undefined。

3.4.4 Boolean类型

可以对任何数据类型的值调用Boolean()函数,而且总会返回一个Boolean值。至于返回的这个值是true还是false,取决于要转换值的数据类型及其实际值。下表给出了各种数据类型及其对应的转换规则。

数据类型 转换为true的值 转换为false的值
Boolean true false
String 任何非空字符串 ""(空字符串)
Number 任何非零数字值(包括无穷大) 0和NaN(参见本章后面有关NaN的内容)
Object 任何对象 bull
Undefined n/a undefined

n/a(或N/A),是notapplicable的缩写,意思是“不适用”。

3.4.5 Number类型

八进制字面量在严格模式下是无效的,会导致支持的JavaScript引擎抛出错误。在进行算术计算时,所有以八进制和十六进制表示的数值最终都将被转换成十进制数值。

浮点数值的最高精度是17位小数,但在进行算术计算时其精确度远远不如整数。例如,0.1加0.2的结果不是0.3,而是0.30000000000000004。这个小小的舍入误差会导致无法测试特定的浮点数值。例如:

if(a + b == 0.3){
    //不要做这样的测试!
    alert("You got 0.3.");
}

永远不要测试某个特定的浮点数值。这是使用基于IEEE754数值的浮点计算的通病。

由于内存的限制,ECMAScript并不能保存世界上所有的数值。ECMAScript能够表示的最小数值保存在Number.MIN_VALUE中——在大多数浏览器中,这个值是5e-324;能够表示的最大数值保存在Number.MAX_VALUE中——在大多数浏览器中,这个值是1.7976931348623157e+308。如果某次计算的结果得到了一个超出JavaScript数值范围的值,那么这个数值将被自动转换成Infinity值。具体来说,如果这个数值是负数,则会被转换成-Infinity(负无穷),如果这个数值是正数,则会被转换成Infinity(正无穷)。

NaN,即非数值(NotaNumber)是一个特殊的数值,这个数值用于表示一个本来要返回数值的操作数未返回数值的情况(这样就不会抛出错误了)。NaN有两个特点。首先,任何涉及NaN的操作(例如NaN/10)都会返回NaN,这个特点在多步计算中有可能导致问题。其次,NaN与任何值都不相等,包括NaN本身。例如,下面的代码会返回false:

alert(NaN == NaN); //false

针对NaN的这两个特点,ECMAScript定义了isNaN()函数。这个函数接受一个参数,该参数可以是任何类型,而函数会帮我们确定这个参数是否“不是数值”。例如:

alert(isNaN(NaN));   //true 
alert(isNaN(10));    //false(10是一个数值)
alert(isNaN("10"));  //false(可以被转换成数值10)
alert(isNaN("blue"));//true(不能转换成数值)
alert(isNaN(true));  //false(可以被转换成数值1)

使用parseInt()进行转换时,应当在第二个参数指定基数。

3.4.6 String类型

在不知道要转换的值是不是是不是null或undefined的情况下,还可以使用转型函数String(),这个函数能够将任何类型的值转换为字符串。String()函数遵循下列转换规则:

  • 如果值有toString()方法,则调用该方法(没有参数)并返回相应的结果;
  • 如果值是null,则返回"null";
  • 如果值是undefined,则返回"undefined"。

3.4.7 Object类型

仅仅创建Object的实例并没有什么用处,但关键是要理解一个重要的思想:即在ECMAScript中,(就像Java中的java.lang.Object对象一样)Object类型是所有它的实例的基础。换句话说,Object类型所具有的任何属性和方法也同样存在于更具体的对象中。

Object的每个实例都具有下列属性和方法。

  • Constructor:保存着用于创建当前对象的函数。
  • hasOwnProperty(propertyName):用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,作为参数的属性名(propertyName)必须以字符串形式指定(例如:o.hasOwnProperty("name"))。
  • isPrototypeOf(object):用于检查传入的对象是否是另一个对象的原型。
  • propertyIsEnumerable(propertyName):用于检查给定的属性是否能够使用for-in语句来枚举。
  • toLocaleString():返回对象的字符串表示,该字符串与执行环境的地区对应。
  • toString():返回对象的字符串表示。
  • valueOf():返回对象的字符串、数值或布尔值表示。通常与toString()方法的返回值相同。

3.5 操作符

左移/右移(<</>>):以符号位填充。
无符号左移/右移(<<</>>>):以0填充。负数会变成无符号数(出现大整数的错误结果)。
在涉及Infinity、-Infinity、NaN等数值的运算时要倍加小心。
字符串比较时,比较的是字符编码(如B>a为真,"23" < "3"为真),最好避免隐式转换。
尽量使用全等===和不全等!==操作符,避免隐式转换带来的问题。

3.6 语句

with语句:大量使用with语句会导致性能下降,同时也会给调试代码造成困难,因此在开发大型应用程序时,不建议使用with语句。
for-in语句:用于枚举对象的所有属性。

3.7 函数

关于返回值:推荐的做法是要么让函数始终都返回一个值,要么永远都不要返回值。否则,如果函数有时候返回值,有时候有不返回值,会给调试代码带来不便。

严格模式对函数有一些限制:

  • 不能把函数命名为eval或arguments;
  • 不能把参数命名为eval或arguments;
  • 不能出现两个命名参数同名的情况。

对参数的理解

ECMAScript函数的参数与大多数其他语言中函数的参数有所不同。ECMAScript函数不介意传递进来多少个参数,也不在乎传进来参数是什么数据类型。也就是说,即便你定义的函数只接收两个参数,在调用这个函数时也未必一定要传递两个参数。可以传递一个、三个甚至不传递参数,而解析器永远不会有什么怨言。之所以会这样,原因是ECMAScript中的参数在内部是用一个数组来表示的。函数接收到的始终都是这个数组,而不关心数组中包含哪些参数(如果有参数的话)。如果这个数组中不包含任何元素,无所谓;如果包含多个元素,也没有问题。实际上,在函数体内可以通过arguments对象来访问这个参数数组,从而获取传递给函数的每一个参数。

其实,arguments对象只是与数组类似(它并不是Array的实例),因为可以使用方括号语法访问它的每一个元素(即第一个元素是arguments[0],第二个元素是arguments[1],以此类推),使用length属性来确定传递进来多少个参数。ECMAScript不支持重载,但利用这一属性,可以模仿方法的重载。

function sayHi() { 
    alert("Hello" + arguments[0] + "," + arguments[1]); 
}

这个重写后的函数中不包含命名的参数。虽然没有使用name和message标识符,但函数的功能依旧。这个事实说明了ECMAScript函数的一个重要特点:命名的参数只提供便利,但不是必需的。

第四章 变量、作用域和内存问题

4.1 基本类型和引用类型的值

第3章讨论了5种基本数据类型:Undefined、Null、Boolean、Number和String。这5种基本数据类型是按值访问的,因为可以操作保存在变量中的实际的值。

引用类型的值是保存在内存中的对象(Object)。与其他语言不同,JavaScript不允许直接访问内存中的位置,也就是说不能直接操作对象的内存空间。在操作对象时,实际上是在操作对象的引用而不是实际的对象。为此,引用类型的值是按引用访问的。

Copyright: 泽卡斯(Zakas. Nicholas C.). JavaScript高级程序设计(第3版) (图灵程序设计丛书) (Kindle位置2591). 人民邮电出版社.

猜你喜欢

转载自www.cnblogs.com/JerryChan31/p/9386002.html