1.try-catch语句续
①只要代码中包含finally子句,则无论try或catch语句块包含什么代码—-甚至return语句,都不会阻止finally子句的执行。
function testFinally(){
try{
return 0;
}catch(error){
return 1;
}finally{
return 2;
}
}
testFinally();//2
function testFinally(){
try{
return 0;
}catch(error){
return 1;
}
}
testFinally();//0
②提供提供finally子句,则catch子句就成了可选的(catch和finally有一个即可)。IE7-中有一个BUG:除非有catch子句,否则finally中的代码永远不会被执行。如果需要考虑IE的早期版本,那就只好提供一个catch子句,哪怕里面什么都没有写。IE8修复了这个BUG。
③只要代码中包含了finally子句,那么无论try还是catch语句块中的return语句都会被忽略。
④执行代码期间可能会发生的错误有多种类型。ECMA-262定义了7中错误类型:
a)Error:基类型,其他错误类型都继承自该类型,主要供开发人员抛出自定义错误。
b)EvalError:在使用eval()函数而发生异常时抛出。在实践中,不同的浏览器可能会以其他错误类型替代 EvalError或成功执行。再加上实际开发中极少情况下会使用eval(),因此该错误类型触发的可能性很小。
c)RangeError:在数值超出相应范围时触发。//var a=new Array(-2);
d)ReferenceError:在找不到对象的情况下触发。//var a=b;
e)SyntaxError:将语法错误的JS字符串传入eval()函数时,就会导致此类错误。//eval(‘a+++b’);
e)TypeError:在变量中保存着意外的类型,或在访问不存在的方式时会触发这种错误。归根结底还是由于在执行特定于类型的操作时,变量的类型不符合要求所致。//var a=new 10;
g)URIError:当使用encodeURI()【编码】或decodeURI()【解码】时,URI格式不正确就会触发该错误。
⑤要想知道错误的类型,可以在try-catch语句的catch块中使用instanceof操作符。
try{
someFunction();
}catch(error){
if(error instanceof error){
//处理基类型错误
}else if(error instanceof EvalError){
//处理Eval错误
}else if(error instanceof ReferenceError){
//处理引用错误
}else if(error instanceof TypeError){
//处理类型错误
}else if(error instanceof RangeError){
//处理范围错误
}else if(error instanceof SyntaxError){
//处理语法错误
}else if(error instanceof URIError){
//处理URI错误
}else{
//others
}
}
⑥try-catch语句适用于处理那些我们无法控制的错误。
2.DOM
①DOM(Document Object Model)是针对HTML和XML文档的一个API(Application Programming interface)
②IE中的所有DOM对象都是以COM对象的形式实现的,这意味着IE中的DOM对象与原生JavaScript对象的行为或活动并不一致。
3.节点层次
①文档元素始终都是html元素。在XML中,没有预定义的元素,因此任何元素都可能成为文档元素。
②JS中所有节点类型都继承自Node类型,因此所有节点类型都共享着相同的基本属性和方法。
③每个节点都有一个nodeType属性,用于表明节点的类型。
//12个数值常量
1.Node.ELEMENT_NODE;
2.Node.ATTRIBUTE_NODE;//特性
3.Node.TEXT_NODE;
4.Node.CDATA_SECTION_NODE;//characterData
5.Node.ENTITY_REFERENCE_NODE;
6.Node.ENTITY_NODE;//实体
7.Node.PROCESSING_INSTRUCTION_NODE;
8.Node.COMMENT_NODE;
9.Node.DOCUMENT_NODE;
10.Node.DOCUMENT_TYPE_NODE;
11.Node.DOCUMENT_FRAGMENT_NODE;
12.Node.NOTATION_NODE;
④为了确保跨浏览器兼容,最好还是将nodeType属性于数字值进行比较。
if(someNode.nodeType==Node.ELEMENT_NODE){ //在IE中无效
alert('Node is an element.');
}
if(someNode.nodeType==1){ //适用于所有浏览器
alert('Node is an element.');
}
⑤nodeName和nodeValue用于了解节点的具体信息,这两个属性的值完全取决于节点的类型。
⑥对于元素节点,nodeName中保存的始终都是元素的标签名,而nodeValue的值始终为null。
4.节点关系
①每个节点都有一个childNodes属性,其中保存着一个NodeList对象。
②NodeList对象并不是Array的实例,其独特之处在于,它是基于DOM结构动态执行查询的结果,因此DOM结构的变化能够自动反应在NodeList对象中。NodeList是有生命、有呼吸的对象,而不是在我们第一次访问它们的某个瞬间拍摄下来的一张照片。
var firstChild=someNode.childNodes[0];
var secondChild=someNode.childNodes.item(1);
var count=someNode.childNodes.length;
③对arguments对象使用Array.prototype.slice()方法可以将其转化为数组,采取同样的方法,也可以将NodeList对象转化为数组。
//在IE 8-无效
var arrayOfNodes=Array.prototype.slice.call(someNode.childNodes,0);
//IE 8-有效---手动枚举所有成员
function convertToArray(nodes){
var array=null;
try{
array=Array.prototype.slice.call(nodes,0);//针对非IE浏览器
}catch(ex){
array=new Array();
for(var i=0,len=nodes.lentgh;i<len;i++){
array.push(nodes[i]);
}
}
return array;
}
④每个节点都有一个parentNode属性,该属性指向文档树中的父节点。包含在childNodes列表中的每个节点相互之间都是同胞节点,通过使用列表(NodeList)中每个节点的previousSibling和nextSibling属性,可以访问同一列表中的其他节点。
if(someNode.nextSibling===null){
alert("Last node in the parent's childNodes list.");
}else if(someNode.previousSibling===null){
alert("First node in the parent's childNodes list.");
}
⑤父节点与第一个和最后一个子节点也存在特殊的关系。父节点的firstChild和lastChild属性分别指向其childNodes列表中的第一个和最后一个节点。其中someNode.firstChild的值始终等于someNode.childNodes[0],而someNode.lastChild的值始终等于someNode.childNodes[someNode.childNodes.length-1]。
⑥hasChildNodes()方法在节点包含一或多个子节点的情况下返回true。
⑦所有节点都有的最后一个属性是ownerDocument,该属性指向表示整个文档的文档节点。
⑧虽然所有节点类型都继承自Node,但并不是每种节点都有子节点。
5.操作节点【appendChild()/insertBefore()/replaceChild()/removeChild()】
①最常用的方法是appendChild(),用于向childNodes列表的末尾添加一个节点。添加完节点后,childNodes的新增节点、父节点和以前的最后一个子节点的关系指针都会得到相应的更新。更新完毕后,appendChild()返回新增的节点。
var returnedNode=someNode.appendChild(newNode);//appendChild()方法会返回新增节点
alert(returnedNode==newNode);//true
alert(someNode.lastChild==newNode);//true
②如果传入到appendChild()中的节点已经是文档的一部分了,那么结果就是将该节点从原来的位置转移到新的位置。
//假设someNode有多个节点
var returnedNode=someNode.appendChild(someNode.firstChild);
alert(returnedNode==someNode.firstChild);//false
alert(returnedNode==someNode.lastChild);//true
③insertBefore()方法可以将节点放在childNodes列表中某个特定的位置,而不一定是在末尾。该方法接收两个参数:要插入的节点和作为参照的节点。插入节点后,被插入的节点会变成参照节点的前一个同胞节点(previousSibling),同时被方法返回。如果参照节点是null,则insertBefore()与appendChild()执行相同操作。
//insertBefore()方法返回插入的节点
//插入后成为最后一个子节点
returnedNode=someNode.insertBefore(newNode,null);
alert(newNode==someNode.lastChild);//true
alert(returnedNode==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(returnedNode==someNode.childNodes[someNode.childNodes.length-2])//true
④replaceChild()方法接收两个参数:要插入的节点和要替换的节点。要替换的节点通过该方法返回并从文档树中移除,同时由要插入的节点占据位置。
//替换第一个子节点---返回被“覆盖”的子节点,即第一个子节点
var returnedNode=someNode.replaceChild(newNode,someNode.firstChild);
//替换最后一个子节点---返回被“覆盖”的子节点,即最后一个子节点
returnedNode=someNode.replaceChild(newNode,someNode.lastChild);
⑤在使用replaceChild()方法插入一个节点时,该节点的所有关系指针都会从被它替换的节点复制过来。从技术上讲,被替换的节点仍存在于文档中,但已没有了当初的位置。
⑥removeChild()只是移除而非替换节点。该方法只接收一个参数,即为要移除的节点。要移除的节点将成为该方法的返回值。
//移除第一个子节点---返回被移除的第一个子节点
var formerFirstChild=someNode.removeChild(someNode.firstChild);
//移除最后一个子节点---返回被移除的最后一个子节点
var formerLastChild=someNode.removeChild(someNode.lastChild);
6.其他方法
①有两个方法是所有类型的节点共有的。cloneNode()/normalize()
②cloneNode()方法用于创建(调用这个方法)的节点的一个完全相同的副本。cloneNode()方法接收一个布尔值参数,表示是否进行深复制。在参数为true的情况下,执行深复制,也就是复制节点和其整个子节点树;在参数为false的情况下,执行浅复制,即只复制节点本身。复制后返回的节点副本归文档所有,单并没有为其指定父节点。因此,这个节点副本就成为了一个孤儿,除非通过appendChild()、insertBefore()或replaceChild()方法将其添加到文档中。
③cloneNode()方法不会复制(添加到DOM节点中的)JS属性,例如事件处理程序等。这个方法只复制特性、(在明确指定的情况下也复制)子节点,其他一切都不会复制。IE在此存在一个BUG,即它会复制事件处理程序,因此建议在复制之前最好先移除事件处理程序。
④normalize()方法的作用是处理文档树中的文本节点。由于解析器的实现或DOM操作的原因,可能会出现文本节点不包含文本,或接连出现两个文本节点的情况。利用该方法,如果找到空文本节点,则删除它;如果找到相邻的文本节点,则将它们合并为一个文本节点。
7.Document类型
①JS通过Document类型表示文档。在浏览器中,document对象是HTMLDocument(继承自Document类型)的一个实例,表示整个HTML页面。同时,document对象是window对象的一个属性,因此可以将其作为一个全局对象来访问。
②Document节点具有下列特征:
a)nodeType=9;
b)nodeName=’#document’;
c)nodeValue=null;
d)parentNode=null;
e)ownerDocument=null;
f)其子节点可能是一个DocumentType(最多一个)、Element(最多一个)、ProcessingInstruction或Comment。
③最常见的应用是作为HTMLDocument实例的document对象。通过这个文档对象,不仅可以获得与页面有关的信息,而且还能操作页面的外观及其底层结构。
④在FireFox、Safari、Chrome和Opera中,可以通过脚本访问Document类型的构造函数和原型。但在所有浏览器中都可以访问HTMLDocument类型的构造函数和原型,包括IE8+。
8.文档的子节点【document.doctype/注释】
①两个内置的访问其子节点的快捷方式:
a)documentElement属性,该属性始终指向HTML页面中的html元素。
b)通过childNodes列表访问文档元素。
②document.documentElement获得对html的引用。
③document.body获得对body的引用。
④所有浏览器都支持document.documentElement和document.body属性。
⑤document.doctype获得对!doctype的引用
⑥浏览器对document.doctype的支持差别很大:
a)IE 8-:如果存在文档类型声明,会将其错误地解释为一个注释并把它当做Comment节点;而document.doctype的值始终为null。
b)IE 9+及Firefox:如果存在文档类型说明,则将其作为文档的第一个子节点;document.doctype是一个DocumentType节点,也可以通过document.firstChild或document.childNodes[0]访问同一个节点。
c)Safari、Chrome和Opera:如果存在文档类型说明,则将其解析,但不作为文档的子节点。document.doctype是一个DocumentType节点,但该节点不会出现在document.childNodes中。
⑦现实中的浏览器在处理位于外部的注释方面存在如下差异:
a)IE 8-、Safari 3.1+、Opera和Chrome只为第一条注释创建节点,不为第二条注释创建节点。导致第一条注释就会成为document.childNodes中的第一个子节点。
b)IE 9+会将第一条注释创建为document.childNodes中的一个注释节点,也会将第二条注释创建为document.childNodes中的注释子节点。
c)Firefox以及Safari 3.1-版本会完全忽略这两个注释。
9.文档信息【title/URL/domain/referrer】
①document对象作为HTMLDocument的一个实例。
②document对象中的title属性,修改title属性会改变元素。
var originalTitle=document.title;
document.title='New page title';
③三个与网页的请求相关的属性:URL,domain和referrer
//获取完整的URL
var url=document.URL;//http://www.wrox.com/WileyCDA/
//获得域名
var domain=document.domain;//www.wrox.com
//获得来源页面的URL
var referrer=document.referrer;
//假设页面来自p2p.worx.com域
document.domain='wrox.com';//成功
document.domain='nczonline.net';//出错!
a)URL属性中包含着页面完整的URL(即地址栏中显示的URL)。
b)domain属性中只包含页面的域名。
c)referrer属性中保存来源页面的URL。
④由于跨域安全限制,来自不同子域的页面无法通过JS通信。而通过将每个页面的document.domain设置为相同的值,这些页面就可以互相访问对方包含的JS对象了。
⑤浏览器对domain属性还有一个限制,如果域名一开始是”松散的”(loose),那么不能将它再设置为”紧绷的”(tight。)
//假设页面来自于p2p.wrox.com域
document.domain='wrox.com';//loose
document.domain='pwp.wrox.com';//tight