《JavaScript高级程序设计》学习笔记——EMCAScript

Author:Chemandy

第一章 JavaScript实现

1. JavaScript由三个部分组成:ECMAScript、DOM、BOM。

2. 文档对象模型(DOM):针对XML,但经扩展用于HTML的应用程序。

3. DOM级别:

□DOM1级(映射文档)

◇DOM核心:规定如何映射基于XML的文档结构。

◇DOM HTML:DOM核心上扩展,添加针对HTML的方法。

□DOM2级

◇视图(DOM Views):跟踪不同文档视图接口。

◇事件(DOM Events):事件和事件处理的接口。

◇样式(DOM Style):基于CSS为元素应用样式的接口。

◇遍历和范围(DOM Travelsal and Range):遍历和操作文档树接口。

□DOM3级

◇加载与保存文档的方法。

◇验证文档方法。

◇核心扩展,支持XML1.0规范。

□DOM0级(其标准不存在):IE4.0和Netscpe 4.0最初支持的DHTML。

4. BOM:访问和操作浏览器窗口和框架。

①弹出新窗口。

②移动、缩放、关闭浏览器

③navigator对象(浏览器详细信息)

④location对象(所加载页面详细信息)

⑤screen对象(显示器分辨率详细信息)

⑥XMLHttpRequest和IE的ActiveXObject。

第二章 在HTML中使用JavaScript

1. <script>元素(插入JS主要方法),含以下5个属性:

①type:必需。考虑兼容性,使用text/javascript。

②src:可选。表示包含要执行的外部文件。

③charset:忽略。表示通过src属性指定的代码的字符集。

④defer:可选。脚本延迟到文档完全被解析和显示后再执行。只有IE、FF可用。

⑤language:已废弃。表示编写代码所用的脚本语言。

2. 将js放置于body元素中,提高页面显示速度。

<body>

<!--body内容-->

<script type="text/javascript" src="#"></script>

</body>

原因:若js置于head元素中,则必须等js都被下载、解析和执行完成以后,才开始读取呈现body内容。

3. defer属性,在js标签中设置此属性,可使脚本延迟到整个页面都解析完毕后再运行,作用于把<script>放在页面最底部的效果一样。(仅IE和FF支持)。

4. 在XHTML中内嵌js代码的方法:

方法一:

<script type="text/javascript">

<![CDATA[

js代码,此处js代码中特殊符号需要进行编码

]]>

</script>

方法二:

<script type="text/javascript">

//<![CDATA[

js代码。完美兼容,此处js代码中特殊符号不需要进行编码

//]]>

</script>

5. <noscript></noscript>元素,显示条件:浏览器不支持脚本或脚本被禁用。

第三章 基本概念

1. 变量、函数名、操作符——都区分大小写。

2. ECMAScript标识符用驼峰大小写格式,首字母小写,余下词首大写。自定义引用类型则用Pascal法。

3. 注释:

//单行注释

/*

* 多行注释

*

*/

4. ECMAScript变量是松散类型(即可以保存任何类型的数据)。

定义变量而未赋值的话,会保存一个特殊值——undefined。

5. □ 使用var操作符定义的变量将成为定义该变量的作用域中的局部变量(即在一函数中定义var变量,函数退出变量被销毁)

    □ 省略var操作符定义变量,则变量成全局变量。

6. ECMAScript中有5种简单数据值类型:Undefined、Null、Bollean、Number和String。还有一种复杂类型——Object(本质上是由一组无需的名值对组成的)

7. typeof操作符。返回值为字符串:“undefined”、“boolean”、“string”、“number”、“object”、“function”。

8. 建议显式初始化变量,使得使用typeof时,当得undefined可判为未声明变量。

9. Number类型

①定义不同数值字面量:

varintNum = 55; //十进制

var octalNum = 070; //八进制,第一位必须为0

var hexNum = 0x1f; //十六进制,前两位必须为0x

进行算术计算时,八进制和十六进制数最终转成十进制。

②由于精度问题,勿测试浮点数值。 if (0.1 + 0.2 == 0.3) //永远为false

③数值范围:Number.MIN_VALUE; Number.MAX_VALUE

   若数值超出范围则转为Infinity或-Infinity(负无穷),此时无法参与运算。可用isFinite()函数测试返回boolean值。

④NaN,一个特殊数值,表示本来要返回数值的操作数未返回数值。通过isNaN()函数测试返回布尔值。传入参数若可转为数值,则返回false。

⑤数值转换:Number()——可用于任何类型。parseInt()和parseFloat()——仅用于字符串。

(1)Number()函数转换规则:

1)布尔值转为0或1

2)数字则简单的传入和返回

3)null值返回0

4)undefined返回NaN

5)字符串,规则如下:

◇只含数字则转为十进制,忽略前导0(011→11)

◇含有效浮点格式,转为相应值。

◇含有效十六进制格式,转为相同大小的十进制值。

◇空字符串,转0

◇其他格式,NaN

6)对象,先调用valueOf(),再用前面的规则判断,若结果为NaN,调用toString(),再用前面规则判断。

(2)parseInt():

□ 忽略字符串前空格,找到第一个非空字符。

◇非数值或非负号,返回NaN

◇数值或负号,继续解析后面字符知道一个非数字字符,返回前面数值。(可解析各种进制。始终返回十进制的值)

var num1 = parseInt("010"); //8(按八进制)

var num2 = parseInt("010",8); //8(按八进制)

var num3 = parseInt("010",10); //10(按十进制)

(3)parseFloat():

□ 与parseInt()区别:

◇ parseFloat()不会忽略第1个小数点。

◇ parseFloat()始终忽略前导0,只转换十进制。

10. String类型

①转义序列:\n换行;\t制表;\b空格;\r回车;\f进纸;\\斜杠;\'单引号;\"双引号;\xnn以十六进制代码nn表示的一个字符(n为0到F)\unnn以十六进制代码nnn表示的一个unicode字符。

②字符串length属性返回文本长度。

③ECMAScript中字符串是不可变的,要改变原字符串值,需要先销毁。

④数值、布尔值、对象和字符串值都有toString()方法。(包装类型,普通类型都有继承object原型的toString方法)

⑤当toString()用于数值时,可选参数2、8、10、16(表进制)

⑥String()方法可用于所有类型的值,没有参数

   ◇如值有toString()方法,则调用并返回。

   ◇值为null返回“null”,值为undefined返回“undefined”

11. Null类型

如果定义的变量准备在将来用于保存对象,那最好初始化为null。

12. Boolean类型

只有两个字面值true(不一定等于1)和false(不一定等于0)

Boolean(参)方法可将所有类型转为布尔值,if()语句中自动调用这个方法。

13. Object类型

Object类型的实例都具有下列属性和方法:

□ constructor属性:保存着用于创建当前对象的函数。

□ hasOwnProperty(propertyName)——用于检查给定的属性在当前对象实例中(而非实例的原型中)是否存在。

□ isPrototypeof(object)——用于检查传入对象是否是另一个对象的原型。

□ propertyIsEnumerable(propertyName)——用于检查给定属性是否能够使用for-in语句。

□ toString():返回对象的字符串表示。

□ valueof():返回对象的字符串、数值或布尔值表示。

14. 递增和递减操作符++、--,可用于各种类型,自动调用numeber()一元加和减操作符,在非数值应用时,自动调用number()后运算。

15. 位操作符:

①按位非(NOT),由(~)表示。

var num1 = 25;  //25

var num2 = ~num1; //-26

②按位与(AND),由(&)表示。

Var num = 25&3; //1

③按位或(OR),由(|)表示。

Var num = 25|3; //27

④按位异或(XOR),由(^)表示。Var num = 25^3; //26

⑤左移,由(<<)表示,隐藏符号位,右空位以0填充。

⑥有符号右移,由(>>)表示,隐藏符号位,左空以符号位数字进行填充。

⑦无符号右移,由(>>>)表示,包含符号位进行移动,以0填充空位。

16. 布尔操作符:

①基本概况:

□ 逻辑非(!):所有类型自动调用Boolean()再进行逻辑非操作,返回布尔值。

□ 逻辑与(&&),逻辑或(||):不一定返回布尔值。

②逻辑与(&&),在有一个操作数不是布尔值的情况下,逻辑与操作符就不一定返回布尔值:

□ 如果第一个操作数是对象,则返回第二个操作数。

□ 如果第二个操作数是对象,则只有在第一个操作数的求值结果为true的情况下才会返回该对象。

□ 如果两个操作数都是对象,则返回第二个操作数。

□ 如果有一个操作数是null,则返回null。

□ 如果有一个操作数是NaN,则返回NaN。

□ 如果有一个操作数是undefined则返回undefined。

③逻辑或(||),如果有一个操作数不是布尔值,逻辑或也不一定返回布尔值:

□ 如果第一个操作数是对象,则返回第一个操作数。

□ 如果第一个操作数求值为false,则返回第二个操作数。

□ 如果两个操作数都是对象,则返回第一个操作数。

□ 如果两个操作数都是null,返回null

□ 如果两都为undefined,返undefined。

□ 如果两都为NaN,返NaN

17. ECMAScript定义的3个乘性操作符:乘法(*)、除法(/)、求模(%),如操作数不是数值,会自动执行number()进行转换。

18. 加性操作符:

①加法

□ 两操作数均为数值时,执行加法计算。

□ 其中一个操作数为字符串时,执行字符串拼接。另一个自动转字符。

②减法

□ 两个操作数都是数值,执行减法

□ 操作数含字符串、布尔值、null或undefined,则后台调用number()

□ 如有一操作数是对象,调用valueOf(),若无此方法,调toString().

19. 关系操作符:< 、> 、<= 、>= 。(当关系操作符的操作数使用了非数值时,也需进行数据转换)。

□ 如果两个操作数都是数值,则直接执行比较。

□ 如果两个操作数都是字符串,则比较两个字符串对应的字符编码值。

□ 如果一个操作数是数值,则将另一个操作数转换为一个数值,再执行比较。

□ 如果一个操作数是对象,则调用valueOf()或toString()再比较。

20. 相等操作符(两类)

①相等和不相等(先转换再比较)==、!=

□ 如果一个是布尔值,比较前先转为数值。

□ 如果一个是字符串,另一个不是,则字符串先转为数字。

□ 如果一个是对象,调用valueOf(),再按两条比较。

□ 若两个操作数均是对象,则比较是否为同一个对象。

□ null和undefined相等,比较时不做转换。

□ NaN不等于NaN

②全相等和不全相等(仅比较而不转换)“===”“!==”

21. 条件操作符 variable = boolean_experssion ? true_value : false_value;

22. 赋值操作符: 其中几个比较特别的:<<= 、>>= 、>>>=

23. 在for语句中,for( var i = 0; i < count; i++) { },由于ECMAScript中不存在块级作用域,因此循环内部定义的变量可以在外部访问到。

24. for-in语句是一种精准的迭代语句,可以用来枚举对象的属性。for(var property in expression) statement;

25. with语句的作用是将代码的作用域设置到一个特定的对象中。with(location){var qs = hostname;},在执行环境中的变量是只读的不能修改,方括号内定义的变量可以在with语句之外访问。

26. ECMAScript中,switch语句特点:

□ switch语句中可以使用任何数据类型。

□ 每个case值不一定是常量,可以使变量,甚至是表达式。

27. 当return语句不带任何返回值,此时,函数停止执行后返回undefined。

28. ECMAScript函数的参数:

ECMAScript中的参数在内部是用个数组表示的。解析器不在乎传入多少个参数,无论声明时定义了多少。

有声明但无参数传入,均赋值为undefined。

函数内部可以用arguments[i]调用参数。

ECMAScript所有参数传递都是值传递,无引用传递。

29. ECMAScript没有重载,通过传入函数中参数类型和数量并作不同的反应,可模仿方法的重载。

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

1. ECMAScript两种不同的数据类型的值:

□ 基本类型值:保存在栈内存中的简单数据段,即值完全在内存中一个位置。固定的值大小:Undefined、Null、Boolean、Number、String

□ 引用类型值:保存在堆内存中的对象,十几保存一个指向内存的指针。

2. 复制变量值:基本类型值——复制值;引用类型值——复制指针;

3. typeof操作符一般用于检测基本数据类型值,String、Number、Boolean、undefined。但检测引用类型时不给力,只能返回object,无法判断是什么类型的对象。

4. instanceof操作符:result = variable instanceof constructor;如果变量是给定引用类型(由构造函数表示)的实例,那么instanceof操作符就会返回ture。

5. 执行环境及作用域:

①基本定义:

1)执行环境(execution context)定义了变量或函数有权访问的其他数据。

2)变量对象(variable object)环境中定义的所有变量和函数都保存在这个对象中。

3)函数调用时会创建自己的执行环境。

4)代码在一个环境中执行时,会创建由变量对象构成的一个作用域链(scope chain)。

5)如果环境是函数,则将其活动对象作为变量对象。

6)执行环境类型只有两种——全局和局部(函数)。

7)延长作用域链:

□ try-catch语句的catch块

□ with语句

执行时作用域链增加一个变量对象,执行后该变量对象移除。

②没有块级作用域

1)这导致{}内代码执行完后,外部仍可以访问,注意if(){},for(){}

2)使用var关键字声明变量时,这个变量将自动添加到距离最近的可用环境中。对于函数而言,这个最近的环境就是函数的局部环境。对with语句而言,也是with语句外最近的环境。

6. 垃圾收集

①实现方法

□ 标记清除:标记进入、退出环境状态,以完成内存清除。

◇ 各浏览器js引擎均以此为垃圾收集引擎。

□ 引用计数:跟踪记录每个值被引用的次数。

◇ 易导致循环引用,使得无法清除无用内存。IE中非原生JS对象和BOM、DOM(COM对象)其垃圾收集为引用计数。

7. 管理内存

解除引用:当数据不再有用,通过将其值设置为null来解放引用。

第五章 引用类型

1. 概念:

①ECMAScript中引用类型是一种数据结构,将数据和功能组织在一起。类似与其他语言的“类”。

②引用类型的值是对象。对象也是一种复杂类型(数据类型)。

2. Object类型:

①创建方法:

□ new操作符+构造函数

□ 对象字面量 var a = {},即创建了object对象。

②对象属性可通过点号语法和方括号语法访问。

□ person.name

□ person["name"],此方法适用于用变量访问属性时使用。

3. Array类型

①ECMAScript数组的每一项可以保存任何类型的数据。

②数组大小是可动态调整的,可随着数据的添加自动增加容纳新增数据。数组的length属性可读可写。

③转换方法:toLocaleString()、toString()和valueOf(),join()

④栈方法:

□ push(),接受任意数量的参数,把他们逐个添加到数组末尾,并返回修改后的数组长度。

□ pop(),从数组末尾移除最后一项,减少数组的length值,然后返回移除的项。

⑤队列方法:

□ push()

□ shift(),移除数组的第一个项并返回该项,同时数组长度减一。

□ unshift(),在数组前端添加任意个项并返回新数组的长度。unshift()和pop(),可以从反方向模拟队列。

⑥重排序方法:

□ reverse(),将数组项顺序对反。

□ sort(),默认对数组每项使用toString()再比较排序。可以传入一函数进行比较判断。

⑦操作方法

□ concat(),基于当前数组中的所有项创建一个新数组。

◇ 若无参数则为简单复制并返回副本。

◇ 若有一个或多个数组作为参数,则将每一项添加到结果数组。

◇ 若传递的值不是数组,则简单添加至末尾。

□ slice(),基于当前数组中的一或多个项创建一个新数组。

◇ 接受一个或两个参数,即要返回项的起始和结束位置。

□ splice(),删除、插入、替换3种用法。

◇ 删除:splice(0,2),从第0项开始删除2项。

◇ 插入:splice(2,0,"a","b"),从第3项开始插入"a"再插入"b"。

◇ 替换:splice(2,1,"a","b")删除第3项,插入"a","b"。

4. Date类型

①创建日期对象

□ var now = new Date(); //不传入参数可得当前日期

□ var sday = new Date("May 25,2004"); //传入字符串自动调用Date.parse()

等价于var sday = new Date(Date.parse("May 25,2004"));

◇Date.parse()返回该日期毫秒数,接受格式:

○“月/日/年”,如6/13/2004;如:January 12,2004

○“英文月名 日,年”,如January 12,2004;如:January 12,2004

○“英文星期几 英文月名 日 年 时:分:秒 时区”,如:Tue May 25 2004 00:00:00 GMT-0700

□ var sday = new Date(2005,4,5,17,55,55); //传入数字,自动调用Date.UTC()

等价于var sday = new Date(Date.UTC(2005,4,5,17,55,55));

◇参数:年,月(基于0),日(1-31),小时(0-23),分钟,秒,毫秒。

②继承的方法

□ toLocaleString():按照与浏览器设置的地区相适应的格式返回日期。

□ toString();返回带时区信息的日期和时间。

□ valueOf():返回日期的毫秒表示,一般用于比较时间。

5. RegExp类型

①创建正则表达式: var expression = / pattern / flags;

□ 其中的模式(pattern)部分可以是任何简单或复杂的正则表达式。

□ flags,用以标明正则表达式的行为。

◇ g-全局(global)模式,即应用于所有字符串,非匹配一项即停。

◇ i-不区分大小写(case-insensitive)模式。

◇m-多行(multiline)模式,到一行末尾会查下一行。

△可用构造函数创建正则:var a = new RegExp("[bc]at","i"); //这种方法需要对字符进行双重转义。

②RegExp实例属性

□ global——布尔值,是否设置了g标志。

□ ignoreCase——布尔值,是否设置了i标志。

□ lastIndex——整数,表示开始搜索下一个匹配项的字符位置。

□ multiline——布尔值,表示是否设置了m标志。

□ source——正则表达式字符串表示。

③RegExp实例方法

□ exec(),接受一个参数,即要应用模式的字符串。没匹配则返回null,有匹配则返回带属性index、input的数组。

◇ index:匹配项在字符串中位置

◇ input:表示应用正则表达式的字符串

◇ 数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串。

□ test(),接受一个字符串,与模式匹配返true,否则false

□ toLocaleString()和toString()返回表达式字面量。

□ valueof()返回表达式本身。

④RegExp构造函数属性:略

6. Function类型

①ECMAScript中,函数是一个对象,与其他类型一样有自己的属性和方法。

②函数名是指针。

③用函数表达式定义函数,末尾要加一个分号。

var sum = function (num1,num2){

return num1 + num2;

};

④没有重载。

⑤函数声明与函数表达式:

□ 函数声明:解释器会率先读取函数声明,并使其在执行任何代码之前可用(可访问)

□ 函数表达式:必须等到解释器执行到它所在的代码行,才会真正被解释执行。

⑥ECMAScript函数名本身就是变量,函数可以作为值来使用。可将函数传入函数也可将函数做返回结果。

⑦函数内部属性,有两个特殊对象arguments和this。

□ arguments:类数组对象,包含传入函数中的所有参数。

◇ arguments对象中还有一个callee属性,该属性是一个指针,指向拥有这个argument对象的函数。

◇ 另一个特殊对象是this,行为与Java和C#中this类似。

○ this引用的是函数据以执行操作的对象。

○ this是函数在执行时所处的作用域。

⑧函数属性和方法

□ length属性:表示函数希望接受的命名参数的个数。

□ prototype属性:保存实例方法的真正所在。

□ apply()方法:在特定作用域中调用函数,接受两个参数,一个是作用域,一个是参数数组。第二个参数可是Array实例,也可是arguments对象。

□ call()方法:作用于apply()一样,但需要逐个传入调用参数。

□ caller属性:通过arguments.callee.caller调用,实现对调用栈的追溯。

□ toLocaleString()、toStirng()、valueOf()返回函数代码。

7. 基本包装类型:Boolean、Number和String。

1)基本概念

①当读取一个基本类型值时,后台会创建一个对应的基本包装类型的对象,从而能调用一些方法来操作数据。

②基本包装类型仅在对应简单数据类型调用其包装方法时创建,方法执行完毕,包装类型销毁。

③不能为基本类型值添加属性和方法。

④可显式创建基本包装对象。

2)Boolean类型(基本包装类型,建议永远不要使用)

因为Boolean基本包装类型对象在布尔环境中永远返回true。

3)Number类型(基本包转类型,不建议实例化)

①valueOf()、toLocaleString()、toString()方法。基本数据类型已提及。

②toFix(num):以指定小数位返回数值的字符串表示。

③toExponential(num):返回以指数(e)表示数值的字符串,参数指定输出结果中的小数位数。

④toPrecision(num):以合适方式返回数值字符串。参数指定表示数值的所有数字的位数(不含指数部分)。

4)String类型

①valueOf()、toLocaleString()、toString()返回字符串。

②chartAt(num):返回数值编号位置字符。charCodeAt(num):返回编号位字符编码。

③Concat()字符串拼接,可传入多个字符串进行拼接,返回一个副本。

④基于字符串创建新字符:slice()、substr()和subString()。

⑤从字符串中查找子字符串:

□ indexOf(string,pos):指定查询的字符串(必选)和起始位置(可选)

□ lastIndexOf(string,pos):从后往前查询。

⑥字符串大小写转换方法:

toLowerCase()、toLocaleLowerCase()、

toUpperCase()、toLocaleUpperCase()

⑦字符串的模式匹配方法:

□ match():本质上与RegExp的exec()相同。接受一个参数,可以是一个正则表达式,可以是一个RegExp对象。返回一个数组。

□ search():从头开始向后查找,返回第一个匹配索引。

□ replace():第一个参数为要替换的值,可是字符串或正则。

□ split():基于指定的分隔符将一个字符串分割成多个字符串,结果一数组形式返回。第一个参数是分隔符,可是字符串或一个RegExp对象。第二个参数可选,指定数组大小。

⑧localeCompare(),比较字符串返回下面值:

□ 字符串在字母表中排在参数前,返回负数(通常为-1)。

□ 相等则返回0

□ 排在后面返回正数(通常为1)

⑨fromCharCode():接受一或多个字符编码,然后将它们转换成一个字符串。

⑩HTML方法,将字符串在浏览器中动态格式化(不推荐)。

8. 内置对象

①定义:由ECMAScript实现,不依赖宿主环境,在ECMAScript程序执行前已实例化。只有2个对象:Global和Math。

②Global对象:

□ 概念:终极“兜底儿对象”,所有在全局作用域中定义的属性和函数,都是Global对象的属性。

□ 前面介绍的函数,如isNaN()、isFinite()、parseInt()、parseFloat()都是Global对象的方法。

□ URI编码方法:(用特殊的UTF-8替换无效字符)

◇ encodeURI():主要用于整个URI,只将空格替换成%20。

◇ encodeURIComponent():主要用于URI中的某一段,一段是对查询字符串编码。替换所有非字母数字字符。

□ eval()方法:像一个完成的解析器,只接受一个参数,即要执行的ECMAScript字符串。

□ 所有原生引用类型的构造函数,都是Global对象的属性。

□ JavaScript中window对象扮演着ECMAScript中的Global对象。

③Math对象

□ Math对象属性。

□ min()和max()方法。

□ 舍入方法:Math.ceil()、Math.floor()、Math.round()

□ random()

□ 其他方法

第6章 面向对象的程序设计

1. 创建对象

ECMAScript中对象是一组名值对,其中值可以是数据或函数,每个对象都是基于一个引用类型创建的,可是原生或自定义类型。

1)工厂模式

优:用函数来封装以特定接口创建对象的细节。

缺:没有解决对象识别的问题。

function creatPerson(name, age, job){

var o new Object();

o.name = name;

o.age = age;

o.job = job;

o.sayName = function(){

alert(this.name);

};

return o;

}

调用:var person1 = createPerson("Nicholas",29,"Doctor");

2)构造函数模式

□ 特点:没有显式地创建对象,直接将属性和方法赋值给了this对象。没有return语句。

□ 执行步骤:创建一个新对象 → 将构造函数作用域赋给新对象 → 执行构造函数代码 → 返回新对象

□ 这种模式的函数名首字母大写。

□ 对象有constructor(构造函数)属性,指向构造函数。如果需要检测对象,instanceof操作符比检测该属性更加可靠。这属性和操作符始终会假设在全局作用域中查询。

□ 构造函数实际上是普通函数,可作普通函数调用。当使用new操作符时,才会创建并返回一个对象。

□ 主要问题:每个方法都要在每个实例上重新创建一遍。

function Person(name, age, job){

this.name = name;

this.age = age;

this.job = job;

this.sayName = function(){

Alert(this.name);

};

}

调用:var person1 = new Person("Nicholas",29,"sf Engineer");

3)原型模式:

①基本概念:创建的函数均有一个prototype属性,此属性是一对象,是通过该函数创建的对象的原型对象。

②理解原型:

□ 创建函数会自动创建一个prototype属性,该属性自动获得constructor。

□ 调用函数创建实例,产生一个内部属性__proto__指向构造函数原型对象,实现属性方法的原型调用。

□ 通过isPrototypeOf()方法来确定对象之间的关系。

Person.prototype.isPrototypeOf(person1)); //true

□ 在实例对象中添加同名属性可屏蔽原型属性,若要恢复原型属性使用操作符delete删除属性。

□ hasOwnProperty(),给定属性存在于实例中时,返回true。person1.hasOwnProperty("name");//false

③原型与in操作符

□ in操作符在通过对象能够方位给定属性时返回true。无论其在原型中还是实例中。alert("name" in person1);//true

□ 屏蔽不可枚举属性的实例属性不会在for-in循环中。

④原型的动态性

□ 可随时为原型添加属性和方法,修改能立即在对象实例中反映。

□ 实例化类型后,重写原型对象会导到实例对象__proto__与原型对象指向丢失,无法访问原型属性和方法。

⑤原生对象的原型

□ 不要修改。。。

⑥原型对象的问题

□ □ □ 对于引用类型的值的属性,由于共享,无法拥有实例自己的私有属性。

function Person(){}

Person.prototype = {

name:"Nicholas",

age:29,

job:"Software Engineer",

sayName:function(){

Alert(this.name);

}

};

4)组合使用构造函数模式和原型模式。(定义引用类型默认模式)

□ 构造函数模式用于定义实力属性,而原型模式用于定义共享属性。

function Person(name, age, job){

this.name = name;

this.age = age;

this.job = job;

this.friends = ["shelby","court"];

}

Person.prototype = {

constructor : Person,

sayName : function(){

alert(this.name);

}

}

var person1 = new Person("Greg",29,"Doctor");

5)动态原型模式

□ 把所有信息都封装在了构造函数中。通过构造函数初始化原型,有保持了同时使用构造函数和原型的优点。

□ 这种模式不能使用对象字面量重写原型。

function Person(name,age,job){

//属性

this.name = name;

this.age = age;

this.job = job;

//方法

If(typeof this.sayName != "function" ) {

Person.prototype.sayName = function(){

Alert(this.name);

};

}

}

6)寄生构造函数模式

□ 思路与工厂模式一致,实例化时,使用new操作符。

□ 返回的对象与构造函数(及其原型属性)没有关系,不能通过instanceof操作符来确定对象类型。(个人认为这与工厂模式一样)。

□ 不推荐使用,只有特殊情况下才用。

function SpecialArray(){

//创建数组

var values = new Array();

//添加值

values.push.apply(values,arguments);

//添加方法

values.toPipeedString = function(){

Return this.join("|");

};

//返回数组

return values;

}

使用:var colors = new SpecialArray("red","blue","green");

7)稳妥构造函数

□ 没有公共属性,方法不引用this对象

□ 适合在安全环境(禁用new和this)中使用,或防止数据被其他应用程序使用。

□ 基本与寄生构造函数类似,区别:①实例方法不引用this;②不适用new调用构造函数。

□ 对象与构造函数无关联,instanceof无意义。

function Person(name,age,job){

//创建要返回的对象

var o = new Object();

//可以在这里定义似有变量和函数

//添加方法

o.sayName = function(){

alert(name);

};

//返回对象

return o;

}

var person = Person("Nicholas",29,"Software Engineer");

2. 继承 

接口继承值继承方法签名,实现继承则继承实际方法。

ECMAScript函数没有签名,只通过原型链实现现实继承。

1)原型链

①基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。

function SuperType(){

this.property = true;

}

SuperType.protype.geSuperValue = function(){

Return this.property;

};

function SubType(){

this.subproperty = false;

}

//继承了SuperType

subType.prototype = new SuperType();

subType.prototype.getSubValue = function(){

return this.subproporty;

};

②默认原型,Object.prototype

③确定原型和实例关系

□ instanceof操作符:测试实例与原型链中出现过的构造函数,返回true。

□ isPrototypeOf()方法:原型链中出现过的原型均返回true。

④谨慎地定义方法:给原型添加方法的代码一定要放在替换原型的语句之后。通过原型链实现继承时,不能使用对象字面量创建原型方法。

⑤原型链的问题

□ 原型链prototype中的属性有引用类型,则出现共享问题。

□ 创建子类型的实例时,无办法在不影响所有对象实例的情况下给超类型函数传递参数。

2)借用构造函数(伪造对象/经典继承)

①思路:在子类型构造函数的内部通过apply()或call()调用超类构造函数。

②利用apply()或call()调用超类构造函数时传入参数。

③问题

□ 方法都在构造函数中定义,无法实现函数复用

□ 超类原型中定义的方法,对子类不可见,结果所有类型只能使用构造函数模式。

function SuperType(name){

this.name = name;

}

function SubType(){

//继承了SuperType,同时还传递了参数

SuperType.call(this,"Nicholas");

//实例属性

this.age = 29;

}

3)组合继承(伪经典继承)

①思路:使用原型链实现对原型属性和方法的继承。使用“借用构造函数”实现对实例属性的继承。

②js中最常用的继承,可以使用instanceof和isPrototypeOf()测试。

function SuperType(name){

This.name = name;

This.colors = ["red","blue","green"];

}

SuperType.prototype.sayName = function(){

alert(this.name);

};

function SubType(name,age){

//继承属性

SupteType.call(this,name);

this.age = age;

}

//继承方法

SubType.prototype = new SuperType();

SubType.prototype.sayAge = function(){

alert(this.age);

};

4)原型式继承

□ 借助已有对象创建新对象

□ 使用场合:在没有必要兴师动众地创建构造函数,而只想让一个对象与另一个对象保持类似.

function proobject(o){

function F(){}

F.prototype = o;

return new F();

}

5)寄生式继承

□ 创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它完成所有工作一样返回。

□ 缺点:函数不复用,共享问题。

function createAnother(original){

var clone = proobject(original); //通过调用函数创建一个新对象

clone.sayHi = function(){

Alert("Hi");

};

return clone; //返回对象

}

6)寄生组合式继承

□ 寄生组合式继承:通过借用构造函数来继承属性,通过原型链的混成形成来继承方法。

□ 本质上是使用寄生继承来继承超类型的原型,在将结果指定给子类型的原型。

□ 优点:避免创建不必要的多余的属性,保持原型链不变,可用instanceof和isPrototypeOf()检测。

function inheritPrototype(subType, superType){

var prototype = proobject(superType); //创建对象

prototype.contructor = subType; //增强对象

subType.prototype = prototype; //指定对象

}

第七章 匿名函数——Lambda

1. 概念

1)函数声明与函数表达式区别:

□ 前者在代码执行以前加载到作用域中,而后者在代码执行到时才有定义。

□ 前者会给函数指定一个名字,后者将匿名函数赋给一个变量。

2)匿名函数:

□ 将函数作为参数传入另一个函数。

□ 从一个函数返回另一个函数。

2. 闭包

1)基本概念:

□ 闭包:有权访问另一个函数作用域中的变量的函数

□ 函数的作用域链保存在函数的一个特殊内部属性[[scope]]中。作用域链包含各级变量对象。

□ 活动对象:函数被调用时,会由this、arguments和其他命名参数初始化。

□ 闭包产生:在函数A中返回函数B,便产生闭包函数B。A返回B后,B的作用域链含有A的变量对象,因而A不会销毁其变量对象,只销毁自身作用域链。当B函数执行完,A的变量对象才会销毁。

2)闭包与变量:闭包只能取得包含函数中任何变量的最后一个值,且只读。

3)关于this对象:

□ this对象是在运行时给予函数的执行环境绑定的。

◇全局函数中,this等于window

◇当函数作为某个对象的方法调用时,this等于那个对象。

◇匿名函数的执行环境具有全局性,this通常指向window。

◇使用匿名函数定义对象方法时,该匿名函数内this等于那个对象。

4)活动对象与变量对象

□ 活动对象:针对函数,在调用函数时产生,由其this、arguments和其它命名参数初始化(函数内定义的变量)

□ 变量对象:执行环境中定义的所有变量和函数。

□ 作用域链:作用域链中,保存各级变量对象。

◇ 当调用一般函数时,变量对象是函数的活动对象。

◇ 当调用对象方法函数时,变量对象是该对象的属性和方法及函数本身的活动对象。

5)内存泄露:页面关闭后,仍保存着不必要的对象信息。

□ IE对JScript对象和COM对象使用不同的垃圾收集例程。

□ 当js原生对象与COM对象产生循环引用,在IE中将永远无法回收COM对象。

□ 内存泄露原因:发生循环引用后,js对象中对DOM的引用需要在DOM对js对象引用释放后才释放,这导致DOM对象引用数永不为0,DOM对象内存无法回收,发生内存泄露。

3. 模仿块级作用域

□ 语法如下:

(function(){

//这里是块级作用域

})();

□ 这种技术经常在全局作用域中被用在函数外部,从而限制全局作用域中添加过多的变量和函数。

4. 私有变量

①基本概念:

□ 似有变量:任何在函数中定义的变量,都可以认为是似有变量。

□ 特权方法:有权访问似有变量和似有函数的共有方法。

②构造函数中定义特权方法:

function MyObject(){

//函数的私有变量

var privateVariable = 10;

function privateFunction(){

Return flase;

}

//特权方法

this.publicMethod = function(){

private Variable ++;

return privateFunction();

};

}

③静态似有变量

□ 私有作用域中定义私有变量或函数,同样可以创建特权方法。

□ 定义全局变量构造函数,用以提供特权方法。

(function(){

//私有变量和似有函数

Var privateVariable = 10;

Function privateFunction(){

Return false;

}

//构造函数

MyObject = function(){

};

//公有或特权方法

MyObject.prototype.publicMethod = function(){

privateVariable ++;

return privateFunction();

};

})();

④模块模式:为单例创建似有变量和特权方法。

单例:JavaScript是以对象字面量的方式创建单例对象的。

var singleton = {

Name : value,

Method : function(){

//code

}

};

模块模式实例:

var singleton = function(){

//私有变量和私有函数

var privateVariable = 10;

function privateFunction(){

return false;

}

//特权或公有方法和属性

return {

publicProperty : true,

publicMethod : function(){

privateVariable ++;

Return privaeFunction();

}

};

}();

⑤增强的模块模式:

□ 适合:单例必须是某种类型的实例,同时还必须添加某些属性和(或)方法对其加以增强的情况。

var singleton = function(){

//私有变量和私有函数

var privateVariable = 10;

function privateFunction(){

Return false;

}

//创建对象

var object = new CustomType();

//添加特权/公有属性和方法

object.publicProperty = true;

object.publicMethod = function(){

privateVariable ++;

return privateFunction();

};

//返回这个对象

return object;

}();

你可能感兴趣的:(JavaScript)