摘抄高程的归纳笔记
《Javascript 高级程序设计》
Javascript 专门为网页交互而设计的语言
- ECMAScript
- 文档对象模型
DOM - 浏览器对象模型
BOM
在HTML中使用Javascript
-
<script />元素async:可选,异步加载javascript,只支持外部脚本文件charset: 可选,指定代码的字符集defer: 可选,立即下载,但是推迟到文档完成被解析显示之后再执行,只对外部脚本文件src: 脚本文件路径type:text/javascript,表示代码使用的脚本语言内容类型
-
位置
一般来说放在<head />中,但是如果js文件较大,执行耗时较长,放在头部,将会影响下面内容的解析和显示,会有明显的空白和延迟。因此,目前基本都放在<body />里面最下面 -
如何在
XHTML中运行
由于XHTML比HTML更加严格,对于js来说会运行错误
比如会将<当做开始一个新标签来解析,所以可以使用HTML实体替换(<), 但是这样又不好理解了
通过外部文件可以正常运行
也可以通过CData片段来包裹js, 但是很多浏览器不兼容XHTML,所以不支持CDATA,因此将CDATA标记注释就行<script type="text/javascript"> // <![CDATA[ // xxxxxx // ]]> </script>
基本概念
-
区分大小写
-
标识符
第一个字符为字母/下划线(_)/美元符号($) -
严格模式
user strict
消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为; 比如未声明的变量进行赋值,严格模式下抛出ReferenceError错误 -
变量
变量是松散型的,也就是可以来保存任何类型的数据,每个变量仅仅是一个内存的占位符。
省略了var,就是全局变量 -
数据类型
有5中基本数据类型(简单数据类型):Undefined,Null,Boolean,Number,String还有一种复杂的数据类型:Object-
typeof操作符
检测数据类型var message = true console.log(typeof message) // Boolean console.log(typeof(message)) // Boolean console.log(typeof 95) // Number console.log(typeof null) // Object console.log(typeof undefined) // undefined -
Undefined类型
当一个变量声明却未赋值的时候,这个变量的值就是undefined
对未声明变量的进行typeof检测,也是undefinedvar message; console.log(message) // undefined console.log(age) // 报错var message; console.log(typeof message) // undefined console.log(type of age) // undefined -
Null类型
null值表示一个空对象的指针,因此typeof操作符检测null值会返回object类型var car = null console.log(typeof car) // object如果定义的变量准备在将来用于保存对象,那么最好将变量初始化为
null,而不是其他值,这样,只要检查null就知道相应的变量是否已经保存了一个对象的引用if (car != null) { //对car对象执行某些操作 } -
undefined,null的关系undefined == null返回true- 无论在什么情况下,没有必要将变量的值显式的设置为
undefined - 准备保存对象的变量还没有真正保存对象的时候,应该明确该变量保存
null
-
Number类型Number.MIN_VALUE获取最小值Number.MAX_VALUE获取最大值- 如果计算得到的值超出了这个返回,将会得到
Infinity无穷 - 可通过
isFinite(value)检测是否超出范围 NaN,非数值,任何数值除以0会返回NaN,因此不会影响其他代码执行,NaN与任何值都不相等,包括自身isNaN(),判断是否不是数值Number(),
Number(true) // 1 Number(false) // 0 Number(null) // 0 Number(undefined) // NaN Number('') // 0 Number('十六进制') // 十进制 Number('hello world') // NaN Number('123') // 123 Number('094') // 94 Number(0.1) // 0.1 -
String类型
数值,布尔值,对象和字符串值,都有toString()方法,但是null,undefined没有这个方法
toString('基数'),可以传一个基数:十进制,二进制,八进制,十六进制等其他有效进制格式
对于null,undefined,可以使用String(),这个函数可以将任何类型的值转换为字符串,对于null,undefined则返回字面量 -
Object类型
每个对象的实例都有下列属性和方法Constructor保存着用于创建当前对象的函数,构造函数(constructor)就是Object()hasOwnProperty(propertyName)检查给定的属性在当前对象实例中(不是在实例的原型中)是否存在isPrototypeOf(object)检查传入的对象是否是另一个对象的原型propertyIsEnumerable(propertyName)检查给定的属性是否能够使用for-in语句toLocalString()返回对象的字符串表示toString()返回对象的字符串表示valueOf()返回对象的字符串、数值或布尔值,通常和toString()返回的值相同
-
-
操作符
-
一元操作符
--++
var a = 0; a++ ++a b-- --b -
位操作符 太复杂
-
布尔操作符
!逻辑非&&逻辑与,如果有一个是null,NaN,undefined,则返回null,NaN,undefined||逻辑或,如果两个都是null,NaN,undefined,则返回null,NaN,undefined
-
乘性操作符
NaN * 2 // NaN Infinity * 0 // NaN Infinity * 2 // Infinity Infinity * Infinity // Infinity NaN / 2 // NaN Infinity / Infinity // NaN 0 / 0 // NaN 0 / 2 // 0 2 / 0 // Infinity Infinity % Infinity // NaN Infinity % 0 // NaN 2 % Infinity // 2 3 % Infinity // 3 2 % 0 // NaN 0 % 2 // 0 -
加性操作符
- 加法
- 如果操作数是字符串,那么就是拼接在一起。
- 如果有一个操作数是对象、数值或者布尔值,则调用
toString()获取相应的字符串值
- 减法
- 如果有一个操作符是字符串、布尔值、
null或者undefined,则调用Number()函数转为数值,然后执行减法,如果转换的结果为NaN,则减法结果就是NaN - 如果有一个操作数是对象,则调用
valueOf(),取得表示该对象的数值,如果得到的值是NaN,那么结果就是NaN, 如果对象没有valueOf(),则调用toString()得到字符串值再转为数值
- 如果有一个操作符是字符串、布尔值、
- 加法
-
关系操作符
<><=>=
'23' < '3' // true '23' < 3 // false NaN < 3 // false NaN >= 3 // false 'a' < 3 // false -
相等操作符
- 如果又一个操作数是布尔值,则在比较相等性之前先将其转换为数值, false为0,true为1
- 如果一个操作数是字符串,另一个操作数是数值,在比较相等性之前先将字符串转为数值
- 如果一个操作数是对象,另一个操作数不是,则调用对象的valueOf()方法,用得到的基本类型值按照前面的规则进行比较 遵循的规则:
null和undefined是不相等的- 要比较相等性之前,不能将
null和undefined转换成其他任何值 - 如果有一个操作数是
NaN, 则相等操作符返回false,而不像等操作符返回true - 如果两个操作数都是对象,则比较他们是不是同一个对象,指向同一个对象,就相等,否则不相等 全等和不全等,将对类型进行比较,不同类型不相等,相等类型再进行值比较
-
条件操作符
-
赋值操作符
-
逗号操作符
-
-
语句
ifdo-while,后测试循环一句,代码至少被执行一次while,前测试循环语句for,灵活for-in,精准的迭代语句,枚举对象属性label,再代码中添加标签,以便将来使用break / continuewith,将代码的作用域设置到一个特定的对象中,严格模式下不允许使用with,否则会视为语法错误switch
-
函数 严格模式对函数有一些限制:
- 不能把函数命名为
eval或者arguments - 不能把参数命名为
eval或者arguments - 不能出现两个命名参数同名的情况
- 不能把函数命名为
-
理解参数
arguments对象只是与数组类似(并不是Array的实例),因此可以使用方括号访问内部元素没有重载,后定的变量或者方法,会覆盖替换前面定义的变量或方法
变量,作用域和内存问题
-
ECMAScript变量可能包含两种不同数据类型的值:基本类型值和引用类型值引用类型值又称为
Object类型,Object类型又可以划分为:Object,Array,Date,RegExp,Function等-
基本类型复制 一个变量向另一个变量复制基本类型的值,会在变量对象上创建一个新值,然后把该值复制到新变量分配的位置上。两个变量相互对立,互不影响
-
引用类型复制
一个变量向另一个变量复制引用类型的值,会在变量对象上创建一个指针,指向存储在堆中的一个对象,两个变量实际上引用的是同一个对象,因此改变一个变量,会改变另一个变量 -
传递参数 ECMAScript中所有的函数的参数都是按值传递的。基本类型将值复制给函数中的一个局部变量,引用类型将内存的地址复制给函数的局部变量。
-
-
执行环境以及作用域 在
WEB浏览器中,全局执行环境既windows对象
使用var声明的变量会被自动添加到最接近的环境中。// 此时name的局部环境就是全局环境,window if(true) { var name = '123' } console.log(name) // url的局部环境是getUrl,而不是with function getUrl () { with(location) { var url = href } console.log(url) // location.href } -
垃圾收集
Javascript具有自动垃圾收集机制。一般来说,没有被引用的对象就属于垃圾
标记清除标记-清除 原理:javasript运行的时候,垃圾回收机制会将内存中的变量进行标记,然后去掉环境中的变量以及被引用的变量的标记。等变量离开环境的时候,又被标记一次。此次被标记的就是要被删除的
将全局变量主动设置为null,释放引用。
-
注意
- 基本类型值保存在栈内存中,引用类型值保存在堆内存中
typeof操作符判断基本类型,instanceof判断那种引用类型- 执行环境分全局执行环境,和函数执行环境
引用类型
引用类型的值(对象)是引用类型的一个实例
引用类型是一种数据结构
-
Object类型 -
Array类型- 检测
value instanceof ArrayArray.isArray(value)
- 转换
alert()toString()valueOf()join(',')toLocalString()如果某一项的值为null或者是undefined,那么该值在上面五个方法返回的结果都以空字符串表示
- 栈方法
栈是一种
Last-In-First-Out后进先出的数据结构,最新插入的最早被移除,而栈中项的插入叫推入,移除叫弹出push(),在数组后加n项pop(),移除数组后一项
- 队列方法
栈数据结构的访问规则是
Fisrt-In-First-Out先进先出,在列表的末端添加项,从列表前端移除项。shift(),移除数组前一项unshift(), 在数组前加n项
- 重排序方法
reserve(), 反转数组顺序sort(), 接收两个参数进行比较var v = [2, 4, 6, 10] v.sort((a, b) => { // 如果第一个参数应该位于第二个参数之前,则返回一个负数 // 如果第一个参数应该位于第二个参数之后,则返回一个正数 // 如果相等,则为0 // 升序 if(a < b) { return -1 } else if(a > b) { return 1 } else { return 0 } // 降序 if(a < b) { return 1 } else if(a > b) { return -1 } else { return 0 } // or 简单 return a - b })
- 操作方法
concat()var colors = ["red", "green", "blue"]; var colors2 = colors.concat("yellow", ["black", "brown"]); alert(colors); //red,green,blue alert(colors2); //red,green,blue,yellow,black,brownslice()var colors = ["red", "green", "blue", "yellow", "purple"]; var colors2 = colors.slice(1); var colors3 = colors.slice(1,4); alert(colors2); //green,blue,yellow,purple alert(colors3); //green,blue,yellowsplice()删除,插入,替换var colors = ["red", "green", "blue"]; var removed = colors.splice(0,1); // 删除第一项 alert(colors); // green,blue alert(removed); // red,返回的数组中只包含一项 removed = colors.splice(1, 0, "yellow", "orange"); // 从位置 1 开始插入两项 alert(colors); // green,yellow,orange,blue alert(removed); // 返回的是一个空数组 removed = colors.splice(1, 1, "red", "purple"); // 插入两项,删除一项 alert(colors); // green,red,purple,orange,blue alert(removed); // yellow,返回的数组中只包含一项
- 位置方法
indexOf()lastIndexOf()
var numbers = [1,2,3,4,5,4,3,2,1]; alert(numbers.indexOf(4)); //3 alert(numbers.lastIndexOf(4)); //5 alert(numbers.indexOf(4, 4)); //5 alert(numbers.lastIndexOf(4, 4)); //3 var person = { name: "Nicholas" }; var people = [{ name: "Nicholas" }]; var morePeople = [person]; alert(people.indexOf(person)); //-1 alert(morePeople.indexOf(person)); //0 - 迭代方法
every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。filter():对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。forEach():对数组中的每一项运行给定函数。这个方法没有返回值。map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。some():对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。 以上方法都不会修改数组中的包含的值。函数接受的参数(项,位置,数组本身)
- 归并方法
reducereduceRight这两个方法都接收两个参数:一个在每一项上调用的函数和(可选的)作为归并基础的初始值。传给reduce()和reduceRight()的函数接收 4 个参数:前一个值、当前值、项的索引和数组对象。这个函数返回的任何值都会作为第一个参数自动传给下一项。第一次迭代发生在数组的第二项上,因此第一个参数是数组的第一项,第二个参数就是数组的第二项。
var sum = values.reduce(function(prev, cur, index, array){ return prev + cur; }); alert(sum); //15 var sum = values.reduceRight(function(prev, cur, index, array){ return prev + cur; }); alert(sum); //15
- 检测
-
Date类型-
Date.parse(), 法接收一个表示日期的字符串参数,然后尝试根据这个字符串返回相应日期的毫秒数 -
Date.UTC(), 同样也返回表示日期的毫秒数。参数分别是年份、基于 0 的月份(一月是 0,二月是 1,以此类推)、月中的哪一天(1 到 31)、小时数(0 到 23)、分钟、秒以及毫秒数。在这些参数中,只有前两个参数(年和月)是必需的 -
Date.now(), 返回表示调用这个方法时的日期和时间的毫秒数
- 格式化
- toDateString()——以特定于实现的格式显示星期几、月、日和年;
- toTimeString()——以特定于实现的格式显示时、分、秒和时区;
- toLocaleDateString()——以特定于地区的格式显示星期几、月、日和年;
- toLocaleTimeString()——以特定于实现的格式显示时、分、秒;
- toUTCString()——以特定于实现的格式完整的 UTC 日期。
与
toLocaleString()和toString()方法一样,以上这些字符串格式方法的输出也是因浏览器而异的,因此没有哪一个方法能够用来在用户界面中显示一致的日期信息。
-
-
RegExp类型-
flags标志
g:表示全局(global)模式,即模式将被应用于所有字符串,而非在发现第一个匹配项时立即停止;i:表示不区分大小写(case-insensitive)模式,即在确定匹配项时忽略模式与字符串的大小写;m:表示多行(multiline)模式,即在到达一行文本末尾时还会继续查找下一行中是否存在与模式匹配的项。
-
实例属性
- RegExp 的每个实例都具有下列属性,通过这些属性可以取得有关模式的各种信息。
- global:布尔值,表示是否设置了 g 标志。
- ignoreCase:布尔值,表示是否设置了 i 标志。
- lastIndex:整数,表示开始搜索下一个匹配项的字符位置,从 0 算起。
- multiline:布尔值,表示是否设置了 m 标志。
- source:正则表达式的字符串表示,按照字面量形式而非传入构造函数中的字符串模式返回。
-
实例方法
主要方法:exec()
接受一个参数,即要应用模式的字符串,然后返回包含第一个匹配项信息的数组;或者在没有匹配项的情况下返回 null。返回的数组虽然是 Array 的实例,但包含两个额外的属性:index 和 input。其中,index 表示匹配项在字符串中的位置,而 input 表示应用正则表达式的字符串。在数组中,第一项是与整个模式匹配的字符串,其他项是与模式中的捕获组匹配的字符串(如果模式中没有捕获组,则该数组只包含一项) -
构造函数属性
-
模式的局限性
-
-
Function类型-
函数内部属性
thisargumentscallee, 该属性是一个指针,指向拥有这个arguments对象的函数function factorial(num){ if (num <=1) { return 1; } else { return num * arguments.callee(num-1) } }caller, 这个属性中保存着调用当前函数的函数的引用,如果是在全局作用域中调用当前函数,它的值为null。严格模式下,这个属性始终是undefinedfunction outer(){ inner(); } function inner(){ alert(inner.caller); } outer(); // 还可以 alert(arguments.callee.caller);访问更上层
-
函数属性和方法 每个函数都包含两个属性:
length和prototype。function sayName(name){ alert(name); } function sum(num1, num2){ return num1 + num2; } function sayHi(){ alert("hi"); } alert(sayName.length); //1 alert(sum.length); //2 alert(sayHi.length); //0apply(),call()和bind(), 作用都一样,改变this指向。applay,第二个参数传的是数组call,是将参数逐个传进去,逗号分割bind,也是逐个传参,但是返回的是一个函数
-
-
基本包装类型 尽量别使用这三个 提供了3个特殊的引用类型:
Boolean、Number和String// 按理说,基本类型不应该有方法,但是确实可以执行读取值。 var s1 = "some text"; var s2 = s1.substring(2); // 当第二行代码访问 s1 时,访问过程处于一种读取模式,也就是要从内存中读取这个字符串的值。而在读取模式中访问字符串时,后台都会自动完成下列处理。 // 实际步骤如下: // 这下面的步骤,是后台自动完成的 var s1 = new String('some text') var s2 = s1.substring(2) s1 = nullString类型
- 字符方法
charAt() - 字符串操作方法
- concat()
- slice()
- substr()
- substring() 上面四种不会修改字符串本身,只是返回一个基本类型的字符串值,对原始的没有影响
var stringValue = "hello "; var result = stringValue.concat("world"); alert(result); //"hello world" alert(stringValue); //"hello" var stringValue = "hello world"; alert(stringValue.slice(3)); //"lo world" alert(stringValue.substring(3)); //"lo world" alert(stringValue.substr(3)); //"lo world" alert(stringValue.slice(3, 7)); //"lo w" 第二个参数指定的是子字符串最后一个字符后面的位置 alert(stringValue.substring(3,7)); //"lo w" 第二个参数指定的是子字符串最后一个字符后面的位置 alert(stringValue.substr(3, 7)); //"lo worl" 第二个参数指定的是要返回的字符个数 // 在给 slice()和 substr()传递一个负值参数时,它们的行为相同。这是因为-3 会被转换为 8(字符串长度加参数 11+(3)=8),实际上相当于调用了 slice(8)和 substr(8)。但 substring()方法则返回了全部字符串,因为它将-3 转换成了 0。 // 当第二个参数是负值时,这三个方法的行为各不相同。slice()方法会把第二个参数转换为 7,这就相当于调用了 slice(3,7),因此返回"lo w"。substring()方法会把第二个参数转换为 0,使调用变成了 substring(3,0),而由于这个方法会将较小的数作为开始位置,将较大的数作为结束位置,因此最终相当于调用了 substring(0,3)。substr()也会将第二个参数转换为 0,这也就意味着返回包含零个字符的字符串,也就是一个空字符串。 var stringValue = "hello world"; alert(stringValue.slice(-3)); //"rld" alert(stringValue.substring(-3)); //"hello world" alert(stringValue.substr(-3)); //"rld" alert(stringValue.slice(3, -4)); //"lo w" alert(stringValue.substring(3, -4)); //"hel" alert(stringValue.substr(3, -4)); //""(空字符串) - 字符串位置方法
indexOf()lastIndexOf()
一个字符串中搜索给定的子字符串,然后返子字符串的位置(如果没有找到该子字符串,则返回-1)
trim()支持这个方法的浏览器有 IE9+、Firefox 3.5+、Safari 5+、Opera 10.5+和 Chrome
Firefox 3.5+、Safari 5+ 和 Chrome 8+还支持非标准的 trimLeft()和 trimRight()方法- 字符串大小写转换方法
toLowerCase()toUpperCase()toLocaleLowerCase()toLocaleUpperCase()
- 字符串的模式匹配方法
-
match()
方法只接受一个参数,要么是一个正则表达式,要么是一个 RegExp 对象var text = "cat, bat, sat, fat"; var pattern = /.at/; //与 pattern.exec(text)相同 var matches = text.match(pattern); alert(matches.index); //0 alert(matches[0]); //"cat" alert(pattern.lastIndex); //0 -
search()
这个方法的唯一参数与match()方法的参数相同:由字符串或RegExp对象指定的一个正则表达式。search()方法返回字符串中第一个匹配项的索引;如果没有找到匹配项,则返回-1。而且,search()方法始终是从字符串开头向后查找模式。var text = "cat, bat, sat, fat"; var pos = text.search(/at/); alert(pos); //1 -
replace()
这个方法接受两个参数:第一个参数可以是一个 RegExp 对象或者一个字符串(这个字符串不会被转换成正则表达式),第二个参数可以是一个字符串或者一个函数。如果第一个参数是字符串,那么只会替换第一个子字符串。要想替换所有子字符串,唯一的办法就是提供一个正则表达式,而且要指定全局(g)标志,如下所示。var text = "cat, bat, sat, fat"; var result = text.replace("at", "ond"); alert(result); //"cond, bat, sat, fat" result = text.replace(/at/g, "ond"); alert(result); //"cond, bond, sond, fond"字符序列 替换文本 $$ $ $& 匹配整个模式的子字符串。与RegExp.lastMatch的值相同 $' 匹配的子字符串之前的子字符串。与RegExp.leftContext的值相同 $` 匹配的子字符串之后的子字符串。与RegExp.rightContext的值相同 $n 匹配第n个捕获组的子字符串,其中n等于0~9。例如,2是匹配第二个捕获组的子字符串,以此类推。如果正则表达式中没有定义捕获组,则使用空字符串 $nn 匹配第nn个捕获组的子字符串,其中nn等于01~99。例如,02是匹配第二个捕获组的子字符串,以此类推。如果正则表达式中没有定义捕获组,则使用空字符串 var text = "cat, bat, sat, fat"; result = text.replace(/(.at)/g, "word ($1)"); alert(result); //word (cat), word (bat), word (sat), word (fat)replace()方法的第二个参数也可以是一个函数 。在只有一个匹配项(即与模式匹配的字符串)的情况下,会向这个函数传递 3 个参数:模式的匹配项、模式匹配项在字符串中的位置和原始字符串。在正则表达式中定义了多个捕获组的情况下,传递给函数的参数依次是模式的匹配项、第一个捕获组的匹配项、第二个捕获组的匹配项……,但最后两个参数仍然分别是模式的匹配项在字符串中的位置和原始字符串。这个函数应该返回一个字符串,表示应该被替换的匹配项使用函数作为 replace()方法的第二个参数可以实现更加精细的替换操作
function htmlEscape(text){ return text.replace(/[<>"&]/g, function(match, pos, originalText){ switch(match){ case "<": return "<"; case ">": return ">"; case "&": return "&"; case "\"": return """; } }); } alert(htmlEscape("<p class=\"greeting\">Hello world!</p>")); //<p class="greeting">Hello world!</p> -
split()
方法可以接受可选的第二个参数,用于指定数组的大小,以便确保返回的数组不会超过既定大小var colorText = "red,blue,green,yellow"; var colors1 = colorText.split(","); //["red", "blue", "green", "yellow"] var colors2 = colorText.split(",", 2); //["red", "blue"] var colors3 = colorText.split(/[^\,]+/); //["", ",", ",", ",", ""] -
localeCompare()
法比较两个字符串- 如果字符串在字母表中应该排在字符串参数之前,则返回一个负数(大多数情况下是-1,具体的值要视实现而定);
- 如果字符串等于字符串参数,则返回 0;
- 如果字符串在字母表中应该排在字符串参数之后,则返回一个正数(大多数情况下是 1,具体的值同样要视实现而定)。
var stringValue = "yellow"; alert(stringValue.localeCompare("brick")); //1 alert(stringValue.localeCompare("yellow")); //0 alert(stringValue.localeCompare("zoo")); //-1 -
fromCharCode()
这个方法的任务是接收一或多个字符编码,然后将它们转换成一个字符串。从本质上来看,这个方法与实例方法 charCodeAt()执行的是相反的操作alert(String.fromCharCode(104, 101, 108, 108, 111)); //"hello"
-
- 字符方法
-
单体内置对象
-
Global对象
isNaN()、isFinite()、parseInt()以及parseFloat(),实际上全都是Global对象的方法-
URI编码方法encodeURI()使用encodeURI()编码后的结果是除了空格之外的其他字符都原封不动,只有空格被替换成了%20encodeURIComponent()
而encodeURIComponent()方法则会使用对应的编码替换所有非字母数字字符。decodeURI()
decodeURI()只能对使用encodeURI()替换的字符进行解码decodeURIComponent()
decodeURIComponent()能够解码使用encodeURIComponent()编码的所有字符,即它可以解码任何特殊字符的编码
var uri = "http://www.wrox.com/illegal value.htm#start"; //"http://www.wrox.com/illegal%20value.htm#start" alert(encodeURI(uri)); //"http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start" alert(encodeURIComponent(uri)); var uri = "http%3A%2F%2Fwww.wrox.com%2Fillegal%20value.htm%23start"; //http%3A%2F%2Fwww.wrox.com%2Fillegal value.htm%23start alert(decodeURI(uri)); //http://www.wrox.com/illegal value.htm#start alert(decodeURIComponent(uri)); -
eval()
eval()方法就像是一个完整的ECMAScript解析器,它只接受一个参数,即要执行的ECMAScript(或JavaScript)字符串
Global 对象的属性
属性 说明 属性 说明 undefined 特殊值undefined Date 构造函数Date NaN 特殊值NaN RegExp 构造函数RegExp Infinity 特殊值Infinity Error 构造函数Error Object 构造函数Object EvalError 构造函数EvalError Array 构造函数Array RangeError 构造函数RangeError Function 构造函数Function ReferenceError 构造函数ReferenceError Boolean 构造函数Boolean SyntaxError 构造函数SyntaxError String 构造函数String TypeError 构造函数TypeError Number 构造函数Number URIError 构造函数URIError -
-
window对象,扮演者Global对象 -
Math对象-
对象的属性
属 性 说 明 Math.E 自然对数的底数,即常量e的值 Math.LN10 10的自然对数 Math.LN2 2的自然对数 Math.LOG2E 以2为底e的对数 Math.LOG10E 以10为底e的对数 Math.PI π的值 Math.SQRT1_2 1/2的平方根(即2的平方根的倒数) Math.SQRT2 2的平方根 -
方法
- min()
- max()
- ceil(),执行向上舍入,即它总是将数值向上舍入为最接近的整数
- floor(),执行向下舍入,即它总是将数值向下舍入为最接近的整数
- round(),执行标准舍入,即它总是将数值四舍五入为最接近的整数
- random(),返回大于等于 0 小于 1 的一个随机数
方 法 说 明 Math.abs(num) 返回num 的绝对值 Math.exp(num) 返回Math.E 的num 次幂 Math.log(num) 返回num 的自然对数 Math.pow(num,power) 返回num 的power 次幂 Math.sqrt(num) 返回num 的平方根 Math.asin(x) 返回x 的反正弦值 Math.atan(x) 返回x 的反正切值 Math.atan2(y,x) 返回y/x 的反正切值 Math.cos(x) 返回x 的余弦值 Math.sin(x) 返回x 的正弦值 Math.acos(x) 返回x 的反余弦值 Math.tan(x) 返回x 的正切值
-
-
面向对象的程序设计
每个对象都是基于一个引用类型创建的
-
理解对象:
-
属性类型
-
数据属性
数据属性包含一个数据值的位置。在这个位置可以读取和写入值。数据属性有 4 个描述其行为的特性[[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true。[[Enumerable]]:表示能否通过for-in循环返回属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true[[Writable]]:表示能否修改属性的值。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为true[[Value]]:包含这个属性的数据值。读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。这个特性的默认值为undefined
要修改属性默认的特性,必须使用
ECMAScript 5的Object.defineProperty()方法var person = {}; Object.defineProperty(person, "name", { writable: false, value: "Nicholas" }); alert(person.name); //"Nicholas" person.name = "Greg"; alert(person.name); //"Nicholas" -
访问器属性
访问器属性不能直接定义,必须使用Object.defineProperty()来定义[[Get]]:在读取属性时调用的函数。默认值为undefined[[Set]]:在写入属性时调用的函数。默认值为undefined
// 在这个方法之前,要创建访问器属性,使用 __defineSetter__() 和 __defineGetter__() 代替 var book = { _year: 2004, edition: 1 }; Object.defineProperty(book, "year", { get: function(){ return this._year; }, set: function(newValue){ if (newValue > 2004) { this._year = newValue; this.edition += newValue - 2004; } } }); book.year = 2005; alert(book.edition); //2
-
-
定义多个属性
Object.defineProperties()方法。利用这个方法可以通过描述符一次定义多个属性。这个方法接收两个对象参数:第一个对象是要添加和修改其属性的对象,第二个对象的属性与第一个对象中要添加或修改的属性一一对应 -
读取属性的特性
Object.getOwnPropertyDescriptor(), 取得给定属性的描述符。接收两个参数:属性所在的对象和要读取其描述符的属性名称
-
-
创建对象
-
工厂模式:用函数来封装以特定接口创建对象的细节
function createPerson(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, "Software Engineer"); var person2 = createPerson("Greg", 27, "Doctor"); -
构造函数模式
- 创建一个新对象;
- 将构造函数的作用域赋给新对象(因此
this就指向了这个新对象); - 执行构造函数中的代码(为这个新对象添加属性);
- 返回新对象
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, "Software Engineer"); var person2 = new Person("Greg", 27, "Doctor"); alert(person1.constructor == Person); //true alert(person2.constructor == Person); //true alert(person1 instanceof Object); //true alert(person1 instanceof Person); //true alert(person2 instanceof Object); //true alert(person2 instanceof Person); //true -
原型模式 原型对象的好处是可以让所有对象实例共享它所包含的属性和方法
// 与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享的 function Person(){} Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; var person1 = new Person(); person1.sayName(); //"Nicholas" var person2 = new Person(); person2.sayName(); //"Nicholas" alert(person1.sayName == person2.sayName); //true alert(Person.prototype.isPrototypeOf(person1)); //true alert(Person.prototype.isPrototypeOf(person2)); //true alert(Object.getPrototypeOf(person1) == Person.prototype); //true alert(Object.getPrototypeOf(person1).name); //"Nicholas"hasOwnProperty()检测一个属性是否存在于实例中,是就返回truein检测一个属性只要能访问到,就返回true,不论在实例中,还是在原型中for-in循环时,返回所有能够访问的,可枚举的,包括实例中与原型中的属性Object.keys()接收一个对象作为参数,返回一个包含所有可枚举属性的字符串数组Object.getOwnPropertyNames()得到所有实例属性,无论它是否可枚举
// 同时使用 hasOwnProperty()方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中 function hasPrototypeProperty(object, name){ return !object.hasOwnProperty(name) && (name in object); } -
动态原型模式 即在构造函数中,通过判断类型,来给原型添加属性
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); }; } } var friend = new Person("Nicholas", 29, "Software Engineer"); friend.sayName(); -
寄生构造函数模式 这个模式可以在特殊的情况下用来为对象创建构造函数。假设我们想创建一个具有额外方法的特殊数组。由于不能直接修改 Array 构造函数,因此可以使用这个模式
function SpecialArray(){ //创建数组 var values = new Array(); //添加值 values.push.apply(values, arguments); //添加方法 values.toPipedString = function(){ return this.join("|"); }; //返回数组 return values; } var colors = new SpecialArray("red", "blue", "green"); alert(colors.toPipedString()); //"red|blue|green" -
稳妥构造函数模式
稳妥构造函数遵循与寄生构造函数类似的模式,但有两点不同:一是新创建对象的实例方法不引用this;二是不使用new操作符调用构造函数function Person(name, age, job){ //创建要返回的对象 var o = new Object(); //可以在这里定义私有变量和函数 //添加方法 o.sayName = function(){ alert(name); }; //返回对象 return o; }
-
-
继承 许多 OO 语言都支持两种继承方式:接口继承和实现继承
ECMAScript 只支持实现继承,而且其实现继承主要是依靠原型链来实现的-
原型链
function SuperType(){ this.property = true; } SuperType.prototype.getSuperValue = function(){ return this.property; }; function SubType(){ this.subproperty = false; } //继承了 SuperType SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function (){ return this.subproperty; }; var instance = new SubType(); alert(instance.getSuperValue()); //true存在的问题:
function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){} //继承了 SuperType SubType.prototype = new SuperType(); var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green,black" -
借用构造函数
// example1 function SuperType(){ this.colors = ["red", "blue", "green"]; } function SubType(){ //继承了 SuperType SuperType.call(this); } var instance1 = new SubType(); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green" // example2 function SuperType(name){ this.name = name; } function SubType(){ //继承了 SuperType,同时还传递了参数 SuperType.call(this, "Nicholas"); //实例属性 this.age = 29; } var instance = new SubType(); alert(instance.name); //"Nicholas"; alert(instance.age); //29 -
组合继承 将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式
思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又能够保证每个实例都有它自己的属性function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ //继承属性 SuperType.call(this, name); this.age = age; } //继承方法 SubType.prototype = new SuperType(); SubType.prototype.constructor = SubType; SubType.prototype.sayAge = function(){ alert(this.age); }; var instance1 = new SubType("Nicholas", 29); instance1.colors.push("black"); alert(instance1.colors); //"red,blue,green,black" instance1.sayName(); //"Nicholas"; instance1.sayAge(); //29 var instance2 = new SubType("Greg", 27); alert(instance2.colors); //"red,blue,green" instance2.sayName(); //"Greg"; instance2.sayAge(); //27 -
原型式继承
ECMAScript 5通过新增Object.create()方法规范化了原型式继承。这个方法接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的情况下,Object.create()与object()方法的行为相同function object(o){ function F(){} F.prototype = o; return new F(); } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = object(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = object(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie" var anotherPerson = Object.create(person); anotherPerson.name = "Greg"; anotherPerson.friends.push("Rob"); var yetAnotherPerson = Object.create(person); yetAnotherPerson.name = "Linda"; yetAnotherPerson.friends.push("Barbie"); alert(person.friends); //"Shelby,Court,Van,Rob,Barbie" var anotherPerson = Object.create(person, { name: { value: "Greg" } }); alert(anotherPerson.name); //"Greg" -
寄生式继承 寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象,最后再像真地是它做了所有工作一样返回对象
function createAnother(original){ var clone = object(original); //通过调用函数创建一个新对象 clone.sayHi = function(){ //以某种方式来增强这个对象 alert("hi"); }; return clone; //返回这个对象 } var person = { name: "Nicholas", friends: ["Shelby", "Court", "Van"] }; var anotherPerson = createAnother(person); anotherPerson.sayHi(); //"hi" -
寄生组合式继承
function inheritPrototype(subType, superType){ var prototype = object(superType.prototype); //创建对象 prototype.constructor = subType; //增强对象 subType.prototype = prototype; //指定对象 } function SuperType(name){ this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function(){ alert(this.name); }; function SubType(name, age){ SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, SuperType); SubType.prototype.sayAge = function(){ alert(this.age); };
-
函数表达式
定义函数有两种方式:函数声明,函数表达式
// 函数声明:特征就是函数声明提升
function functionName(arg0, arg1, arg2) {
// 函数体
}
// 函数表达式,这种方式创建的函数叫 匿名函数(拉姆达函数)
var functionName = function(arg1, arg2, arg3) {
// 函数体
}
-
递归
递归函数是在一个函数通过名字调用自身的情况下构成的function factorial(num){ if (num <= 1){ return 1; } else { return num * factorial(num-1); } } // 这是一个经典的递归阶乘函数。虽然这个函数表面看来没什么问题,但下面的代码却可能导致它出错 var anotherFactorial = factorial; factorial = null; alert(anotherFactorial(4)); //出错! // arguments.callee 可以解决这个问题 function factorial(num){ if (num <= 1){ return 1; } else { return num * arguments.callee(num-1); } } // 但在严格模式下,不能通过脚本访问 arguments.callee,访问这个属性会导致错误。不过,可以使用命名函数表达式来达成相同的结果 var factorial = (function f(num){ if (num <= 1){ return 1; } else { return num * f(num-1); } }); -
闭包 闭包是指有权访问另一个函数作用域中的变量的函数
function createComparisonFunction(propertyName) { return function(object1, object2){ var value1 = object1[propertyName]; var value2 = object2[propertyName]; if (value1 < value2){ return -1; } else if (value1 > value2){ return 1; } else { return 0; } }; }-
闭包与变量
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(){ return i; // 返回的都是10 }; } return result; } function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i++){ result[i] = function(num){ return function(){ return num; // 正常值 }; }(i); } return result; } -
thisvar name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; } }; alert(object.getNameFunc()()); //"The Window"(在非严格模式下) var name = "The Window"; var object = { name : "My Object", getNameFunc : function(){ var that = this; return function(){ return that.name; }; } }; alert(object.getNameFunc()()); //"My Object" -
内存泄漏
function assignHandler(){ var element = document.getElementById("someElement"); element.onclick = function(){ alert(element.id); }; } function assignHandler(){ var element = document.getElementById("someElement"); var id = element.id; element.onclick = function(){ alert(id); }; element = null; }
-
-
模仿块级作用域
(function(){ //这里是块级作用域 })(); function outputNumbers(count){ (function () { for (var i=0; i < count; i++){ alert(i); } })(); alert(i); //导致一个错误! } -
私有变量
任何在函数中定义的变量,都可以认为是私有变量,因为不能在函数的外部访问这些变量
把有权访问私有变量和私有函数的公有方法称为特权方法- 静态私有变量
(function(){ //私有变量和私有函数 var privateVariable = 10; function privateFunction(){ return false; } //构造函数 MyObject = function(){ }; //公有/特权方法 MyObject.prototype.publicMethod = function(){ privateVariable++; return privateFunction(); }; })(); - 模块模式
- 增强的模块模式
- 静态私有变量
Bom
BOM,浏览器对象模型
- window
locationhashhostnamehrefpathnameportportocolsearch
- navigator
- screen
historygobackforward
客户端检测
- 能力检测
- 怪癖检测
- 用户代理检测
navigator.userAgent
DOM
-
操作节点
var returnedNode = someNode.appendChild(newNode); alert(returnedNode == newNode); //true alert(someNode.lastChild == newNode); //true //someNode 有多个子节点 var returnedNode = someNode.appendChild(someNode.firstChild); alert(returnedNode == someNode.firstChild); //false alert(returnedNode == someNode.lastChild); //true //插入后成为最后一个子节点 returnedNode = someNode.insertBefore(newNode, null); alert(newNode == someNode.lastChild); //true //插入后成为第一个子节点 var returnedNode = someNode.insertBefore(newNode, someNode.firstChild); alert(returnedNode == newNode); //true alert(newNode == someNode.firstChild); //true //插入到最后一个子节点前面 returnedNode = someNode.insertBefore(newNode, someNode.lastChild); alert(newNode == someNode.childNodes[someNode.childNodes.length-2]); //true //替换第一个子节点 var returnedNode = someNode.replaceChild(newNode, someNode.firstChild); //替换最后一个子节点 returnedNode = someNode.replaceChild(newNode, someNode.lastChild); //移除第一个子节点 var formerFirstChild = someNode.removeChild(someNode.firstChild); //移除最后一个子节点 var formerLastChild = someNode.removeChild(someNode.lastChild); // clone var deepList = myList.cloneNode(true); alert(deepList.childNodes.length); //3 (IE < 9)或 7(其他浏览器) var shallowList = myList.cloneNode(false); alert(shallowList.childNodes.length); //0 -
attributegetAttributesetAttributeremoveAttribute
DOM扩展
querySelectorquerySelectorAllmatchesSelectorgetElementsByClassNameclassListhasFocusinnerHTMLouterHTMLinsertAdjacentHTMLscrollIntoViewchildrencontainsinnerTextouterTextscrollIntoViewscrollIntoViewIfNeededscrollByLinesscrollByPages
DOM2 DOM3
-
createElementNS -
createAttributeNS
-
getElementsByTagNameNS
-
getAttributeNS
-
getAttributeNodeNS
-
getElementsByTagNameNS
-
hasAttributeNS
-
removeAttriubteNS
-
setAttributeNS
-
setAttributeNodeNS
-
getNamedItemNS
-
removeNamedItemNS
-
setNamedItemNS
-
cssText
-
length
-
parentRule
-
getPropertyCSSValue
-
getPropertyPriority
-
getPropertyValue
-
item
-
removeProperty
-
setProperty
-
disabled
-
href
-
media
-
ownerNode
-
parentStyleSheet
-
title
-
type
-
cssRules
-
ownerRule
-
deleteRule
-
insertRule
《12.2.3 元素大小,有空看下》 34. offsetHeight 35. offsetWidth 36. offsetLeft 37. offsetTop
-
scrollHeight
-
scrollWidth
-
scrollLeft
-
scrollTop
-
getBoundingClientRect
-
parentNode
-
firstChild
-
lastChild
-
nextSibling
-
previousSibling
小结
- 每个元素都有一个关联的 style 对象,可以用来确定和修改行内的样式。
- 要确定某个元素的计算样式(包括应用给它的所有 CSS 规则),可以使用 getComputedStyle()方法。
- IE不支持 getComputedStyle()方法,但为所有元素都提供了能够返回相同信息 currentStyle属性。
- 可以通过 document.styleSheets 集合访问样式表。
- 除 IE 之外的所有浏览器都支持针对样式表的这个接口,IE 也为几乎所有相应的 DOM 功能提供了自己的一套属性和方法。
“DOM2 级遍历和范围”模块提供了与 DOM 结构交互的不同方式,简要总结如下。
- 遍历即使用 NodeIterator 或 TreeWalker 对 DOM 执行深度优先的遍历。
- NodeIterator 是一个简单的接口,只允许以一个节点的步幅前后移动。而 TreeWalker 在提供相同功能的同时,还支持在 DOM 结构的各个方向上移动,包括父节点、同辈节点和子节点等方向。
- 范围是选择 DOM 结构中特定部分,然后再执行相应操作的一种手段。
- 使用范围选区可以在删除文档中某些部分的同时,保持文档结构的格式良好,或者复制文档中的相应部分。
- IE8 及更早版本不支持“DOM2 级遍历和范围”模块,但它提供了一个专有的文本范围对象,可以用来完成简单的基于文本的范围操作。IE9 完全支持 DOM 遍历。
事件
-
事件冒泡,沿着
DOM树向上传播 -
事件捕获,沿着
DOM树向下传播DOM事件流- 事件捕获阶段
- 处于目标阶段
- 事件冒泡阶段
DOM0级事件处理程序被认为是元素的方法
btn.onclick = function(){}DOM2级事件处理程序- 定义了两个方法:处理指定和删除时间处理程序的操作;
addEventListener()removeEventListener()
- 接受 3 个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值
- 布尔值参数如果是
true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。不建议在事件捕获阶段注册事件处理程序 - 主要好处是可以添加多个事件处理程序
var btn = document.getElementById("myBtn"); btn.addEventListener("click", function(){ alert(this.id); }, false); btn.addEventListener("click", function(){ alert("Hello world!"); }, false);事件对象
event对象包含与创建它的特定事件有关的属性和方法。触发的事件类型不一样,可用的属性和方法也不一样。不过,所有事件都会有下表列出的成员bubbles Boolean 只读 表明事件是否冒泡 cancelable Boolean 只读 表明是否可以取消事件的默认行为 currentTarget Element 只读 其事件处理程序当前正在处理事件的那个元素 defaultPrevented Boolean 只读 为 true 表示已经调用了 preventDefault()(DOM3级事件中新增) detail Integer 只读 与事件相关的细节信息 eventPhase Integer 只读 调用事件处理程序的阶段:1表示捕获阶段,2表示“处于目标”,3表示冒泡阶段 preventDefault() Function 只读 取消事件的默认行为。如果cancelable是true,则可以使用这个方法 stopImmediatePropagation() Function 只读 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(DOM3级事件中新增) stopPropagation() Function 只读 取消事件的进一步捕获或冒泡。如果bubbles为true,则可以使用这个方法 target Element 只读 事件的目标 trusted Boolean 只读 为true表示事件是浏览器生成的。为false表示事件是由开发人员通过 JavaScript 创建的(DOM3级事件中新增) type String 只读 被触发的事件的类型 view AbstractView 只读 与事件关联的抽象视图。等同于发生事件的window对象 在事件处理程序内部,对象
this始终等于currentTarget的值,而target则只包含事件的实际目标。如果直接将事件处理程序指定给了目标元素,则this、currentTarget和target包含相同的值var btn = document.getElementById("myBtn"); btn.onclick = function(event){ alert(event.currentTarget === this); //true alert(event.target === this); //true }; document.body.onclick = function(event){ alert(event.currentTarget === document.body); //true alert(this === document.body); //true alert(event.target === document.getElementById("myBtn")); //true };在需要通过一个函数处理多个事件时,可以使用 type 属性。例如:
var btn = document.getElementById("myBtn"); var handler = function(event){ switch(event.type){ case "click": alert("Clicked"); break; case "mouseover": event.target.style.backgroundColor = "red"; break; case "mouseout": event.target.style.backgroundColor = ""; break; } }; btn.onclick = handler; btn.onmouseover = handler; btn.onmouseout = handler;事件类型
-
UI事件:当用户与页面上的元素交互时触发
DOMActivate,废弃load:当页面完全加载后在 window 上面触发,当所有框架都加载完毕时在框架集上面触发,当图像加载完毕时在元素上面触发,或者当嵌入的内容加载完毕时在元素上面触发。
unload:当页面完全卸载后在 window 上面触发,当所有框架都卸载后在框架集上面触发,或者当嵌入的内容卸载完毕后在元素上面触发。abort:在用户停止下载过程时,如果嵌入的内容没有加载完,则在元素上面触发。error:当发生 JavaScript 错误时在 window 上面触发,当无法加载图像时在元素上面触发,当无法加载嵌入内容时在元素上面触发,或者当有一或多个框架无法加载时在框架集上面触发。
select:当用户选择文本框(或)中的一或多个字符时触发resize:当窗口或框架的大小变化时在 window 或框架上面触发scroll:当用户滚动带滚动条的元素中的内容时,在该元素上面触发。元素中包含所加载页面的滚动条-
焦点事件:当元素获得或失去焦点时触发
blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它focus:在元素获得焦点时触发。这个事件不会冒泡;所有浏览器都支持它focusin:在元素获得焦点时触发。这个事件与 HTML 事件 focus 等价,但它冒泡focusout:在元素失去焦点时触发。这个事件是 HTML 事件 blur 的通用版本
当焦点从页面中的一个元素移动到另一个元素,会依次触发下列事件
focusout在失去焦点的元素上触发;focusin在获得焦点的元素上触发;blur在失去焦点的元素上触发;focus在获得焦点的元素上触发;
-
鼠标事件:当用户通过鼠标在页面上执行操作时触发
click: 在用户单击主鼠标按钮(一般是左边的按钮)或者按下回车键时触发dblclick: 在用户双击主鼠标按钮(一般是左边的按钮)时触发mousedown: 在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件mouseup: 在用户释放鼠标按钮时触发mouseenter: 在鼠标光标从元素外部首次移动到元素范围之内时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发mouseleave: 在位于元素上方的鼠标光标移动到元素范围之外时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发mousemove: 当鼠标指针在元素内部移动时重复地触发mouseout: 在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素mouseover: 在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。不能通过键盘触发这个事件
-
滚轮事件:当使用鼠标滚轮(或类似设备)时触发
-
文本事件:当在文档中输入文本时触发
-
键盘事件:当用户通过键盘在页面上执行操作时触发
-
合成事件:当为 IME(Input Method Editor,输入法编辑器)输入字符时触发
-
变动事件:当底层 DOM 结构发生变化时触发
-
DOMSubtreeModified: 在 DOM 结构中发生任何变化时触发。这个事件在其他任何事件触发后都会触发 -
DOMNodeInserted: 在一个节点作为子节点被插入到另一个节点中时触发 -
DOMNodeRemoved: 在节点从其父节点中被移除时触发 -
DOMNodeInsertedIntoDocument: 在一个节点被直接插入文档或通过子树间接插入文档之后触发。这个事件在 DOMNodeInserted 之后触发 -
DOMNodeRemovedFromDocument: 在一个节点被直接从文档中移除或通过子树间接从文档中移除之前触发。这个事件在 DOMNodeRemoved 之后触发 -
DOMAttrModified: 在特性被修改之后触发 -
DOMCharacterDataModified: 在文本节点的值发生变化时触发
-
- contextmenu
- beforeunload
- DOMContentLoaded
- readystatechange
- uninitialized
- loading
- loaded
- interactive
- complete
- pageshow & pagehide
- hashchange
- orientationchange: 移动 Safari 中添加了 orientationchange 事件,以便开发人员能够确定用户何时将设备由横向查看模式切换为纵向查看模式
- MozOrientation:当设备的加速计检测到设备方向改变时,就会触发这个事件。前缀 Moz 表示这是特定于浏览器开发商的事件
- deviceorientation:是在加速计检测到设备方向变化时在 window 对象上触发
- alpha:在围绕 z 轴旋转时(即左右旋转时),y 轴的度数差;是一个介于 0 到 360 之间的浮点数
- beta:在围绕 x 轴旋转时(即前后旋转时),z 轴的度数差;是一个介于180 到 180 之间的浮点数
- gamma:在围绕 y 轴旋转时(即扭转设备时),z 轴的度数差;是一个介于90 到 90 之间的浮点数
- absolute:布尔值,表示设备是否返回一个绝对值
- compassCalibrated:布尔值,表示设备的指南针是否校准过
- devicemotion:要告诉开发人员设备什么时候移动,而不仅仅是设备方向如何改变
- acceleration:一个包含 x、y 和 z 属性的对象,在不考虑重力的情况下,告诉你在每个方向上的加速度
- accelerationIncludingGravity:一个包含 x、y 和 z 属性的对象,在考虑 z 轴自然重力加速度的情况下,告诉你在每个方向上的加速度
- interval:以毫秒表示的时间值,必须在另一个 devicemotion 事件触发前传入。这个值在每个事件中应该是一个常量
- rotationRate:一个包含表示方向的 alpha、beta 和 gamma 属性的对象
-
触摸事件
touchstart:当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发touchmove:当手指在屏幕上滑动时连续地触发。在这个事件发生期间,调用preventDefault()可以阻止滚动touchend:当手指从屏幕上移开时触发touchcancel:当系统停止跟踪触摸时触发
触摸事件还包含下列三个用于跟踪触摸的属性
- touches:表示当前跟踪的触摸操作的 Touch 对象的数组
- targetTouchs:特定于事件目标的 Touch 对象的数组
- changeTouches:表示自上次触摸以来发生了什么改变的 Touch 对象的数组
每个 Touch 对象包含下列属性
- clientX:触摸目标在视口中的 x 坐标。
- clientY:触摸目标在视口中的 y 坐标。
- identifier:标识触摸的唯一 ID。 + pageX:触摸目标在页面中的 x 坐标。
- pageY:触摸目标在页面中的 y 坐标。
- screenX:触摸目标在屏幕中的 x 坐标。
- screenY:触摸目标在屏幕中的 y 坐标。
- target:触摸的 DOM 节点目标
-
手势事件 Safari 还引入了一组手势事件
- gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发
- gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发
- gestureend:当任何一个手指从屏幕上面移开时触发
HTML5 事件
设备事件
触摸与手势事件
模拟事件
createEvent()方法创建 event 对象 dispatchEvent()触发事件小结: 在使用事件时,需要考虑如下一些内存与性能方面的问题。
- 有必要限制一个页面中事件处理程序的数量,数量太多会导致占用大量内存,而且也会让用户感觉页面反应不够灵敏。
- 建立在事件冒泡机制之上的事件委托技术,可以有效地减少事件处理程序的数量。
- 建议在浏览器卸载页面之前移除页面中的所有事件处理程序。
高级技巧
-
安全的类型检测
// 在任何值上调用 Object 原生的 toString()方法,都会返回一个[object NativeConstructorName]格式的字符串 Object.prototype.toString.call(value) //"[object Array]" -
作用域安全的构造函数
function Person(name, age, job){ // 首先确认 this 对象是正确类型的实例 if (this instanceof Person){ this.name = name; this.age = age; this.job = job; } else { return new Person(name, age, job); } } -
惰性载入函数 个人理解,就是经常调用一个函数,函数里面一系列
if语句,每次调用都好性能。那么在一开始调用的时后将执行的语句再返给这个函数,那么下次函数调用的时候,就是已经判断过的函数 -
函数绑定
bind() -
函数柯里化
函数柯里化的基本方法和函数绑定是一样的:使用一个闭包返回一个函数,两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数 -
防篡改对象
-
Object.preventExtensions(),Object.isExtensible()
不能再给对象添加属性和方法,仍然还可以修改和删除已有的成员var person = { name: "Nicholas" }; Object.preventExtensions(person); person.age = 29; alert(person.age); //undefined // Object.istExtensible()方法还可以确定对象是否可以扩展 var person = { name: "Nicholas" }; alert(Object.isExtensible(person)); //true Object.preventExtensions(person); alert(Object.isExtensible(person)); //false -
Object.seal(),Object.isSealed()
密封对象不可扩展,而且已有成员的[[Configurable]]特性将被设置为false。这就意味着不能删除属性和方法,因为不能使用Object.defineProperty()把数据属性修改为访问器属性,或者相反。属性值是可以修改的var person = { name: "Nicholas" }; Object.seal(person); person.age = 29; alert(person.age); //undefined delete person.name; alert(person.name); //"Nicholas" // Object.isSealed()方法可以确定对象是否被密封了 var person = { name: "Nicholas" }; alert(Object.isExtensible(person)); //true alert(Object.isSealed(person)); //false Object.seal(person); alert(Object.isExtensible(person)); //false alert(Object.isSealed(person)); //true -
Object.freeze(),Object.isFrozen()
冻结对象,冻结的对象既不可扩展,又是密封的,而且对象数据属性的[[Writable]]特性会被设置为falsevar person = { name: "Nicholas" }; Object.freeze(person); person.age = 29; alert(person.age); //undefined delete person.name; alert(person.name); //"Nicholas" person.name = "Greg"; alert(person.name); //"Nicholas"
-
-
高级定时器
指定的时间间隔表示何时将定时器的代码添加到队列,而不是何时实际执行代码
使用setInterval时候,当定时器的循环的时间间隔小,但是定时器内部代码执行时间又长的情况下,会出现重复定时的情况。因此可以使用setTimeout链式调用setTimeout(function() { setTimeout(arguments.callee, interval) }, interval) -
函数节流 函数节流背后的基本思想是指,某些代码不可以在没有间断的情况连续重复执行
var processor = { timeoutId: null, //实际进行处理的方法 performProcessing: function(){ //实际执行的代码 }, //初始处理调用的方法 process: function(){ clearTimeout(this.timeoutId); var that = this; this.timeoutId = setTimeout(function(){ that.performProcessing(); }, 100); } }; //尝试开始执行 processor.process();
9: 自定义事件
小结:
- 可以使用惰性载入函数,将任何代码分支推迟到第一次调用函数的时候。
- 函数绑定可以让你创建始终在指定环境中运行的函数,同时函数柯里化可以让你创建已经填了某些参数的函数。
- 将绑定和柯里化组合起来,就能够给你一种在任意环境中以任意参数执行任意函数的方法。
ECMAScript 5 允许通过以下几种方式来创建防篡改对象。
- 不可扩展的对象,不允许给对象添加新的属性或方法。
- 密封的对象,也是不可扩展的对象,不允许删除已有的属性和方法。
- 冻结的对象,也是密封的对象,不允许重写对象的成员。
JavaScript 中可以使用 setTimeout()和 setInterval()如下创建定时器。
- 定时器代码是放在一个等待区域,直到时间间隔到了之后,此时将代码添加到 JavaScript 的处理队列中,等待下一次 JavaScript 进程空闲时被执行。
- 每次一段代码执行结束之后,都会有一小段空闲时间进行其他浏览器处理。
- 这种行为意味着,可以使用定时器将长时间运行的脚本切分为一小块一小块可以在以后运行的代码段。这种做法有助于 Web 应用对用户交互有更积极的响应。
JavaScript 中经常以事件的形式应用观察者模式。虽然事件常常和 DOM 一起使用,但是你也可以通过实现自定义事件在自己的代码中应用。使用自定义事件有助于将不同部分的代码相互之间解耦,让维护更加容易,并减少引入错误的机会。
拖放对于桌面和 Web 应用都是一个非常流行的用户界面范例,它能够让用户非常方便地以一种直观的方式重新排列或者配置东西。在 JavaScrip 中可以使用鼠标事件和一些简单的计算来实现这种功能 2 类型。将拖放行为和自定义事件结合起来可以创建一个可重复使用的框架,它能应用于各种不同的情 况下。HTML5脚本编程
- 跨文档传递消息 postMessage()
- 原生拖放
- 媒体元素
- 历史状态管理 history.pushState 等
小结 HTML5 除了定义了新的标记规则,还定义了一些 JavaScript API。这些API 是为了让开发人员创建出更好的、能够与桌面应用媲美的用户界面而设计的。本章讨论了如下 API。
- 跨文档消息传递 API 能够让我们在不降低同源策略安全性的前提下,在来自不同域的文档间传递消息。
- 原生拖放功能让我们可以方便地指定某个元素可拖动,并在操作系统要放置时做出响应。还可以创建自定义的可拖动元素及放置目标。
- 新的媒体元素和拥有自己的与音频和视频交互的 API。并非所有浏览器支持所有的媒体格式,因此应该使用 canPlayType()检查浏览器是否支持特定的格式。
- 历史状态管理让我们不必卸载当前页面即可修改浏览器的历史状态栈。有了这种机制,用户就可以通过“后退”和“前进”按钮在页面状态间切换,而这些状态完全由 JavaScript 进行控制。
离线应用与客户端存储
离线应用
- HTML5 的应用缓存(application cache)
存储
- cookie
- setAttribute, 在标签节点上保存数据
- storange
- IndexedDB
小结: 离线 Web 应用和客户端存储数据的能力对未来的 Web 应用越来越重要。
浏览器已经能够检测到用户是否离线,并触发 JavaScript 事件以便应用做出处理。可以指定在应用缓存中保存哪些文件以便离线时使用。对于应用缓存的状态及变化,也有相应的 JavaScript API 可以调用检测。本书还讨论了客户端存储的以下几方面内容。
- 以前,这种存储只能使用 cookie 完成,cookie 是一小块可以客户端设置也可以在服务器端设置的信息,每次发起请求时都会传送它。
- 在 JavaScript 中通过 document.cookie 可以访问 cookie。
- cookie 的限制使其可以存储少量数据,然而对于大量数据效率很低。IE 发明了一种叫做用户数据的行为,可以应用到页面的某个元素上,它有以下特点。
- 一旦应用后,该元素便可以从一个命名数据空间中载入数据,然后可以通过 getAttribute()、setAttribute()和 removeAttribute()方法访问。
- 数据必须明确使用 save()方法保存到命名数据空间中,以便能在会话之间持久化数据。 Web Storage 定义了两种用于存储数据的对象:sessionStorage 和 localStorage。前者严格用于在一个浏览器会话中存储数据,因为数据在浏览器关闭后会立即删除;后者用于跨会话持久化数据并遵循跨域安全策略。
IndexedDB 是一种类似 SQL 数据库的结构化数据存储机制。但它的数据不是保存在表中,而是保存在对象存储空间中。创建对象存储空间时,需要定义一个键,然后就可以添加数据。可以使用游标在对象存储空间中查询特定的对象。而索引则是为了提高查询速度而基于特定的属性创建的。
有了以上这些选择,就可以在客户端机器上使用 JavaScript 存储大量数据了。但你必须小心,不要在客户端存储敏感数据,因为数据缓存不会加密