十 JS正则表达式
1 创建方式:
方式:
[1] 字面量(var 变量名=/表达式/模式修饰符)、
[2] 构造函数(var 变量名=new RegExp(“表达式”,”模式修饰符”))
说明:
(1)表达式
单个字符与数字:
. (表示匹配除换行符之外的任意字符)、
[a-z0-9] (表示匹配方括号中的任意字符)、
[^a-z0-9] (表示匹配不在方括号里的任意字符)、
d (表示匹配数字[0-9])、
D (匹配非数字[^0-9])、
w (匹配任何ASCII字符组成的单词,等价于[a-zA-Z0-9])、
W (匹配不是ASCII字符组成的单词,等价于[^a-zA-Z0-9])
空白字符:
(匹配null字符)、
(匹配空格字符)、
f (匹配进纸符)、
(匹配换行符)、
(匹配回车符)、
s (匹配空白字符、空格、制表符或换行符)、
S (匹配非空白符)、
(匹配制表符)
ps:将直接量字符单独放进方括号内就组成了字符类,一个字符类可以用匹配它所包含的任意字符。
定位符:
^ (行首匹配)、
$ (行尾匹配)、
A (只匹配字符串的开始处)、
(匹配单词边界,词在[]内无效)、
B (匹配非单词边界)、
G (匹配当前搜索的开始位置)、
(匹配字符串结束处或行尾)、
z (只匹配字符串结束处)
(?=p) (要求接下来的字符都与p匹配,但不能报考匹配p的那些字符)
(?!p) (要求接下来的字符不与p匹配)
限定符:
在正则表达式之后跟随用以指定限定字符重复的标记。分为贪婪匹配与非贪婪匹配。
贪婪匹配:
x? (匹配0个或1个x)、
x* (匹配0个或任意多个x)、
x+ (匹配至少1个x)、
x{m,n} (匹配最少m个,最多n个x)
x{n,} (匹配x n次或者更多次)
x{n} (匹配x n次)
非贪婪匹配:
若对正则表达式进行非贪婪匹配,只需在待匹配的字符后跟随一个问号即可,表示尽可能少的匹配,如??、+?、*?、{1,5}?
eg.
当使用aaa作为匹配字符串时,正则表达式为/a+/时可以匹配到aaa,但正则表达式为/a+?/时只能匹配到a
var tet="aaab"; var pattern=/a+?b/; console.log(pattern.exec(tet));//[ 'aaab', index: 0, input: 'aaab' ]
ps:此时非贪婪匹配结果却与贪婪匹配结果相同,这是因为正则表达式的模式匹配总是会寻找字符串中第一个可能匹配的位置。由于该匹配是从字符串的第一个字符开始的,因此这里不考虑它的子串中更短的匹配。
分组:
(?:x) (表示匹配x但不记录匹配结果)、
x(?=y) (表示当x后接y时匹配x)、
x(?!y) (表示当x不是y时匹配)
ps:使用圆括号把单独的项组合成子表达式,以便可以像处理一个独立的单元那样用|、*、+、?等对单元内的项进行处理。如/java(script)?/
Ps:圆括号还可以在完整的模式中定义子模式,当一个正则表达式成功地和目标字符串相匹配时,可以从目标串中抽出和圆括号中的子模式相匹配的部分。如/[a-z]+d+/,小写字母后跟了一位或多位数字,如果我们真正关心的是数字部分,可以将模式的数字部分放在括号中,如(/[a-z]+(d+)/),就可以从检索到的匹配中抽取数字了。
引用:
1…9 $1…$9 (表示返回九个在模式匹配期间找到的、最近保存的部分)
Ps:带圆括号的表达式允许在同一正则表达式的后部引用前面的子表达式,通过后加数字实现的。该数字指定了带圆括号的子表达式在正则表达式中的位置。如1表示引用的是第一个带圆括号的子表达式。Ps:参与计数第几个是左括号的位置。
Ps:对正则表达式中前一个子表达式的引用,并不是指对子表达式模式的引用,而指的是与那个模式相匹配的文本的引用。引用可以用于实施一条约束,即一个字符串各个单独部分包含的是完全相同的字符。如匹配左侧或右侧的引号:/([‘”]) [^’”]*1/
模式(选择):
x|y|z (表示匹配x或y或z)
ps:选择项的尝试匹配次序是从左到右,直到发现了匹配项。如果坐标的选择项匹配,就忽略右边的匹配项,即可可能有更好的匹配。
Ps:
|表示选择,匹配的是该符号坐标的子表达式或右边的子表达式。
(…)表示组合,将几个项组合为一个单元,该单元可通过*、+、?、|等符号加以修饰,且记住和这个组合相匹配的字符。
(?:…)表示只组合,把项组合到一个单元,但不记忆与该组相匹配的字符。
表示和第n个分组第一次匹配的字符相匹配,组是圆括号中的子表达式,组索引是从左到右的左括号数,以”(?:”形式的分组不编码。
(2) 模式修饰符
g:(全局模式,应用于所有字符串)
i:(区分大小写模式)
m:(多行匹配模式)
eg.
var pattern1=/at/g; //匹配所有含有at的实例 var pattern2=/[bc]at/i; //匹配第一个bat或cat,不区分大小写 var pattern3=/.at/gi; //匹配所有以at结尾的3个字符的组合,不区分大小写
2 属性:
实例属性:
global (表示检测是否设置g标记)、
ignoreCase (表示检测是否设置了i标记)、
multiline (表示检测是否设置了m标记)、
lastIndex (表示开始检索下一个匹配项的字符位置)、
构造函数属性:
$_ input (表示最近一次匹配的字符串)
$& lastMatch (表示最近一次的匹配项)
$+ lastParen (表示返回最近一次匹配的捕获组)
$` leftContext (表示返回被查找的字符串从字符串开始位置到最后匹配之前的位置之间的字符)
$’ rightContext (表示返回被搜索的字符串中从最后一个匹配位置开始到字符串结尾之间的字符)
$* multiline (表示检测表达式是否采用多行模式匹配m)
3 方法:
实例方法:
exec(): (表示在字符串中执行匹配检索,返回结果数组)
test(): (表示在字符串中测试模式匹配,返回true或false)(一般用于if语句中,验证输入信息)
var text="mom and dad and baby"; var pattern=/mom(and dad (and baby)?)?/gi; var matches=pattern.exec(text); console.log(matches.index);//0 console.log(matches.input);// "mom and dad and baby" console.log(matches[0]);//"mom and dad and baby" console.log(matches[1]);//"and dad and baby" console.log(matches[2]);//"and baby" var re=/cat/g; console.log(re.test("catjkcat"));//true
ps: 对exec()方法而言,即使在模式中设置了g标志,每次也只会返回一个匹配项。在不设置全局标志的情况下,同一个字符串上多次调用exec()方法将始终返回第一个匹配项的信息,而在设置全局标志的情况下,每次调用exec()则都会在字符串中继续查找新匹配的项。
字符串方法:
match(): (找到一个或多个正则表达式的匹配)
replace(): (替换与正则表达式匹配的子串)
search(): (检索与正则表达式相匹配的值)
split(): (把字符串分割为字符串数组)
十一 事件
事件:文档或浏览器窗口中发生的一些特定的交互瞬间。JavaScript与HTML之间的交互是通过事件实现的。可以使用事件监听器来预订事件,以便事件发生时执行相应的代码。
1 事件流
事件流:描述的是从页面中接收事件的顺序,如当点击了按钮之后,单击事件不仅发生在按钮上,也发生在按钮的容器元素,甚至是整个页面上。IE的事件流是事件冒泡流,而Netscape的事件流是事件捕获流。
事件冒泡:事件开始时,由最具体的元素接收,然后逐级向上传播到较为不具体的节点。
Ps:所有现代浏览器都支持事件冒泡。
事件捕获:不太具体的元素节点更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于事件到达预定目标之前捕获它。
DOM2级事件流:包含三个阶段,事件捕获阶段、处于目标阶段、事件冒泡阶段。如document-html-body-div,在DOM事件流中,实际的目标在捕获阶段不会接收到事件,即在捕获阶段,事件从document到html再到body就停止了。下一个阶段是处于目标阶段,事件在目标事件div上发生,并在事件处理中被看成是冒泡阶段的一部分。然后冒泡阶段发生,事件又传播回文档。
2 事件处理程序
事件可以理解为用户或浏览器自身执行的某种动作,如click、load等都是事件的名字,而响应某个事件的函数就叫事件处理程序(或事件侦听器)。JavaScript中事件处理程序名字以on开头,如click事件的事件处理程序就是onclick。
为事件指定事件处理程序的方式有几种:HTML事件处理程序、DOM0级事件处理程序、DOM2级事件处理程序、IE事件处理程序、跨浏览器的事件处理程序
[1] HTML事件处理程序
某个元素支持的每种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。该特性的值应该是能够知晓的JavaScript代码。在HTML中定义的事件处理程序可以包含要执行的具体动作,也可以调用在页面其他地方定义的函数脚本。
<input type="button" value="click me" onclick="alert('clicked');" /> 或 function showMsg(){ alert("hello"); } <input type="button" value="click me" onclick="showMsg()" />
[2] DOM0级事件处理程序
将一个函数赋值给一个事件处理程序属性
var btn=document.getElementById("myBtn"); btn.onclick=function(){ alert(this.id); }
删除通过DOM0级方法指定的事件处理程序:
btn.onclick=null;
[3] DOM2级事件处理程序
DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener()、removeEventListener(),其参数有三个,要处理的事件名,作为事件处理程序的函数,和一个布尔值,true表示捕获阶段调用事件处理程序,false表示冒泡阶段调用事件处理程序。
var btn=document.getElementById("myBtn"); btn.addEventListener("click",function(){alert(this.id)},false); btn.addEventListener("click",function(){alert("hello")},false);
//这里调用两次addEventListener(),为同一个按钮添加两个不同的事件处理程序,会以顺序的顺序执行这两次事件处理程序
//通过addEventListener()添加的事件处理程序只能使用removeEventListener()来移除,移除时传入的参数及添加的事件处理程序需要一致,
//即通过匿名函数添加的事件处理程序将无法移除。因此在传入事件处理程序时,需要使用具名函数。 var btn=document.getElementById("myBtn"); var handler=function(){ alert(this.id); } btn.addEventListener("click",handler,false); btn.removeEventListener("click",handler,false);
ps:通常,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种浏览器。建议只在需要事件到达目标之前捕获它的时候将事件处理程序添加到捕获阶段。不是特别需要的情况下,不建议在事件捕获阶段注册事件处理程序。
[4] IE事件处理程序
attachEvent()、detachEvent(),接受两个参数,事件处理程序名称与事件处理程序函数。只支持事件冒泡。
var btn=document.getElementById("myBtn"); btn.attachEvent("onclick",function(){ alert("clicked"); }); btn.attachEvent("onclick",function(){ //这里调用两次attcahEvent(),为同一个按钮添加两个不同的事件处理程序,会以相反的顺序执行这两次事件处理程序 alert("heool"); }); var btn=document.getElementById("myBtn"); var handler=function(){ alert(this.id); } btn.attachEvent("onclick",handler); btn.detachEvent("click",handler);
ps:IE中使用attachEvent()与使用DOM0级方法的主要区别在于事件处理程序的作用域。在使用DOM0级方法的情况下,事件处理程序会在所属元素的作用域内运行,在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行。
[5] 跨浏览器的事件处理程序
var EventUtil={ addHandler:function(element,type,handler){ if(element.addEventListener){ element.addEventListener(type,handler,false); }else if(element.attachEvent){ element.attachEvent("on"+type,handler); }else{ element["on"+type]=handler ; } }, removeHandler:function(element,type,handler){ if(element.removeEventListener){ element.removeEventListener(type,handler,false); }else if(element.detachEvent){ element.detachEvent("on"+type,handler); }else{ element["on"+type]=null; } } }; var btn=document.getElementById("myBtn"); var handler=function(){ alert("clicked"); }; EventUtil.addHandler(btn,"click",handler); EventUtil.removeHandler(btn,"click",handler);
3 事件对象
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息,包括导致事件的元素、事件的类型及其他与特定事件相关的信息。
[1]DOM中的事件对象
[2]IE中的事件对象
[3]跨浏览器的事件对象
十二 JSON
JSON,JavaScript对象表示法,一种数据格式,是在JavaScript中读写结构化数据的更好方式。
1 语法
JSON的语法可以表示三种类型的值:
[1] 简单值
如字符串(JSON字符串必须用双引号,单引号可能导致语法错误)、数值、布尔值、null
[2] 对象
表示的是一组无序的键值对,而每个键值对中的值可以是简单值、对象
eg.
Javascript中对象字面量:
var obj={ name:"xh", age:26 }; 或 var obj={ "name":"xh", "age":26 }; JSON表示上述对象: { "name":"xh", "age":26 }
ps:JSON对象,没有声明变量,没有末尾分号。对象属性名必须用双引号。
[3] 数组
表示一组有序的值的列表,可以通过数值索引来访问其中的值,数组中的值可以是简单值、对象、数组
JavaScript中数组:var values=[23,"hi",true]; JSON数组:[23,"hi",true]
Ps: JSON数组,没有变量和分号。
Ps:JSON不支持变量、函数、对象实例,它就是一种表示结构化数据的格式。
2 解析与序列化
JSON流行原因:与JavaScript类似的语法、可以把JSON数据结构解析为JavaScript对象。
[1] JSON对象有两个方法:stringify()、parse(),分别用于把JavaScript对象序列化为JSON字符串和把JSON字符串解析为原生JavaScript值。
var books={ //js对象 title:"pp javascript", authors:[ "n sk skd" ], edidtion:3, year:2018 }; var jsonText=JSON.stringify(book);//转化为JSON字符串
ps:JSON.stringify()输出的JSON字符串不包含任何空格字符或缩进。在序列化JavaScript对象时,所有函数及原型成员都会被有意忽略,不体现在结果中。此外,值为undefined的任何属性都会被跳过。结果中 都是值为有效JSON数据类型的实例属性。
将JSON字符串直接传递给JSON.parse()就可以得到相应的JavaScript对象
var bookCopy=JSON.parse(jsonText)
[2] 序列化选项
JSON.stringify()除了要序列化的JavaScript对象外,还可以接收另外两个参数,用于指定以不同的方式序列化JavaScript对象。第一个参数为过滤器 ,可以是一个数组,也可以是一个函数,第二个参数是一个选项,表示是否在JSON字符串中保留缩进。
var books={ title:"pp javascript", authors:[ "n sk skd" ], edidtion:3, year:2018 }; var jsonText=JSON.stringify(book,["title","edition"]);//转化为JSON字符串
ps:如果过滤器参数是数组,则json字符串中将只包含数组中列出的属性。
var books={ title:"pp javascript", authors:[ "n sk skd" ], edidtion:3, year:2018 }; var jsonText=JSON.stringify(book,function(key,value){ switch(key){ case "authors": return value.join(","); case "year": return 5000; case "edition": return undefined; default: return value; } });//转化为JSON字符串
ps:如果第一个参数是函数,则传入的函数接收两个参数:属性名和属性值。属性名只能是字符串。为了改变序列化对象的结果,函数返回的值就是相应键的值。若函数返回了undefined,则相应的属性会被忽略(这一特性可以用于删除某个属性)。
字符串缩进:JSON.stringify()方法的第三个参数用于控制结果中的缩进和空白符。如果这个参数是一个数值,那它表示的是每个级别缩进的空格数。
var books={ title:"pp javascript", authors:[ "n sk skd" ], edidtion:3, year:2018 }; var jsonText=JSON.stringify(book,null,4);//转化为JSON字符串,每个级别缩进4格
ps:只要传入有效的控制缩进的参数值,结果字符串中就会包含换行符。最大缩进数是10。如果缩进参数是一个字符串而非数值,则这个字符串将在JSON字符串中被用作字符(不再用空格)。
当JSON.stringify()还不能满足对某些对象进行自定义序列化需求时,可以选择toJSON()方法,返回其自身的JSON数据格式。可以为任何对象添加toJSON()方法:
var books={ title:"pp javascript", authors:[ "n sk skd" ], edidtion:3, year:2018, toJSON:function(){ return this.title; } }; var jsonText=JSON.stringify(book);//转化为JSON字符串
ps:可以让toJSON()返回任何值。toJSON()可以作为函数过滤器的补充。如想要让这个方法返回undefined,此时,如果包含它的对象嵌入在另一个对象中,会导致它的值变为null,如果其是顶级对象,则结果是undefined。
假设把一个对象传入JSON.stringify(),序列化该对象的顺序如下:
(1) 若存在toJSON()方法且能通过它获得有效值,则调用该方法,否则返回对象本身。
(2) 若提供了第二个参数,应用这个函数过滤器。传入该函数过滤器的值是第1步返回的值。
(3) 对第2步返回的每个值执行相应的序列化。
(4) 若提供了第三个参数,执行相应的格式化。
[3] 解析选项
JSON.parse()方法可以接收另一个参数,该参数为一个函数,将在每个键值对上调用(称还原函数)。该函数接收两个参数,一个键一个值。
如果还原函数返回undefined,啧啧表示要从结果中删除相应的键,如果返回其他值,则将该值插入到结果中。
var books={ title:"pp javascript", authors:[ "n sk skd" ], edidtion:3, year:2018, releaseDate:new Date(2011,12,16); }; var jsonText=JSON.stringify(book);//转化为JSON字符串 var bookCopy=JSON.parse(jsonText,function(key,value){ if(key == "releaseDate"){ return new Date(value); }else{ return value; } }); alert(bookCopy.releaseDate.getFullYear());
参考资料:
《JavaScript高级程序设计》、《JavaScript权威指南》