把近期看高程这本书作的笔记摘录整理出来了,总归对原生javascript理论有了一个比较全面的的认识,此次把书中的一些知识要点摘录出来了,便于之后查阅的时候有方向,也更有效率!!javascript
第一章、javascript简介
- 010一、完整的javascript有三部分组成:核心ECMAScript,DOM和BOM
- 010二、ECMAScript规定了语言的下列组成部分:语法,类型,语句,关键字,保留字,操做符,对象
第二章、在html中使用javascript
- 020一、HTML4.01为script定义了下列6个属性:async:可选,表示当即下载脚本,不阻塞;charset:可选,指定字符集;defer:可选,延迟到文档彻底被解析和显示以后再执行;language:已废弃;src:可选,包含要执行代码的外部文件;type:可选,脚本语言的内容类型
- 020二、标签的位置:全部script元素都应该放在页面的<body>元素页面内容的后面
- 020三、IE8之后不支持defer属性
- 020四、async属性的目的是不让页面等待脚本下载和执行,从而异步加载页面其余内容
- 020五、<小于号在XHTML中会被看成开始一个新标签来解析
- 020六、noscript包含该元素的内容只有在如下状况才会显示出来:不支持脚本,支持脚本但被禁用
第三章、基本概念
- 030一、标识符,就是指变量、函数、属性的名字,或者函数的参数:第一个字符必须是一个字母、下划线( _ )或一个美圆符号( $ );
其余字符能够是字母、下划线、美圆符号或数字html
- 030二、严格模式下,ECMAScript 3 中的一些不肯定的行为将获得处理,并且对某些不安全的操做也会抛出错误。在函数内部的上方包含这条编译指示,也能够指定函数在严格模式下执行
- 030三、加上这个分号能够避免不少错误,加上分号也会在某些状况下增进代码的性能,由于这样解析器就没必要再花时间推测应该在哪里插入分号了
- 030四、用 var 操做符定义的变量将成为定义该变量的做用域中的局部变量。也就是说,若是在函数中使用 var 定义一个变量,那么这个变量在函数退出后就会被销毁。虽然省略 var 操做符能够定义全局变量,但这也不是咱们推荐的作法。给未经声明的变量赋值在严格模式下会致使抛出 ReferenceError 错误
- 030五、ECMAScript 中有 5 种简单数据类型(也称为基本数据类型):Undefined 、Null、Boolean 、Number和 String 。还有 1种复杂数据类型—— Object , Object 本质上是由一组无序的名值对组成的
- 030六、Safari 5 及以前版本、Chrome 7 及以前版本在对正则表达式调用 typeof 操做符时会返回 "function" ,而其余浏览器在这种状况下会返回"object"
- 030七、对未经声明的变量调用 delete 不会致使错误,但这样作没什么实际意义,并且在严格模式下确实会致使错误
- 030八、对未初始化和未声明的变量执行 typeof 操做符都返回了 undefined 值;这个结果有其逻辑上的合理性。由于虽然这两种变量从技术角度看有本质区别,但实际上不管对哪一种变量也不可能执行真正的操做
- 030九、若是定义的变量准备在未来用于保存对象,那么最好将该变量初始化为 null 而不是其余值。只要意在保存对象的变量尚未真正保存对象,就应该明确地让该变量保存null值。这样作不只能够体现 null 做为空对象指针的惯例,并且也有助于进一步区分null和undefined
- 03十、要将一个值转换为其对应的 Boolean 值,能够调用转型函数 Boolean()
- 03十一、八进制字面值的第一位必须是零(0),而后是八进制数字序列(0~7)。若是字面值中的数值超出了范围,那么前导零将被忽略,后面的数值将被看成十进制数值解析
- 03十二、十六进制字面值的前两位必须是 0x,后跟任何十六进制数字(0~9 及 A~F)。其中,字母 A~F能够大写,也能够小写
- 031三、保存浮点数值须要的内存空间是保存整数值的两倍,所以 ECMAScript会不失时机地将浮点数值转换为整数值
- 031四、在默认状况下,ECMASctipt 会将那些小数点后面带有 6 个零以上的浮点数值转换为以 e 表示法表示的数值(例如,0.0000003 会被转换成 3e-7)
- 031五、浮点数值的最高精度是 17 位小数,但在进行算术计算时其精确度远远不如整数。例如,0.1 加 0.2的结果不是 0.3,而是 0.30000000000000004。这个小小的舍入偏差会致使没法测试特定的浮点数值
- 031六、要想肯定一个数值是否是有穷的(换句话说,是否是位于最小和最大的数值之间),可使用 isFinite() 函数。这个函数在参数位于最小与最大数值之间时会返回 true
- 031七、NaN 与任何值都不相等,包括 NaN自己1八、 isNaN() 在接收到一个值以后,会尝试将这个值转换为数值。某些不是数值的值会直接转换为数值,例如字符串 "10" 或 Boolean 值。而任何不能被转换为数值的值都会致使这个函数返回true
- 031八、尽管有点儿难以想象,但 isNaN() 确实也适用于对象。在基于对象调用 isNaN()函数时,会首先调用对象的 valueOf() 方法,而后肯定该方法返回的值是否能够转换为数值。若是不能,则基于这个返回值再调用 toString() 方法,再测试返回值。而这个过程也是 ECMAScript中内置函数和操做符的通常执行流程
- 031九、因为 Number() 函数在转换字符串时比较复杂并且不够合理,所以在处理整数的时候更经常使用的是parseInt()函数。parseInt() 函数在转换字符串时,更多的是看其是否符合数值模式。它会忽略字符串前面的空格,直至找到第一个非空格字符。若是第一个字符不是数字字符或者负号, parseInt()就会返回 NaN ;也就是说,用 parseInt() 转换空字符串会返回 NaN ( Number() 对空字符返回 0)。若是第一个字符是数字字符, parseInt() 会继续解析第二个字符,直到解析完全部后续字符或者遇到了一个非数字字符。例如, "1234blue" 会被转换为 1234,由于 "blue" 会被彻底忽略。相似地, "22.5"会被转换为 22,由于小数点并非有效的数字字符。
- 0320、除了第一个小数点有效以外, parseFloat() 与 parseInt() 的第二个区别在于它始终都会忽略前导的零, parseFloat() 只解析十进制值
- 032一、ECMAScript 中的字符串是不可变的,也就是说,字符串一旦建立,它们的值就不能改变。要改变某个变量保存的字符串,首先要销毁原来的字符串,而后再用另外一个包含新值的字符串填充该变量
- 032二、Object 的每一个实例都具备下列属性和方法:constructor :保存着用于建立当前对象的函数。对于前面的例子而言,构造函数(constructor)就是 Object(); hasOwnProperty(propertyName) :用于检查给定的属性在当前对象实例中(而不是在实例的原型中)是否存在。其中,做为参数的属性名( propertyName )必须以字符串形式指定(例如: o.hasOwnProperty("name") );isPrototypeOf(object) :用于检查传入的对象是不是传入对象的原型;propertyIsEnumerable(propertyName) :用于检查给定的属性是否可以使用 for-in 语句(本章后面将会讨论)来枚举。与 hasOwnProperty() 方法同样,做为参数的属性名必须以字符串形式指定;toLocaleString() :返回对象的字符串表示,该字符串与执行环境的地区对应;toString() :返回对象的字符串表示;valueOf() :返回对象的字符串、数值或布尔值表示。一般与 toString() 方法的返回值相同
- 032三、在应用于对象时,相应的操做符一般都会调用对象的 valueOf()和(或) toString() 方法,以便取得能够操做的值
- 032四、使用 while 循环作不到的,使用 for 循环一样也作不到。也就是说, for 循环只是把与循环有关的代码集中在了一个位置
- 032五、Safari 3 之前版本的 for-in 语句中存在一个 bug,该 bug 会致使某些属性被返回两次。
- 032六、break 和 continue 语句用于在循环中精确地控制代码的执行。其中, break 语句会当即退出循环,强制继续执行循环后面的语句。而 continue 语句虽然也是当即退出循环,但退出循环后会从循环的顶部继续执行
- 032七、with 语句的做用是将代码的做用域设置到一个特定的对象中。严格模式下不容许使用 with 语句,不然将视为语法错误。因为大量使用 with 语句会致使性能降低,同时也会给调试代码形成困难,所以在开发大型应用程序时,不建议使用 with 语句
with(location){
var qs = search.substring(1);
var hostName = hostname;
var url = href;
}
- 032八、经过为每一个 case 后面都添加一个 break 语句,就能够避免同时执行多个 case代码的状况。假如确实须要混合几种情形,不要忘了在代码中添加注释,说明你是有意省略了 break 关键字。虽然 ECMAScript 中的 switch 语句借鉴自其余语言,但这个语句也有本身的特点。首先,能够在switch 语句中使用任何数据类型(在不少其余语言中只能使用数值),不管是字符串,仍是对象都没有问题。其次,每一个 case 的值不必定是常量,能够是变量,甚至是表达式
switch (i) {
case 25:
/* 合并两种情形 */
case 35:
alert("25 or 35");
break;
case 45:
alert("45");
break;
default:
alert("Other");
}
- 032九、switch 语句在比较值时使用的是全等操做符,所以不会发生类型转换(例如,字符串 "10" 不等于数值 10)
- 0330、函数会在执行完 return 语句以后中止并当即退出。所以,位于 return 语句以后的任何代码都永远不会执行
- 033一、 return 语句也能够不带有任何返回值。在这种状况下,函数在中止执行后将返回 undefined值。这种用法通常用在须要提早中止函数执行而又不须要返回值的状况下
- 033二、严格模式对函数有一些限制:不能把函数命名为 eval 或 arguments ;不能把参数命名为 eval 或 arguments ; 不能出现两个命名参数同名的状况。若是发生以上状况,就会致使语法错误,代码没法执行
- 033三、函数体内能够经过 arguments 对象来访问这个参数数组,从而获取传递给函数的每个参数。 arguments 对象只是与数组相似(它并非 Array 的实例),由于可使用方括号语法访问它的每个元素(即第一个元素是 arguments[0] ,第二个元素是 argumetns[1] ,以此类推),使用 length 属性来肯定传递进来多少个参数
- 033四、没有传递值的命名参数将自动被赋予 undefined 值
- 033五、严格模式对如何使用 arguments 对象作出了一些限制。把 arguments[1] 设置为 10 , num2 的值仍然仍是 undefined 。其次,重写arguments 的值会致使语法错误(代码将不会执行)
- 033六、ECMAScript 中的全部参数传递的都是值,不可能经过引用传递参数
- 033七、经过检查传入函数中参数的类型和数量并做出不一样的反应,能够模仿方法的重载
- 033八、 ECMAScript 中的基本数据类型包括 Undefined 、 Null 、 Boolean 、 Number 和 String
- 033九、与其余语言不一样,ECMScript 没有为整数和浮点数值分别定义不一样的数据类型, Number 类型可用于表示全部数值
- 0340、ECMAScript 中也有一种复杂的数据类型,即 Object 类型,该类型是这门语言中全部对象的基础类型
- 034一、未指定返回值的函数返回的是一个特殊的 undefined 值
- 034二、 能够向 ECMAScript 函数传递任意数量的参数,而且能够经过 arguments 对象来访问这些参数
- 034三、当复制保存着对象的某个变量时,操做的是对象的引用。但在为对象添加属性时,操做的是实际的对象
第四章、变量、做用域和内存问题
- 040一、 typeof 操做符是肯定一个变量是字符串、数值、布尔值,仍是 undefined 的最佳工具
- 040二、一般,咱们并非想知道某个值是对象,而是想知道它是什么类型的对象。为此,ECMAScript提供了 instanceof 操做符
- 040三、函数参数也被看成变量来对待,所以其访问规则与执行环境中的其余变量相同
- 040四、在catch 语句中捕获的错误对象会被添加到执行环境的变量对象,而不是 catch 语句的变量对象中。换句话说,即便是在 catch 块的外部也能够访问到错误对象
- 040五、变量查询也不是没有代价的。很明显,访问局部变量要比访问全局变量更快,由于不用向上搜索做用域链。JavaScript 引擎在优化标识符查询方面作得不错,所以这个差异在未来恐怕就能够忽略不计了
- 040六、一旦数据再也不有用,最好经过将其值设置为 null 来释放其引用——这个作法叫作解除引用(dereferencing)
- 040七、基本类型值在内存中占据固定大小的空间,所以被保存在栈内存中
- 040八、 从一个变量向另外一个变量复制基本类型的值,会建立这个值的一个副本
- 040九、引用类型的值是对象,保存在堆内存中
- 04十、包含引用类型值的变量实际上包含的并非对象自己,而是一个指向该对象的指针
- 04十一、从一个变量向另外一个变量复制引用类型的值,复制的实际上是指针,所以两个变量最终都指向同一个对象
- 04十二、肯定一个值是哪一种基本类型可使用 typeof 操做符,而肯定一个值是哪一种引用类型可使用instanceof 操做符
- 041三、 “标记清除”是目前主流的垃圾收集算法,这种算法的思想是给当前不使用的值加上标记,而后再回收其内存
- 041四、解除变量的引用不只有助于消除循环引用现象,并且对垃圾收集也有好处。为了确保有效地回收内存,应该及时解除再也不使用的全局对象、全局对象属性以及循环引用变量的引用
- 041五、除非必须使用变量来访问属性,不然咱们建议使用点表示法
第五章、引用类型
- 050一、与对象同样,在使用数组字面量表示法时,也不会调用 Array 构造函数(Firefox 3及更早版本除外)
- 050二、数组最多能够包含 4 294 967 295 个项,这几乎已经可以知足任何编程需求了。若是想添加的项数超过这个上限值,就会发生异常。而建立一个初始大小与这个上限值接近的数组,则可能会致使运行时间超长的脚本错误
- 050三、全部对象都具备 toLocaleString() 、 toString() 和 valueOf() 方法。其中,调用数组的 toString() 方法会返回由数组中每一个值的字符串形式拼接而成的一个以逗号分隔的字符串。而调用 valueOf() 返回的仍是数组。实际上,为了建立这个字符串会调用数组每一项的 toString() 方法
- 050四、 toLocaleString() 方法常常也会返回与 toString() 和 valueOf() 方法相同的值,但也不老是如此
- 050五、若是数组中的某一项的值是 null 或者 undefined ,那么该值在 join() 、toLocaleString() 、 toString() 和 valueOf() 方法返回的结果中以空字符串表示
- 050六、push() 方法能够接收任意数量的参数,把它们逐个添加到数组末尾,并返回修改后数组的长度。而pop() 方法则从数组末尾移除最后一项,减小数组的 length 值,而后返回移除的项
- 050七、栈数据结构的访问规则是 LIFO(后进先出),而队列数据结构的访问规则是 FIFO(First-In-First-Out,先进先出)
- 050八、结合使用 shift() 和 push() 方法,能够像使用队列同样使用数组
- 050九、同时使用 unshift() 和 pop() 方法,能够从相反的方向来模拟队列,即在数组的前端添加项,从数组末端移除项
- 05十、alert([0, 1, 5, 10, 15].sort());//0,1,10,15,5。可见,即便例子中值的顺序没有问题,但 sort() 方法也会根据测试字符串的结果改变原来的顺序。由于数值 5 虽然小于 10,但在进行字符串比较时, "10" 则位于 "5" 的前面,因而数组的顺序就被修改了。不用说,这种排序方式在不少状况下都不是最佳方案。比较函数接收两个参数,若是第一个参数应该位于第二个以前则返回一个负数,若是两个参数相等则返回 0,若是第一个参数应该位于第二个以后则返回一个正数
- 05十一、因为比较函数经过返回一个小于零、等于零或大于零的值来影响排序结果,所以减法操做就能够适当地处理全部这些状况
- 05十二、 concat() 方法会先建立当前数组一个副本,而后将接收到的参数添加到这个副本的末尾,最后返回新构建的数组。在没有给 concat() 方法传递参数的状况下,它只是复制当前数组并返回副本。若是传递给 concat() 方法的是一或多个数组,则该方法会将这些数组中的每一项都添加到结果数组中。若是传递的值不是数组,这些值就会被简单地添加到结果数组的末尾
- 051三、slice() 方法能够接受一或两个参数,即要返回项的起始和结束位置。在只有一个参数的状况下, slice() 方法返回从该参数指定位置开始到当前数组末尾的全部项。若是有两个参数,该方法返回起始和结束位置之间的项——但不包括结束位置的项。注意, slice() 方法不会影响原始数组
- 051四、若是 slice() 方法的参数中有一个负数,则用数组长度加上该数来肯定相应的位置。例如,在一个包含5项的数组上调用 slice(-2,-1) 与调用 slice(3,4) 获得的结果相同。若是结束位置小于起始位置,则返回空数组
- 051五、splice() 方法能够删除任意数量的项,只需指定2个参数:要删除的第一项的位置和要删除的项数;能够向指定位置插入任意数量的项,只需提供 3 个参数:起始位置、0(要删除的项数)和要插入的项。若是要插入多个项,能够再传入第4、第五,以致任意多个项;能够向指定位置插入任意数量的项,且同时删除任意数量的项,只需指定3个参数:起始位置、要删除的项数和要插入的任意数量的项。插入的项数没必要与删除的项数相等
- 051六、splice() 方法始终都会返回一个数组,该数组中包含从原始数组中删除的项(若是没有删除任何项,则返回一个空数组)
- 051七、 indexOf() 和 lastIndexOf()。这两个方法都接收两个参数:要查找的项和(可选的)表示查找起点位置的索引。其中, indexOf() 方法从数组的开头(位置0)开始向后查找,lastIndexOf()方法则从数组的末尾开始向前查找。这两个方法都返回要查找的项在数组中的位置,或者在没找到的状况下返回-1。支持它们的浏览器包括 IE9+、Firefox 2+、Safari3+、Opera 9.5+和 Chrome
- 051八、ECMAScript 5 为数组定义了5个迭代方法,这些方法中的函数会接收三个参数:数组项的值、该项在数组中的位置和数组对象自己。every() :对数组中的每一项运行给定函数,若是该函数对每一项都返回true,则返回true;filter():对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组;forEach():对数组中的每一项运行给定函数。这个方法没有返回值;map() :对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组;some():对数组中的每一项运行给定函数,若是该函数对任一项返回 true ,则返回 true。以上方法都不会修改数组中的包含的值
- 051九、这些数组方法经过执行不一样的操做,能够大大方便处理数组的任务。支持这些迭代方法的浏览器有IE9+、Firefox2+、Safari 3+、Opera 9.5+和 Chrome
- 0520、 reduce() 和 reduceRight()。这两个方法都会迭代数组的全部项,而后构建一个最终返回的值。这两个方法都接收两个参数:一个在每一项上调用的函数和(可选的)做为归并基础的初始值。传给reduce()和reduceRight()的函数接收4个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会做为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,所以第一个参数是数组的第一项,第二个参数就是数组的第二项。使用reduce()方法能够执行求数组中全部值之和的操做
- 052一、使用 reduce() 仍是 reduceRight() ,主要取决于要从哪头开始遍历数组。除此以外,它们彻底相同
- 052二、在调用 Date 构造函数而不传递参数的状况下,新建立的对象自动得到当前日期和时间
- 052三、 Date.parse() 方法接收一个表示日期的字符串参数,而后尝试根据这个字符串返回相应日期的毫秒数。ECMA-262没有定义Date.parse() 应该支持哪一种日期格式,所以这个方法的行为因实现而异,并且一般是因地区而异
- 052四、若是传入 Date.parse()方法的字符串不能表示日期,那么它会返回NaN。实际上,若是直接将表示日期的字符串传递给 Date 构造函数,也会在后台调用 Date.parse() 。换句话说,下面的代码与前面的例子是等价的:var someDate = new Date("May 25, 2004");
- 052五、Date.UTC() 方法一样也返回表示日期的毫秒数,但它与Date.parse()在构建值时使用不一样的信息。Date.UTC()的参数分别是年份、基于 0 的月份(一月是0,二月是1,以此类推)、月中的哪一天(1到31)、小时数(0到23)、分钟、秒以及毫秒数。在这些参数中,只有前两个参数(年和月)是必需的。若是没有提供月中的天数,则假设天数为1;若是省略其余参数,则通通假设为 0。
- 052六、ECMAScript 5 添加了 Data.now() 方法,返回表示调用这个方法时的日期和时间的毫秒数
- 052七、支持 Data.now() 方法的浏览器包括IE9+、Firefox3+、Safari3+、Opera10.5和Chrome。在不支持它的浏览器中,使用+操做符把 Data 对象转换成字符串,也能够达到一样的目的
- 052八、正则表达式。字面量声明和构造函数声明的区别,字面量始终会共享一个RegExp实例,而使用构造函数建立的每个新RegExp实例都是一个新实例
- 052九、RegExp 对象的主要方法是 exec() ,该方法是专门为捕获组而设计的。 exec() 接受一个参数,即要应用模式的字符串,而后返回包含第一个匹配项信息的数组;或者在没有匹配项的状况下返回 null 。返回的数组虽然是 Array 的实例,但包含两个额外的属性: index 和 input 。其中, index 表示匹配项在字符串中的位置,而 input 表示应用正则表达式的字符串。在数组中,第一项是与整个模式匹配的字符串,其余项是与模式中的捕获组匹配的字符串(若是模式中没有捕获组,则该数组只包含一项)
- 0530、正则表达式的第二个方法是 test() ,它接受一个字符串参数。在模式与该参数匹配的状况下返回true ;不然,返回 false 。在只想知道目标字符串与某个模式是否匹配,但不须要知道其文本内容的状况下,使用这个方法很是方便
- 053一、正则表达式的 valueOf() 方法返回正则表达式自己。
- 053二、即便 test() 方法只返回一个布尔值,但RegExp 构造函数的属性$1和$2也会被匹配相应捕获组的字符串自动填充
- 053三、每一个函数都是Function类型的实例,并且都与其余引用类型同样具备属性和方法。因为函数是对象,所以函数名实际上也是一个指向函数对象的指针,不会与某个函数绑定
- 053四、Function构造函数能够接收任意数量的参数,但最后一个参数始终都被当作是函数体,而前面的参数则枚举出了新函数的参数。可是,咱们不推荐读者使用这种方法定义函数,由于这种语法会致使解析两次代码(第一次是解析常规 ECMAScript代码,第二次是解析传入构造函数中的字符串),从而影响性能
- 053五、函数声明式与函数表达式的区别。解析器在向执行环境中加载数据时,对函数声明和函数表达式并不是一视同仁。解析器会率先读取函数声明,并使其在执行任何代码以前可用(能够访问);至于函数表达式,则必须等到解析器执行到它所在的代码行,才会真正被解释执行
- 053六、由于 ECMAScript中的函数名自己就是变量,因此函数也能够做为值来使用。也就是说,不只能够像传递参数同样把一个函数传递给另外一个函数,并且能够将一个函数做为另外一个函数的结果返回
- 053七、arguments是一个类数组对象,包含着传入函数中的全部参数。虽然 arguments 的主要用途是保存函数参数,但这个对象还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数
- 053八、this引用的是函数据以执行的环境对象——或者也能够说是this值(当在网页的全局做用域中调用函数时,this对象引用的就是window)
- 053九、函数的名字仅仅是一个包含指针的变量而已。所以,即便是在不一样的环境中执行,全局的 sayColor() 函数与 o.sayColor() 指向的仍然是同一个函数
- 0540、ECMAScript5也规范化了另外一个函数对象的属性: caller 。除了Opera的早期版本不支持,其余浏览器都支持这个 ECMAScript3并无定义的属性。这个属性中保存着调用当前函数的函数的引用,若是是在全局做用域中调用当前函数,它的值为null。为了实现更松散的耦合,也能够经过 arguments.callee.caller来访问相同的信息
- 054一、IE、Firefox、Chrome和Safari的全部版本以及 Opera 9.6 都支持 caller 属性
- 054二、当函数在严格模式下运行时,访问arguments.callee 会致使错误。ECMAScript5还定义了arguments.caller 属性,但在严格模式下访问它也会致使错误,而在非严格模式下这个属性始终是undefined。定义这个属性是为了分清 arguments.caller和函数的caller属性。以上变化都是为了增强这门语言的安全性,这样第三方代码就不能在相同的环境里窥视其余代码了
- 054三、ECMAScript中的函数是对象,所以函数也有属性和方法。每一个函数都包含两个属性: length和prototype 。其中,length属性表示函数但愿接收的命名参数的个数
- 054四、在ECMAScript5中,prototype属性是不可枚举的,所以使用 for-in 没法发现
- 054五、每一个函数都包含两个非继承而来的方法:apply() 和 call() 。这两个方法的用途都是在特定的做用域中调用函数,实际上等于设置函数体内this对象的值。首先, apply() 方法接收两个参数:一个是在其中运行函数的做用域,另外一个是参数数组。其中,第二个参数能够是Array 的实例,也能够是arguments 对象
- 054六、在严格模式下,未指定环境对象而调用函数,则 this 值不会转型为 window 。除非明确把函数添加到某个对象或者调用 apply() 或 call() ,不然 this 值将是undefined
- 054七、call()方法与apply()方法的做用相同,它们的区别仅在于接收参数的方式不一样。对于call()方法而言,第一个参数是 this值没有变化,变化的是其他参数都直接传递给函数。换句话说,在使用call()方法时,传递给函数的参数必须逐个列举出来
- 054八、事实上,传递参数并不是 apply() 和 call() 真正的用武之地;它们真正强大的地方是可以扩充函数赖以运行的做用域
- 054九、使用 call()(或apply())来扩充做用域的最大好处,就是对象不须要与方法有任何耦合关系
- 0550、ECMAScript 5 还定义了一个方法: bind() 。这个方法会建立一个函数的实例,其 this 值会被绑定到传给 bind() 函数的值。支持 bind() 方法的浏览器有 IE9+、Firefox 4+、Safari 5.1+、Opera 12+和 Chrome
- 055一、为了便于操做基本类型值,ECMAScript还提供了 3 个特殊的引用类型:Boolean、Number和String。这些类型与本章介绍的其余引用类型类似,但同时也具备与各自的基本类型相应的特殊行为。实际上,每当读取一个基本类型值的时候,后台就会建立一个对应的基本包装类型的对象,从而让咱们可以调用一些方法来操做这些数据
- 055二、引用类型与基本包装类型的主要区别就是对象的生存期。使用 new操做符建立的引用类型的实例,在执行流离开当前做用域以前都一直保存在内存中。而自动建立的基本包装类型的对象,则只存在于一行代码的执行瞬间,而后当即被销毁。这意味着咱们不能在运行时为基本类型值添加属性和方法
- 055三、Object构造函数也会像工厂方法同样,根据传入值的类型返回相应基本包装类型的实例。var obj = new Object("some text"); alert(obj instanceof String); //true
- 055四、使用new调用基本包装类型的构造函数,与直接调用同名的转型函数是不同的
- 055五、 toFixed()方法会按照指定的小数位返回数值的字符串表示。若是数值自己包含的小数位比指定的还多,那么接近指定的最大小数位的值就会舍入。能够利用round配合toFixed加爵该方法的在ie浏览器上的兼容问题
- 055六、对于一个数值来讲,toPrecision()方法可能会返回固定大小(fixed)格式,也可能返回指数(exponential)格式;具体规则是看哪一种格式最合适。这个方法接收一个参数,即表示数值的全部数字的位数(不包括指数部分)。实际上,toPrecision()会根据要处理的数值决定究竟是调用 toFixed() 仍是调用 toExponential()
- 055七、在使用typeof操做符测试基本类型数值时,始终会返回 "number" ,而在测试 Number 对象时,则会返回 "object" 。相似地,Number对象是Number类型的实例,而基本类型的数值则不是
- 055八、两个用于访问字符串中特定字符的方法是:charAt() 和 charCodeAt()。这两个方法都接收一个参数,即基于 0 的字符位置。其中,charAt()方法以单字符字符串的形式返回给定位置的那个字符(ECMAScript中没有字符类型)
- 055九、ECMAScript5还定义了另外一个访问个别字符的方法。在支持此方法的浏览器中,可使用方括号加数字索引来访问字符串中的特定字符。使用方括号表示法访问个别字符的语法获得了 IE8 及 Firefox、Safari、Chrome 和 Opera 全部版本的支持。若是是在IE7及更早版本中使用这种语法,会返回undefined值(尽管根本不是特殊的undefined 值)
- 0560、ECMAScript还提供了三个基于子字符串建立新字符串的方法: slice() 、 substr() 和 substring() 。这三个方法都会返回被操做字符串的一个子字符串,并且也都接受一或两个参数。第一个参数指定子字符串的开始位置,第二个参数(在指定的状况下)表示子字符串到哪里结束。具体来讲, slice() 和substring() 的第二个参数指定的是子字符串最后一个字符后面的位置。而 substr() 的第二个参数指定的则是返回的字符个数。若是没有给这些方法传递第二个参数,则将字符串的长度做为结束位置。与concat() 方法同样, slice() 、 substr() 和 substring() 也不会修改字符串自己的值——它们只是返回一个基本类型的字符串值,对原始字符串没有任何影响。在传递给这些方法的参数是负值的状况下,它们的行为就不尽相同了。其中, slice() 方法会将传入的负值与字符串的长度相加, substr() 方法将负的第一个参数加上字符串的长度,而将负的第二个参数转换为 0。最后, substring() 方法会把全部负值参数都转换为 0
- 056一、IE 的 JavaScript 实如今处理向 substr() 方法传递负值的状况时存在问题,它会返回原始的字符串。IE9 修复了这个问题
- 056二、有两个能够从字符串中查找子字符串的方法: indexOf() 和 lastIndexOf() 。这两个方法都是从一个字符串中搜索给定的子字符串,而后返子字符串的位置(若是没有找到该子字符串,则返回 -1 )。这两个方法的区别在于: indexOf() 方法从字符串的开头向后搜索子字符串,而 lastIndexOf() 方法是从字符串的末尾向前搜索子字符串。这两个方法均可以接收可选的第二个参数,表示从字符串中的哪一个位置开始搜索
- 056三、ECMAScript 5 为全部字符串定义了 trim() 方法。这个方法会建立一个字符串的副本,删除前置及后缀的全部空格,而后返回结果。因为 trim() 返回的是字符串的副本,因此原始字符串中的前置及后缀空格会保持不变。支持这个方法的浏览器有 IE9+、Firefox 3.5+、Safari 5+、Opera 10.5+和 Chrome。此外,Firefox 3.5+、Safari 5+和 Chrome 8+还支持非标准的 trimLeft() 和 trimRight() 方法,分别用于删除字符串开头和末尾的空格
- 056四、接下来咱们要介绍的是一组与大小写转换有关的方法。ECMAScript中涉及字符串大小写转换的方法有 4 个:toLowerCase()、toLocaleLowerCase()、toUpperCase()和 toLocaleUpperCase() 。其中, toLowerCase() 和 toUpperCase() 是两个经典的方法,借鉴自 java.lang.String 中的同名方法。而 toLocaleLowerCase() 和 toLocaleUpperCase() 方法则是针对特定地区的实现。通常来讲,在不知道本身的代码将在哪一种语言环境中运行的状况下,仍是使用针对地区的方法更稳妥一些
- 056五、String 类型定义了几个用于在字符串中匹配模式的方法。第一个方法就是 match() ,在字符串上调用这个方法,本质上与调用 RegExp 的 exec() 方法相同。 match() 方法只接受一个参数,要么是一个正则表达式,要么是一个 RegExp 对象
- 056六、另外一个用于查找模式的方法是 search() 。这个方法的惟一参数与 match() 方法的参数相同:由字符串或 RegExp 对象指定的一个正则表达式。 search() 方法返回字符串中第一个匹配项的索引;若是没有找到匹配项,则返回 -1 。并且, search() 方法始终是从字符串开头向后查找模式
- 056七、ECMAScript 提供了 replace() 方法。这个方法接受两个参数:第一个参数能够是一个 RegExp 对象或者一个字符串(这个字符串不会被转换成正则表达式),第二个参数能够是一个字符串或者一个函数。若是第一个参数是字符串,那么只会替换第一个子字符串。要想替换全部子字符串,惟一的办法就是提供一个正则表达式,并且要指定全局( g )标志
- 056八、replace() 方法的第二个参数也能够是一个函数。在只有一个匹配项(即与模式匹配的字符串)的状况下,会向这个函数传递 3 个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。在正则表达式中定义了多个捕获组的状况下,传递给函数的参数依次是模式的匹配项、第一个捕获组的匹配项、第二个捕获组的匹配项……,但最后两个参数仍然分别是模式的匹配项在字符串中的位置和原始字符串。这个函数应该返回一个字符串,表示应该被替换的匹配项使用函数做为 replace() 方法的第二个参数能够实现更加精细的替换操做
- 056九、最后一个与模式匹配有关的方法是 split() ,这个方法能够基于指定的分隔符将一个字符串分割成多个子字符串,并将结果放在一个数组中。分隔符能够是字符串,也能够是一个 RegExp 对象(这个方法不会将字符串当作正则表达式)。 split() 方法能够接受可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会超过既定大小。对 split() 中正则表达式的支持因浏览器而异。尽管对于简单的模式没有什么差异,但对于未发现匹配项以及带有捕获组的模式,匹配的行为就不大相同了
- 0570、与操做字符串有关的最后一个方法是 localeCompare() ,这个方法比较两个字符串,并返回下列值中的一个: 若是字符串在字母表中应该排在字符串参数以前,则返回一个负数(大多数状况下是 -1 ,具体的值要视实现而定); 若是字符串等于字符串参数,则返回 0 ;若是字符串在字母表中应该排在字符串参数以后,则返回一个正数(大多数状况下是 1 ,具体的值一样要视实现而定)。localeCompare() 方法比较不同凡响的地方,就是实现所支持的地区(国家和语言)决定了这个方法的行为
- 057一、另外, String 构造函数自己还有一个静态方法: fromCharCode() 。这个方法的任务是接收一或多个字符编码,而后将它们转换成一个字符串。从本质上来看,这个方法与实例方法 charCodeAt()执行的是相反的操做
- 057二、 encodeURI() 主要用于整个 URI(例如,http://www.wrox.com/illegal value.htm),而 encode-URIComponent() 主要用于对 URI 中的某一段(例如前面 URI 中的 illegal value.htm )进行编码。它们的主要区别在于, encodeURI() 不会对自己属于 URI 的特殊字符进行编码,例如冒号、正斜杠、问号和井字号;而 encodeURIComponent() 则会对它发现的任何非标准字符进行编码
- 057三、一 般 来 说 , 我 们 使 用 encodeURIComponent() 方 法 的 时 候 要 比 使 用encodeURI() 更多,由于在实践中更常见的是对查询字符串参数而不是对基础 URI进行编码。
- 057四、与 encodeURI() 和 encodeURIComponent() 方法对应的两个方法分别是 decodeURI() 和decodeURIComponent()
- 057五、如今,咱们介绍最后一个——大概也是整个 ECMAScript语言中最强大的一个方法: eval() 。 eval()方法就像是一个完整的 ECMAScript 解析器,它只接受一个参数,即要执行的 ECMAScript (或 JavaScript)字符串
- 057六、可以解释代码字符串的能力很是强大,但也很是危险。所以在使用 eval() 时必须极为谨慎,特别是在用它执行用户输入数据的状况下。不然,可能会有恶意用户输入威胁你的站点或应用程序安全的代码(即所谓的代码注入)
- 057七、其中, min() 和 max() 方法用于肯定一组数值中的最小值和最大值。这两个方法均可以接收任意多个数值参数
- 057八、要找到数组中的最大或最小值,能够像下面这样使用 apply() 方法。Math.max.apply(Math,[1,2,4,65,8,4)//65
- 057九、下面来介绍将小数值舍入为整数的几个方法: Math.ceil() 、 Math.floor() 和 Math.round()
- 0580、Math.random() 方法返回大于等于 0 小于 1 的一个随机数
- 058一、 引用类型与传统面向对象程序设计中的类类似,但实现不一样
- 058二、Object 是一个基础类型,其余全部类型都从 Object 继承了基本的行为
- 058三、Array 类型是一组值的有序列表,同时还提供了操做和转换这些值的功能
- 058四、Date 类型提供了有关日期和时间的信息,包括当前日期和时间以及相关的计算功能
- 058五、RegExp 类型是 ECMAScript 支持正则表达式的一个接口,提供了最基本的和一些高级的正则表达式功能
- 058六、函数其实是 Function 类型的实例,所以函数也是对象;而这一点正是 JavaScript 最有特点的地方。因为函数是对象,因此函数也拥有方法,能够用来加强其行为
- 058七、由于有了基本包装类型,因此 JavaScript 中的基本类型值能够被看成对象来访问。三种基本包装类型分别是: Boolean 、 Number 和 String 。如下是它们共同的特征
- 058八、在全部代码执行以前,做用域中就已经存在两个内置对象: Global 和 Math 。在大多数 ECMAScript实现中都不能直接访问 Global 对象;不过,Web 浏览器实现了承担该角色的 window 对象。全局变量和函数都是 Global 对象的属性。 Math 对象提供了不少属性和方法,用于辅助完成复杂的数学计算任务
第六章、面向对象的程序设计
- 060一、ECMAScript中有两种属性:数据属性和访问器属性。数据属性包含一个数据值的位置。在这个位置能够读取和写入值。数据属性有4个描述其行为的特性。对于像前面例子中那样直接在对象上定义的属性,它们的[[Configurable]] 、[[Enumerable]]和[[Writable]]特性都被设置为 true ,而[[Value]]特性被设置为指定的值。要修改属性默认的特性,必须使用ECMAScript5的Object.defineProperty()方法。这个方法接收三个参数:属性所在的对象、属性的名字和一个描述符对象。其中,描述符(descriptor)对象的属性必须是:configurable、enumerable 、 writable和value。设置其中的一或多个值,能够修改对应的特性值。能够屡次调用Object.defineProperty() 方法修改同一个属性,但在把configurable特性设置为 false 以后就会有限制了。在调用Object.defineProperty() 方法时,若是不指定,configurable、enumerable 和writable特性的默认值都是false。多数状况下,可能都没有必要利用Object.defineProperty()方法提供的这些高级功能
- 060二、访问器属性不包含数据值;它们包含一对儿getter 和 setter函数(不过,这两个函数都不是必需的)。在读取访问器属性时,会调用getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。访问器属性有以下 4 个特性:[[Configurable]]、[[Enumerable]]、[[Get]]、[[Set]]
- 060三、在不支持Object.defineProperty()方法的浏览器中不能修改[[Configurable]]和[[Enumerable]]
- 060四、支持 Object.defineProperties()方法的浏览器有 IE9+、Firefox 4+、Safari 5+、Opera 12+和Chrome
- 060五、在 JavaScript 中,能够针对任何对象——包括 DOM 和 BOM 对象,使用 Object.getOwnProperty-Descriptor() 方法。支持这个方法的浏览器有 IE9+、Firefox 4+、Safari 5+、Opera 12+和 Chrome
- 060六、工厂模式是软件工程领域一种广为人知的设计模式,这种模式抽象了建立具体对象的过程。工厂模式虽然解决了建立多个类似对象的问题,但却没有解决对象识别的问题(即怎样知道一个对象的类型)
- 060七、构造器模式。没有显式地建立对象;直接将属性和方法赋给了 this 对象;没有 return 语句。以这种方式调用构造函数实际上会经历如下 4个步骤:建立一个新对象; 将构造函数的做用域赋给新对象(所以 this 就指向了这个新对象);执行构造函数中的代码(为这个新对象添加属性);返回新对象。以这种方式定义的构造函数是定义在 Global 对象(在浏览器中是 window 对象)中的。使用构造函数的主要问题,就是每一个方法都要在每一个实例上从新建立一遍。在前面的例子中, person1 和 person2 都有一个名为 sayName() 的方法,但那两个方法不是同一个 Function 的实例
- 060八、 prototype 就是经过调用构造函数而建立的那个对象实例的原型对象咱们建立的每一个函数都有一个 prototype (原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含能够由特定类型的全部实例共享的属性和方法。使用原型对象的好处是可让全部对象实例共享它所包含的属性和方法。换句话说,没必要在构造函数中定义对象实例的信息,而是能够将这些信息直接添加到原型对象中
- 060九、不管何时,只要建立了一个新函数,就会根据一组特定的规则为该函数建立一个 prototype属性,这个属性指向函数的原型对象。在默认状况下,全部原型对象都会自动得到一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针
- 06十、使用 Object.getPrototypeOf()能够方便地取得一个对象的原型,而这在利用原型实现继承(本章稍后会讨论)的状况下是很是重要的。支持这个方法的浏览器有 IE9+、Firefox 3.5+、Safari 5+、Opera 12+和 Chrome
- 06十一、使用 delete 操做符则能够彻底删除实例属性,从而让咱们可以从新访问原型中的属性
- 06十二、使用 hasOwnProperty() 方法能够检测一个属性是存在于实例中,仍是存在于原型中。这个方法(不要忘了它是从 Object 继承来的)只在给定属性存在于对象实例中时,才会返回 true
- 061三、ECMAScript 5 的 Object.getOwnPropertyDescriptor() 方法只能用于实例属性,要取得原型属性的描述符,必须直接在原型对象上调用 Object.getOwnProperty-Descriptor() 方法
- 061四、有两种方式使用 in 操做符:单独使用和在 for-in 循环中使用。在单独使用时, in 操做符会在经过对象可以访问给定属性时返回true,不管该属性存在于实例中仍是原型中
- 061五、因为 in 操做符只要经过对象可以访问到属性就返回 true , hasOwnProperty() 只在属性存在于实例中时才返回 true ,所以只要 in 操做符返回 true 而 hasOwnProperty() 返回 false ,就能够肯定属性是原型中的属性
- 061六、要取得对象上全部可枚举的实例属性,可使用 ECMAScript 5 的 Object.keys() 方法。这个方法接收一个对象做为参数,返回一个包含全部可枚举属性的字符串数组
- 061七、若是你想要获得全部实例属性,不管它是否可枚举,均可以使用 Object.getOwnPropertyNames()方法。 Object.keys() 和 Object.getOwnProperty-Names() 方法均可以用来替代 for-in 循环。支持这两个方法的浏览器有 IE9+、Firefox 4+、Safari 5+、Opera12+和 Chrome
- 061八、实例与原型之间的链接只不过是一个指针,而非一个副本,所以就能够在原型中找到新的 sayHi 属性并返回保存在那里的函数
- 061九、原型模式也不是没有缺点。首先,它省略了为构造函数传递初始化参数这一环节,结果全部实例在默认状况下都将取得相同的属性值。虽然这会在某种程度上带来一些不方便,但还不是原型的最大问题。原型模式的最大问题是由其共享的本性所致使的
- 0620、混合模式。建立自定义类型的最多见方式,就是组合使用构造函数模式与原型模式。构造函数模式用于定义实例属性,而原型模式用于定义方法和共享的属性。结果,每一个实例都会有本身的一份实例属性的副本,但同时又共享着对方法的引用,最大限度地节省了内存。另外,这种混成模式还支持向构造函数传递参数;可谓是集两种模式之长。这种构造函数与原型混成的模式,是目前在 ECMAScript中使用最普遍、认同度最高的一种建立自定义类型的方法。能够说,这是用来定义引用类型的一种默认模式
- 062一、使用动态原型模式时,不能使用对象字面量重写原型。前面已经解释过了,若是在已经建立了实例的状况下重写原型,那么就会切断现有实例与新原型之间的联系
- 062二、关于寄生构造函数模式,有一点须要说明:首先,返回的对象与构造函数或者与构造函数的原型属性之间没有关系;也就是说,构造函数返回的对象与在构造函数外部建立的对象没有什么不一样。为此,不能依赖 instanceof 操做符来肯定对象类型。因为存在上述问题,咱们建议在可使用其余模式的状况下,不要使用这种模式
- 062三、继承是 OO 语言中的一个最为人津津乐道的概念。许多 OO 语言都支持两种继承方式:接口继承和实现继承。接口继承只继承方法签名,而实现继承则继承实际的方法。如前所述,因为函数没有签名,在 ECMAScript 中没法实现接口继承。ECMAScript 只支持实现继承,并且其实现继承主要是依靠原型链来实现的
- 062四、构造函数、原型和实例的关系。每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针
- 062五、谨慎地定义方法。子类型有时候须要重写超类型中的某个方法,或者须要添加超类型中不存在的某个方法。但无论怎样,给原型添加方法的代码必定要放在替换原型的语句以后
- 062六、经过原型链实现继承时,不能使用对象字面量建立原型方法。由于这样作就会重写原型链
- 062七、在解决原型中包含引用类型值所带来问题的过程当中,开发人员开始使用一种叫作借用构造函数(constructor stealing)的技术(有时候也叫作伪造对象或经典继承)。这种技术的基本思想至关简单,即在子类型构造函数的内部调用超类型构造函数。别忘了,函数只不过是在特定环境中执行代码的对象,所以经过使用 apply() 和 call() 方法也能够在(未来)新建立的对象上执行构造函数
- 062八、相对于原型链而言,借用构造函数有一个很大的优点,便可以在子类型构造函数中向超类型构造函数传递参数
- 062九、若是仅仅是借用构造函数,那么也将没法避免构造函数模式存在的问题——方法都在构造函数中定义,所以函数复用就无从谈起了。并且,在超类型的原型中定义的方法,对子类型而言也是不可见的,结果全部类型都只能使用构造函数模式。考虑到这些问题,借用构造函数的技术也是不多单独使用的
- 0630、ECMAScript 5 经过新增 Object.create() 方法规范化了原型式继承。这个方法接收两个参数:一个用做新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的状况下,Object.create() 与 object() 方法的行为相同。Object.create() 方法的第二个参数与 Object.defineProperties() 方法的第二个参数格式相同:每一个属性都是经过本身的描述符定义的。以这种方式指定的任何属性都会覆盖原型对象上的同名属性
- 063一、寄生组合式继承,即经过借用构造函数来继承属性,经过原型链的混成形式来继承方法
- 063二、 工厂模式,使用简单的函数建立对象,为对象添加属性和方法,而后返回对象。这个模式后来被构造函数模式所取代
- 063三、 构造函数模式,能够建立自定义引用类型,能够像建立内置对象实例同样使用 new 操做符。不过,构造函数模式也有缺点,即它的每一个成员都没法获得复用,包括函数。因为函数能够不局限于任何对象(即与对象具备松散耦合的特色),所以没有理由不在多个对象间共享函数
- 063四、原型模式,使用构造函数的 prototype 属性来指定那些应该共享的属性和方法。组合使用构造函数模式和原型模式时,使用构造函数定义实例属性,而使用原型定义共享的属性和方法
- 063五、JavaScript 主要经过原型链实现继承。原型链的构建是经过将一个类型的实例赋值给另外一个构造函数的原型实现的。这样,子类型就可以访问超类型的全部属性和方法,这一点与基于类的继承很类似。原型链的问题是对象实例共享全部继承的属性和方法,所以不适宜单独使用。解决这个问题的技术是借用构造函数,即在子类型构造函数的内部调用超类型构造函数。这样就能够作到每一个实例都具备本身的属性,同时还能保证只使用构造函数模式来定义类型。使用最多的继承模式是组合继承,这种模式使用原型链继承共享的属性和方法,而经过借用构造函数继承实例属性。 寄生组合式继承,集寄生式继承和组合继承的优势与一身,是实现基于类型继承的最有效方式
- 063六、当某个函数被调用时,会建立一个执行环境(execution context)及相应的做用域链。而后,使用 arguments 和其余命名参数的值来初始化函数的活动对象(activation object)。但在做用域链中,外部函数的活动对象始终处于第二位,外部函数的外部函数的活动对象处于第三位,……直至做为做用域链终点的全局执行环境
第七章 函数表达式
- 070一、因为闭包会携带包含它的函数的做用域,所以会比其余函数占用更多的内存。过分使用闭包可能会致使内存占用过多,咱们建议读者只在绝对必要时再考虑使用闭包。虽然像 V8 等优化后的 JavaScript 引擎会尝试回收被闭包占用的内存,但请你们仍是要慎重使用闭包
- 070二、在闭包中使用 this 对象也可能会致使一些问题。咱们知道, this 对象是在运行时基于函数的执行环境绑定的:在全局函数中, this 等于 window ,而当函数被做为某个对象的方法调用时, this 等于那个对象。不过,匿名函数的执行环境具备全局性,所以其 this 对象一般指向window。但有时候因为编写闭包的方式不一样,这一点可能不会那么明显
- 070三、若是闭包的做用域链中保存着一个HTML 元素,那么就意味着该元素将没法被销毁
- 070四、闭包会引用包含函数的整个活动对象,而其中包含着 element 。即便闭包不直接引用 element ,包含函数的活动对象中也仍然会保存一个引用。所以,有必要把 element 变量设置为 null 。这样就可以解除对 DOM 对象的引用,顺利地减小其引用数,确保正常回收其占用的内存
- 070五、函数声明后面不能跟圆括号。然而,函数表达式的后面能够跟圆括号。要将函数声明转换成函数表达式,只要像下面这样给它加上一对圆括号便可
- 070六、通常来讲,咱们都应该尽可能少向全局做用域中添加变量和函数。在一个由不少开发人员共同参与的大型应用程序中,过多的全局变量和函数很容易致使命名冲突。而经过建立私有做用域,每一个开发人员既可使用本身的变量,又没必要担忧搞乱全局做用域
- 070七、严格来说,JavaScript 中没有私有成员的概念;全部对象属性都是公有的。不过,却是有一个私有变量的概念。任何在函数中定义的变量,均可以认为是私有变量,由于不能在函数的外部访问这些变量。私有变量包括函数的参数、局部变量和在函数内部定义的其余函数。
- 070八、构造函数模式的缺点是针对每一个实例都会建立一样一组新方法,而使用静态私有变量来实现特权方法就能够避免这个问题
- 070九、初始化未经声明的变量,老是会建立一个全局变量
- 07十、多查找做用域链中的一个层次,就会在必定程度上影响查找速度。而这正是使用闭包和私有变量的一个显明的不足之处
- 07十一、 函数表达式不一样于函数声明。函数声明要求有名字,但函数表达式不须要。没有名字的函数表达式也叫作匿名函数
- 07十二、在没法肯定如何引用函数的状况下,递归函数就会变得比较复杂
- 071三、 递归函数应该始终使用 arguments.callee 来递归地调用自身,不要使用函数名——函数名可能会发生变化
- 071四、当在函数内部定义了其余函数时,就建立了闭包。闭包有权访问包含函数内部的全部变量:在后台执行环境中,闭包的做用域链包含着它本身的做用域、包含函数的做用域和全局做用域;一般,函数的做用域及其全部变量都会在函数执行结束后被销毁;可是,当函数返回了一个闭包时,这个函数的做用域将会一直在内存中保存到闭包不存在为止
- 071五、使用闭包能够在 JavaScript中模仿块级做用域(JavaScript自己没有块级做用域的概念)
- 071六、JavaScript 中的函数表达式和闭包都是极其有用的特性,利用它们能够实现不少功能。不过,由于建立闭包必须维护额外的做用域,因此过分使用它们可能会占用大量内存
第八章 BOM
- 080一、抛开全局变量会成为 window 对象的属性不谈,定义全局变量与在 window 对象上直接定义属性仍是有一点差异:全局变量不能经过 delete 操做符删除,而直接在 window 对象上的定义的属性能够
- 080二、刚才使用 var 语句添加的 window 属性有一个名为 [[Configurable]] 的特性,这个特性的值被设置为 false ,所以这样定义的属性不能够经过 delete 操做符删除。IE8及更早版本在遇到使用 delete删除 window 属性的语句时,无论该属性最初是如何建立的,都会抛出错误,以示警告。IE9 及更高版本不会抛出错误
- 080三、尝试访问未声明的变量会抛出错误,可是经过查询 window 对象,能够知道某个可能未声明的变量是否存在20二、窗口位置。用来肯定和修改 window 对象位置的属性和方法有不少。IE、Safari、Opera 和 Chrome 都提供了screenLeft 和 screenTop 属性,分别用于表示窗口相对于屏幕左边和上边的位置。Firefox 则在screenX 和 screenY 属性中提供相同的窗口位置信息,Safari 和 Chrome 也同时支持这两个属性。Opera虽然也支持 screenX 和 screenY 属性,但与 screenLeft 和 screenTop 属性并不对应,所以建议你们不要在 Opera 中使用它们
- 080四、最终结果,就是没法在跨浏览器的条件下取得窗口左边和上边的精确坐标值。然而,使用 moveTo()和 moveBy() 方法却是有可能将窗口精确地移动到一个新位置。这两个方法都接收两个参数,其中moveTo() 接收的是新位置的 x 和 y 坐标值,而 moveBy() 接收的是在水平和垂直方向上移动的像素数。
- 080五、须要注意的是,这两个方法可能会被浏览器禁用;并且,在 Opera 和 IE 7(及更高版本)中默认就是禁用的。另外,这两个方法都不适用于框架,只能对最外层的 window 对象使用
- 080六、跨浏览器肯定一个窗口的大小不是一件简单的事。IE9+、Firefox、Safari、Opera 和 Chrome 均为此提供了 4个属性: innerWidth、 innerHeight 、 outerWidth 和 outerHeight 。在 IE9+、Safari和 Firefox中, outerWidth 和 outerHeight 返回浏览器窗口自己的尺寸(不管是从最外层的 window 对象仍是从某个框架访问)。在Opera中,这两个属性的值表示页面视图容器① 的大小。而innerWidth 和 innerHeight则表示该容器中页面视图区的大小(减去边框宽度)。在 Chrome 中, outerWidth 、 outerHeight 与innerWidth 、 innerHeight 返回相同的值,即视口(viewport)大小而非浏览器窗口大小
- 080七、在 IE、Firefox、Safari、Opera 和 Chrome 中, document.documentElement.clientWidth 和document.documentElement.clientHeight 中保存了页面视口的信息。在 IE6 中,这些属性必须在标准模式下才有效;若是是混杂模式,就必须经过 document.body.clientWidth 和 document.body.clientHeight 取得相同信息。而对于混杂模式下的 Chrome,则不管经过 document.documentEle-ment 仍是 document.body 中的 clientWidth 和 clientHeight 属性,均可以取得视口的大小
- 080八、对于移动设备, window.innerWidth 和 window.innerHeight 保存着可见视口,也就是屏幕上可见页面区域的大小。移动 IE 浏览器不支持这些属性,但经过 document.documentElement.client-Width 和 document.documentElement.clientHeihgt 提供了相同的信息。随着页面的缩放,这些值也会相应变化
- 080九、有关移动设备视口的话题比较复杂,有不少很是规的情形,也有各类各样的建议。移动开发咨询师 Peter-Paul Koch 记述了他对这个问题的研究:http://t.cn/zOZs0Tz。若是你在作移动 Web 开发,推荐你读一读这篇文章
- 08十、 window.open() 方法既能够导航到一个特定的 URL,也能够打开一个新的浏览器窗口。这个方法能够接收 4 个参数:要加载的 URL、窗口目标、一个特性字符串以及一个表示新页面是否取代浏览器历史记录中当前加载页面的布尔值。一般只须传递第一个参数,最后一个参数只在不打开新窗口的状况下使用。后面这行代码会打开一个新的能够调整大小的窗口,窗口初始大小为 400×400 像素,而且距屏幕上沿和左边各 10 像素。window.open("http://www.wrox.com/","wroxWindow","height=400,width=400,top=10,left=10,resizable=yes");
- 08十一、wroxWin.close()这个方法仅适用于经过 window.open() 打开的弹出窗口。对于浏览器的主窗口,若是没有获得用户的容许是不能关闭它的。不过,弹出窗口却是能够调用 top.close() 在不经用户容许的状况下关闭本身。弹出窗口关闭以后,窗口的引用仍然还在,但除了像下面这样检测其 closed 属性以外,已经没有其余用处了
- 08十二、超时调用须要使用 window 对象的 setTimeout() 方法,它接受两个参数:要执行的代码和以毫秒表示的时间(即在执行代码前须要等待多少毫秒)。因为传递字符串可能致使性能损失,所以不建议以字符串做为第一个参数
- 081三、JavaScript 是一个单线程序的解释器,所以必定时间内只能执行一段代码。为了控制要执行的代码,就有一个 JavaScript 任务队列。这些任务会按照将它们添加到队列的顺序执行。 setTimeout() 的第二个参数告诉 JavaScript 再过多长时间把当前任务添加到队列中。若是队列是空的,那么添加的代码会当即执行;若是队列不是空的,那么它就要等前面的代码执行完了之后再执行
- 081四、超时调用的代码都是在全局做用域中执行的,所以函数中 this 的值在非严格模式下指向 window 对象,在严格模式下是 undefined
- 081五、通常认为,使用超时调用来模拟间歇调用的是一种最佳模式。在开发环境下,不多使用真正的间歇调用,缘由是后一个间歇调用可能会在前一个间歇调用结束以前启动。而像前面示例中那样使用超时调用,则彻底能够避免这一点。因此,最好不要使用间歇调用
- 081六、经过 JavaScript 打开的对话框,即“查找”和“打印”。这两个对话框都是异步显示的,可以将控制权当即交还给脚本。这两个对话框与用户经过浏览器菜单的“查找”和“打印”命令打开的对话框相同。而在 JavaScript 中则能够像下面这样经过 window 对象的 find() 和 print() 方法打开它们
- 081七、URL获取参数并封装成对象。这个函数的第一步是先去掉查询字符串开头的问号。固然,前提是 location.search 中必需要包含一或多个字符。而后,全部参数将被保存在 args 对象中,该对象以字面量形式建立。接下来,根据和号(&)来分割查询字符串,并返回 name=value 格式的字符串数组。下面的 for 循环会迭代这个数组,而后再根据等于号分割每一项,从而返回第一项为参数名,第二项为参数值的数组。再使用 decodeURIComponent() 分别解码 name 和 value (由于查询字符串应该是被编码过的)。最后,将 name 做为 args 对象的属性,将 value 做为相应属性的值
- 081八、每次修改 location 的属性( hash 除外),页面都会以新 URL 从新加载
- 081九、在 IE八、Firefox 一、Safari 2+、Opera 9+和 Chrome 中,修改 hash 的值会在浏览器的历史记录中生成一条新记录。在 IE 的早期版本中, hash 属性不会在用户单击“后退”和“前进”按钮时被更新,而只会在用户单击包含 hash 的 URL 时才会被更新
- 0820、replace() 方法。这个方法只接受一个参数,即要导航到的 URL;结果虽然会致使浏览器位置改变,但不会在历史记录中生成新记录。在调用 replace() 方法以后,用户不能回到前一个页面
- 082一、与位置有关的最后一个方法是 reload() ,做用是从新加载当前显示的页面。若是调用 reload()时不传递任何参数,页面就会以最有效的方式从新加载。也就是说,若是页面自上次请求以来并无改变过,页面就会从浏览器缓存中从新加载。若是要强制从服务器从新加载,则须要像下面这样为该方法传递参数 true。位于 reload() 调用以后的代码可能会也可能不会执行,这要取决于网络延迟或系统资源等因素。为此,最好将 reload() 放在代码的最后一行
- 082二、检测浏览器中是否安装了特定的插件是一种最多见的检测例程。对于非 IE 浏览器,可使用plugins 数组来达到这个目的。
- 082三、检测 IE 中的插件比较麻烦,由于 IE 不支持 Netscape 式的插件。在 IE 中检测插件的惟一方式就是使用专有的 ActiveXObject 类型,并尝试建立一个特定插件的实例。IE 是以 COM对象的方式实现插件的,而 COM对象使用惟一标识符来标识。所以,要想检查特定的插件,就必须知道其 COM 标识符。例如,Flash 的标识符是 ShockwaveFlash.ShockwaveFlash
- 082四、plugins 集合有一个名叫 refresh() 的方法,用于刷新 plugins 以反映最新安装的插件。这个方法接收一个参数:表示是否应该从新加载页面的一个布尔值。若是将这个值设置为 true ,则会从新加载包含插件的全部页面;不然,只更新 plugins集合,不从新加载页面
- 082五、history 对象保存着用户上网的历史记录,从窗口被打开的那一刻算起。由于 history 是 window对象的属性,所以每一个浏览器窗口、每一个标签页乃至每一个框架,都有本身的 history 对象与特定的window 对象关联
- 082六、使用 go() 方法能够在用户的历史记录中任意跳转,能够向后也能够向前。这个方法接受一个参数,表示向后或向前跳转的页面数的一个整数值。负数表示向后跳转(相似于单击浏览器的“后退”按钮),正数表示向前跳转(相似于单击浏览器的“前进”按钮)。也能够给 go() 方法传递一个字符串参数,此时浏览器会跳转到历史记录中包含该字符串的第一个位置——可能后退,也可能前进,具体要看哪一个位置最近。若是历史记录中不包含该字符串,那么这个方法什么也不作
- 082七、另外,还可使用两个简写方法 back() 和 forward() 来代替 go() 。顾名思义,这两个方法能够模仿浏览器的“后退”和“前进”按钮
- 082八、当页面的 URL 改变时,就会生成一条历史记录。在 IE8 及更高版本、Opera、Firefox、Safari 3 及更高版本以及 Chrome 中,这里所说的改变包括 URL 中 hash 的变化(所以,设置 location.hash 会在这些浏览器中生成一条新的历史记录)
- 082九、浏览器对象模型(BOM)以 window 对象为依托,表示浏览器窗口以及页面可见区域。同时, window对象仍是 ECMAScript 中的 Global 对象,于是全部全局变量和函数都是它的属性,且全部原生的构造函数及其余函数也都存在于它的命名空间下
第九章 客户端检测
- 090一、检测 Web 客户端的手段不少,并且各有利弊。但最重要的仍是要知道,不到万不得已,就不要使用客户端检测。只要能找到更通用的方法,就应该优先采用更通用的方法。一言以蔽之,先设计最通用的方案,而后再使用特定于浏览器的技术加强该方案
- 090二、在实际开发中,应该将能力检测做为肯定下一步解决方案的依据,而不是用它来判断用户使用的是什么浏览器
- 090三、与能力检测相似,怪癖检测(quirks detection)的目标是识别浏览器的特殊行为。但与能力检测确认浏览器支持什么能力不一样,怪癖检测是想要知道浏览器存在什么缺陷(“怪癖”也就是 bug)
- 090四、能力检测:在编写代码以前先检测特定浏览器的能力
- 090五、 怪癖检测:怪癖其实是浏览器实现中存在的 bug
- 090六、用户代理检测:经过检测用户代理字符串来识别浏览器
- 090七、在决定使用哪一种客户端检测方法时,通常应优先考虑使用能力检测。怪癖检测是肯定应该如何处理代码的第二选择。而用户代理检测则是客户端检测的最后一种方案,由于这种方法对用户代理字符串具备很强的依赖性