《JavaScript高级程序设计》序、Chapter 1/2/3/4
序
考虑到本书的发行时间,对于一些兼容性的问题按照先按照本书的说法进行记录。
这里记录的是对《JavaScript高级程序设计》第三版一书的纯主观的理解。
Chapter 1 JavaScript简介、发展情况 go
Chapter 2 HTML中使用JS(插入JS及注意事项) go
Chapter 3 JS基本概念(语法、数据类型、语句、函数基本) go
Chapter 4 变量、作用域、内存问题(理解JS的作用域机制)go
Chapter 1(JavaScript简介、发展情况)
- javaScript是为了减轻服务端的负担、减少数据递交浪费的时间而出现的,逐渐发展成比较系统的面向对象的语言、实现交互等功能。
- javaScript的演变经历了公司之间的竞争,最终在W3C等标准协会的介入下形成标准。
- javaScript = ECMAScript + DOM +BOM
- ECMAScript规定了语言部分。
- DHTML->DOM:将Web页面映射成节点(对象)树,便于维护和动态处理,实际上,DOM作为API,不仅适用于Web。
- DHTML、 DOM HTML、DOM core
- BOM:对浏览器窗体的控制等,在HTML5中有形成标准的希望。
Chapter 2(HTML中使用JavaScript)
- <script>可嵌入脚本或者引入外部脚本,也可以在HTML标签中书写简单的javaScript。
- 注意对于type的设置,可以不使用,或者设置成“text/javascript”-->总之要确保服务器正确的返回MIME。
- 下载和执行的顺序问题:
- 一般按照引入的顺序执行,所以放在头部会影响到页面内容的加载,建议放在body标记的最后
- defer属性:延迟脚本。先下载,后执行,在页面加载完毕之后执行。理论上,延迟脚本之间会按照顺序执行,并会在DOMContentLoaded事件触发之前执行。然而实际上并不一定,所以建议只引入单个延迟脚本。
- async属性:顾名思义,异步脚本。避免页面等待脚本的下载和执行,异步加载其余的内容,异步脚本之间不一定按照顺序执行,也不一定会在DOMContentLoaded时间触发之前执行。
- 二者都只对外部脚本有效。
- XHTML(XML):对JS的书写要求更加的严格,可采用<![CData[...]]>减轻对特殊字符的转义的工作量,在脚本中使用//<![CData[...//]]>可实现平稳退化。
- 对于不支持或者禁用了JS的HTML,用<noscript>标记平稳退化,或者用<!-- ... //-->进行平稳退化(不推荐,因为一般浏览器都支持JS了,想要实现平稳退化,可考虑其他更加有效严谨的手段,参照《JavaScript DOM编程艺术》)
- 文档模式:混杂模式、标准模式(HTML5)--->准标准模式,后两者的差距比较下。
- 本书推荐使用外部脚本。
Chapter 3 基本概念(语法、数据类型、语句、函数)
ECMAScript 3 ---> ECMAScript 5
第二次阅读本书,理解起来比第一次看的时候清晰、容易了许多。
- 语法
- 标识符:用作变量、函数、属性的名称
- 关键字:语言本身使用的。
- 保留字:将来可能用作关键字的。
- 变量、字面量:前者为值提供一个占位符,后者就是值本身。
- 关键字和保留字:注意ES3和ES5的不同之处,后者的一般模式和严格模式又有不同。注意eval和arguments的现实。
- 变量:var。弱类型。占位符:不过还是不建议在使用的过程中更改数据类型。
- 数据类型
- 5个基本类型(null\undefined\boolean\number\string)、1个复杂数据类型(引用类型,object)
- typeof返回字符串。主要用来区分具体的基本类型。但会对函数提供特殊的“function”,对于null则认为是object。
- 对于未定义的变量,可以用typeof表示为“undefined”,但无法进行其他的具体操作。而在严格模式下,连typeof操作符也失效。
- null:空对象。表示占位但为赋值(这里和undefined有微妙的不同)。更用来表示未赋值的对象,“空指针”。
- boolean:Boolean()函数
- number类型
- 既可以表示整数,也可以用来表示浮点数。既可以表示十进制,也可以表示其他进制(但在ES3、ES5有差异,一般模式和严格模式也有差异)
- 避免浮点数的计算和比较,因为说到底只是计算机的近似处理。
- 特殊的数值:Infinity/-Infinity/NaN -- isFinity()函数、isNaN()函数---NaN与谁的不相等,包括自身。
- 数值转换(转型函数):Number()函数、parseInt()函数、parseFloat()函数。
- string类型
- 字符一旦创建就不能更改,我们眼中的更改实际上经历了后台对字符串的销毁和再赋值等操作。
- toString()方法和String()函数。后者功能略多些,可以处理undefined和null。
- 区分函数String(value)和方法value.toString()
- 其他类型向数值等进行默认的转换:有普遍的规律。一般会调用Number()转型函数进行转换。对于Object类型,会调用valueOf()方法和toString()方法,前者优先于后者。
- 操作符
- ·一般的操作符的使用,都会涉及到数据类型之间的转换,常见的转换有
- 向数值的转换
- 向字符串的转换
- 向布尔值的转换
- 第一次提到副效应:变量的值在语句被求值之前就改变了(如前置递增、递减操作符)
- 位操作符:注意实际上存储的是64位,但一般按照32位进行处理。貌似较少用到。
- 布尔操作符:逻辑与或非。或和与都是短路操作。以“与”操作为例,当第一个操作数为false,就“短路”---不再考虑第二个操作数,直接返回false;书中有复杂的对于两个操作数有object类型的考虑,考虑到object的转换为布尔类型均为true,实际上这个规律与与、或操作的短路特点有关。
- ·一般的操作符的使用,都会涉及到数据类型之间的转换,常见的转换有
- 语句
- for-in语句:常用来枚举对象属性,并以此为接口进行更多的操作。
- 函数
- 参数:JS中形参传入后将被放到函数内部的一个对象数组arguments[]中作为局部变量,因此JS中函数声明的参数个数(可以通过调用函数的length属性获得)与实际的参数个数(调用arguments.length获得)没有必然的关系。
- 由于上述原因,再加上JS函数名实际上只是一个引用,JS函数没有“函数签名”的概念(同名函数,参数不同视作不同函数)
- 因此,JS函数没有重载的说法,但可以模拟重载。
- 没有重载,体现在:若声明复数个数的同名函数,即使参数不同,最后的函数声明将之前的覆盖。
- 模拟重载,可以这么做:对不同的参数个数用if-else语句书写不同的处理语段,以此进行模拟。
- ES的参数传递的都是值,而非引用(在chapter 4进一步说明)
- 自由的语言
Chapter 4 变量、作用域、内存问题
- 基本类型和引用类型
- 只有引用类型可以动态创建属性(基本类型想要访问方法和属性,得借助于基本包装类型)
- 基本类型占据固定大小的空间(栈内存),引用类型则是堆内存。
- 在进行访问的时候,基本类型按照值访问,而引用类型按照引用访问(实际上,JS不允许直接访问内存,所以引用类型只能依靠指针访问)
- 同样,在进行复制的时候,基本类型创建副本。引用类型同样创建副本,然而这个副本实际上是指向某个内存的引用的副本。
- 在向函数传递参数的时候,无论基本类型还是引用类型,统一按值传递。前者比较好理解,引用类型的按值传递可以依靠下面的例子理解:
function setName(obj){ obj.name = "Nicholas"; obj = new Object(); obj.name = "Peter"; } var person = new Object(); setName(person); alert(person.name); //实际上弹出的是"Nicholas"
-
- 类型检测(typeof以及instanceof):
- 基本类型的检测依靠typeof操作符
- 引用类型可以通过检测所属的类型实例进行检测,即,使用instanceof操作符
- 由于所有的引用类型最终都是Object的实例,所以对于引用类型x,x instanceof Object始终会返回true
- instanceof用于对具体的引用类型进行检测,所以如果这个操作符后所跟的不是引用类型,则会返回false
- 正则表达式的typeof:按照规定,含有[[call]]方法的对象都会返回function。根据浏览器而异。
- 类型检测(typeof以及instanceof):
- 执行环境和作用域
- 通过下图理解以下代码的作用域
-
var color ="blue"; function changecolor(){ var anotherColor = "red"; function swapColor(){ var tempColor = anotherColor; anotherColor = color; color = tempColor; } } changeColor();
- 由某一个对象来代表当前的执行环境,这个对象下又存储着一系列的变量(对象)和方法,如浏览器的window对象,函数内部的arguments对象(“面向对象”)
- 执行环境在该函数执行完毕后销毁,从栈中退出,将控制权交还给上一个执行环境。
- 作用域链随着执行环境的创建而创建,为了可以有序合理的对函数和变量进行访问。
- 标识符的解析:如图,沿着作用域链向上搜索,当搜索到匹配的变量后即停止,不再继续搜索(即使父环境中可能仍然有符合条件的变量)。这就决定了不同环境对变量的访问权问题,以及JS中变量的覆盖问题。
- 延长作用域链的方法:try-catch,with语句。
- JS没有块级作用域,var声明的变量属于最近的环境。
- 垃圾收集
- JS自动对内存进行管理,进行垃圾收集,不需要程序员过于操心。
- 垃圾收集机制按照周期启用,收集标记为待销毁的变量。
- 实际上,对于局部变量,会在退出该局部环境的时候自动销毁。
- 两种方式:标记清除、引用标记。
- 标记清除:对于不使用的变量做上标记,以便之后清除。
- 引用标记:有循环引用的问题。在BOM中仍然存在。
- 解除引用:为了避免循环引用,同时考虑到内存管理的问题。建议必要的时候,对无法自动标记的变量打上标记:variable = null;解除引用,以待垃圾收集。