JavaScript DOM 高级程序设计读书笔记一

创建可重用的对象

简而言之,对象就是包含一组变量(称为属性)和函数(称为方法)的集合的实例。对象通常由类派生而来,而类中定义了对象拥有的属性和方法。如果你的脚本中都是对象之间的交互操作,那么就可以称之为OO(Object Oriented,面向对象)的脚本。特别要说明的是,JavaScript 是一种原型式(prototype-style)的OO语言,没有类的概念,所有一切都派生自现有对象的一个副本。JavaScript 的主要内置对象有:Object, Function, Array, String, Boolean, Number, Math, Date, RegExp 等等。所有内置对象都可以通过 new 关键字或者其他特殊的语法来创建,例如 function 关键字用于创建 Function 对象,花括号({})是 Object 的简写形式,而方括号([])则是 Array 的简写形式。

创建一个构造函数

function myConstructor(message) {
  this.myMessage = message;
  
  //私有属性
  var separator = '-';
  var myOwner = this;
  
  //私有方法
  function alertMessage() {
    alert(myOwner.myMessage);
  }
  //特权方法(也是公有方法)
  this.appendToMessgae = function(string) {
    this.myMessage += separator + string;
    alertMessage();
  }
}
//公有方法
myConstructor.prototype.clearMessage = function(string) {
  this.myMessage = '';
}
//静态属性
myConstructor.name = 'jeff';
//静态方法
myConstructor.alertName = function() {
  alert(this.name);
}

this

this 在 JavaScript 中是一个依赖于使用它的执行环境被解析的关键字。嗯...,有点难懂,其实就是 this 引用的是包含它的函数作为某个对象的方法被调用时的那个对象。可以通过 call() 和 apply() 重新定义执行环境。

实例:实现一个调试日志

function myLogger(id) {
  id = id || 'logWindow';
  var logWindow = null;
  //用受保护的方法创建日志窗口
  var createWindow = function() {
    var browserWindowSize = getBrowserWindowSize();
    var top = ((browserWindowSize.height - 200) / 2) || 0;
    var left = ((browserWindowSize.width - 200) / 2) || 0;
    //使用受保护的 logWindow 属性维护引用
    logWindow = document.createElement('ul');
    //指定 ID 值,以便必要时在DOM树中能够识别它
    logWindow.setAttribute('id', id);
    //定位日志窗口既设置大小
    logWindow.style.position = 'absolute';
    logWindow.style.top = top + 'px';
    logWindow.style.left = left + 'px';
    logWindow.style.width = '200px';
    logWindow.style.height = '200px';
    logWindow.style.overflow = 'scroll';
    //美化外观
    logWindow.style.padding = '0';
    logWindow.style.margin = '0';
    logWindow.style.border = '1px solid black';
    logWindow.style.backgroundColor = 'palegoldenrod';
    logWindow.style.listStyle = 'none';
    //添加到文档主体
    document.body.appendChild(logWindow);
  };
  //向日志窗口中添加新条目
  this.writeRaw = function(message) {
    if(!logWindow) createWindow();
    var li = document.createElement('li');
    li.style.padding = '2px';
    li.style.borderBottom = '1px solid #000';
    li.style.color = 'orangered';
    if(typeof message == 'undefined') {
      li.appendChild(document.createTextNode('Message was undefined.'));
    } else {
      li.innerHTML = message;
    }
    logWindow.appendChild(li);
    
    return true;
  };
}

myLogger.prototype.write = function(message) {
  //警告 message 为空值
  if(typeof message == 'string' && message.length == 0 || typeof message == 'undefined') {
    return this.writeRaw('null message');
  }
  //如果 message 不是字符串,则尝试调用 toString() 方法,如果不存在则记录对象类型。
  if(typeof message != 'string') {
    if(message.toString) return this.writeRaw(message.toString());
    else return this.writeRaw(typeof message);
  }
  //转换 <, > ,以便 .innerHTML 不会将 message 作为 HTML 进行解析。
  message = message.replace(/</g, '&lt;').replace(/>/g, '&gt;');
  return this.writeRaw(message);
}

获取浏览器窗口大小的兼容写法

function getBrowserWindowSize() {
  var de = document.documentElement;
  return {
    'width': (
      window.innerWidth
      || (de && de.clientWidth)
      || document.body.clientWidth),
    'height': (
      window.innerHeight
      || (de && de.clientHeight)
      || document.body.clientHeight)
  }
};

DOM2 核心和 DOM2 HTML

DOM 是什么

DOM 是一组用来描述脚本怎样与结构化文档进行交互和访问的web标准。DOM定义了一系列对象,方法和属性,用于访问,操纵和创建文档中的内容,结构,样式以及行为。需要清楚的是 DOM 不是 JavaScript,DOM 是 W3C 开发的一组规范,这些规范规定了 JavaScript 这样的语言为符合标准需要实现的对象,方法和属性。通过建立和遵守规范,可以保证你编写的JavaScript代码在不同的操作环境(例如不同的浏览器)中具有一致的行为和相同的预期效果。

DOM 级别

W3C DOM 并不是只有一份大而全的规范,它分成不同的级别,每个级别包含不同的子规范和模块。DOM 级别有 DOM 1级,DOM 2级,DOM 3级。要知道你选择的浏览器支持何种W3C DOM特性,可以使用 DOMImplementation 对象。在 Web 浏览器中,DOMImplementation 对象被实例化为 document.implementation 。如果浏览器的官方声称支持某种特性,那么可以通过 document.implementation.hasFeature() 方法进行验证。该方法接受两个参数:第一个参数(Core, XML, HTML, Views, StyleSheets, CSS, CSS2, Events等等),第二个参数是DOM级别(1.0,2.0,3.0)。

if(document.implementation) {
  if(document.implementation.hasFeature('Core', '2.0')) {
    alert('DOM2 Core Supported');
  } else {
    alert('DOM2 Core Not Supported');
  }
} else {
  alert('No DOMImplementation Supported');
}

当然也可以打开https://www.w3.org/2003/02/06-dom-support.html页面测试查看该页面的浏览器所有的报告特性。

DOM 核心

当浏览器解析一个 html 文件时,它会根据自身支持的W3C DOM模块把标记转换为对象,树形结构中项的主体部分是Element节点,唯一的特例是表示整个文档的Document和表示标记中根元素<html>的documentElement,需要注意的是标记中每个标签之间的空白符都被转换成了Text节点。然而,在使用IE时,只有当除了空白符之外还夹杂着其他的文本字符时文本节点才会存在。

核心 Node 对象

每个Element都扩展自Node对象,即使是document和documentElement也是如此,只不过它们也有自己独特的属性和方法。
1. 节点名称,值和类型
nodeName 属性取得用于区分节点的标签名称,为了保持一致性,nodeName的值会被转化为大写形式。
对于不基于文档中标签的其他对象来说,nodeName 的值取决于引用对象的类型。

对象 返回值
Element.nodeName 元素的名称,大写
Attr.nodeName 属性的名称,小写
Text.nodeName #text
Comment.nodeName #comment
Document.nodeName #document
DocumentType.nodeName 文档类型的名称,如HTML
DocumentFragment.nodeName #document fragment

与 nodeName 类似,nodeValue 属性对于不同的对象类型也具有不同的含义。

对象 返回值
Element.nodeValue null
Attr.nodeValue 字符串形式的属性值
Text.nodeValue 字符串形式的节点内容
Comment.nodeValue 字符串形式的注释文本
Document.nodeValue null
DocumentType.nodeValue null
DocumentFragment.nodeValue null

DOM 核心对象的 nodeType 常量

nodeType值 等价命名常量
1 Node.ELEMENT_NODE
2 Node.ATTRIBUTE_NODE
3 Node.TEXT_NODE
8 Node.COMMENT_NODE
9 Node.DOCUMENT_NODE
10 Node.DOCUMENT_TYPE_NODE
11 Node.DOCUMENT_FRAGMENT_NODE

如果你在代码中需要检测 nodeType ,尽量使用 DOM 常量(更容易被人看懂,维护和调试)。比如:

if(node.nodeType == Node.COMMENT_NODE) {
  //针对注释节点的代码
}

2. 父节点,子节点和同辈节点

  • parentNode属性 引用指定节点的直接父节点;
  • childNodes属性引用的是指定节点的所有子元素,也是包含DOM对象的一个类数组的NodeList对象;
  • firstChild属性引用的是第一个子节点;
  • lastChild属性引用的是最后一个子节点;
  • previousSibling属性引用的是与当前节点前紧邻的同辈节点,如果没有则为 null ;
  • nextSibling属性引用的是与当前节点后紧邻的同辈节点,如果没有则为 null ;

3. 节点的属性
作为核心Attr对象的实例,节点的属性被包含在相应节点的attributes成员的一个NamedNodeMap对象中。包括html预定义属性和自定义属性。
4. 节点的ownerDocument属性
一个节点的ownerDocument属性类似于指向节点所属根文档的引用。可以通过它引用 document, 或者window.document。假如你在某个自定义对象的内部覆盖了 document 对象,可以通过这个属性访问到原始的 document 。

function example(node) {
  //在作用域中覆盖document
  var document = 'something else';
  //使用ownerDocument引用原始DOM文档
  var anotherNode = node.ownerDocument.getElementById('id');
  //下面这行代码会出错,因为document现在是一个字符串,而非DOM文档
  var anotherNode = document.getElementById('id');
}

5. 检测子节点和属性
如果你需要简单的检测一下某个节点是否具有子节点或属性,那么可以使用hasChildNodes()和hasAttributes()方法。

var h2 = document.getElementsByTagName('H2')[0];
console.log(h2.nodeName + ' hasChildNodes: ' + h2.hasChildNodes());
console.log(h2.nodeName + ' childNodes: ' + h2.childNodes);
console.log(h2.nodeName + ' number of childNodes: ' + h2.childNodes.length);
console.log(h2.nodeName + ' hasAttributes: ' + h2.hasAttributes());
console.log(h2.nodeName + ' attributes: ' + h2.attributes);
console.log(h2.nodeName + ' number of attributes: ' + h2.attributes.length);

输出结果为:

H2 hasChildNodes: true
H2 childNodes: [object NodeList]
H2 number of childNodes: 1
H2 hasAttributes: false
H2 attributes: [object NamedNodeMap]
H2 number of attributes: 0

6. 操纵DOM节点树

  • ParentNode.appendChild(newChild) 用于把新节点插入到当前节点末尾;
  • ParentNode.append((节点或字符串)... 更多节点) 用于在当前节点的最后面插入其它节点内容(作为子节点);
  • ParentNode.prepend((节点或字符串)... 更多节点) 用于在当前节点的最前面插入其它节点内容(作为子节点);
  • ParentNode.insertBefore(newNode, referenceNode) 用于在当前的子节点之前插入一个新节点;
  • ParentNode.removeChild(oldChild) 用于删除当前节点的子节点;
  • ParentNode.replaceChild(newChild, oldChild) 用于替换当前节点的子节点为其他节点;
  • ChildNode.before((节点或字符串)... 其它更多节点) 用于在一个子节点之前插入一个或多个节点;
  • ChildNode.after((节点或字符串)... 其它更多节点) 用于在一个子节点之后插入一个或多个节点;
  • ChildNode.replaceWith((节点或字符串)... 更多节点) 用于替换当前节点为其他节点内容;

注意:append(),prepend(),before(),after(),replaceWith()方法的参数既可以是DOM元素,也可以是DOM节点,甚至可以是直接字符内容,这些都是新增的DOM API。
7. 复制和移动节点
首先需要明白的是 document.getElementById('id') 返回的是 Node 对象的引用。

核心Element对象

所有Element对象都拥有Node对象的属性和方法,同时还有其他一些便于操纵节点属性和查找子Element对象的方法。
1. 操纵Element对象的属性

  • getAttribute(name) 方法基于一个字符串形式的属性名称取得相应属性的值
  • setAttribute(name, value) 方法基于一个字符串形式的属性名称设置相应属性的值
  • removeAttribute(name) 方法基于一个字符串形式的属性名称删除相应属性的值

2. 在Element对象中查找Element对象
在Element对象的范围内,可以用来查找其他节点的唯一有效方法是getElementsByTagName(),getElementsByTagName()方法返回的是一个NodeList对象。该方法返回的节点只包括Element节点,不包含其他类型的节点。

核心Document对象

JavaScript 的全局对象是 window 对象,所以这里讨论的就是 window 对象的 document 属性,或者是 window.document。
1. document.documentElement属性
document.documentElement属性是访问文档根元素的快捷方式。对于在浏览器呈现的HTML文档而言,所谓的根元素就是标签。
2. 使用Document对象的方法创建节点

  • createAttribute(name): 创建节点类型为Node.ATTRIBUTE_NODE的Attr节点。
  • createComment(data): 创建节点类型为Node.COMMENT_NODE的Comment节点。
  • createDocumentFragment(): 创建节点类型为Node.DOCUMENT_FRAGMENT_NODE的DocumentFragment节点。
  • createElement(tagName): 创建节点类型为Node.ELEMENT_NODE的Element节点。
  • createTextNode(data): 创建节点类型为Node.TEXT_NODE的Text节点。

3. 使用Document对象的方法查找Element对象
document.getElementById('id'), document.getElementsByTagName('tagName'), document.getElementsByClassName('className')

DOM HTML

DOM2 HTML 的 HTMLDocument 对象

当HTML文档呈现在浏览器中时,window.document 中的DOM文档对象实际上是HTMLDocument对象的一个实例,HTMLDocument 对象从核心的Document对象中继承了所有成员,而且还添加了一些属性和方法,其中增加的属性如下:

  • title: 包含位于<title>标签中的字符串;
  • referrer: 包含链接到当前页面的前一个页面的URL;
  • domain: 包含当前站点的域名;
  • URL: 包含当前页面地址栏中的URL;
  • body: 引用从节点开始的DOM树;
  • images: 是一个包含当前文档中所有标签的数组(集合);
  • links: 是一个包含与当前文档中所有标签对应的DOM节点的数组(集合);
  • forms: 是一个包含与当前文档中所有
    标签对应的DOM节点的数组(集合);
  • cookie: 是一个包含当前页面中所有cookie信息的字符串;

增加的方法如下:

  • open(): 打开一个文档;
  • close(): 关闭当前文档;
  • write(data): 将输入写入到文档中;
  • writeln(data): 将输入写入文档的同时写入一个换行符;
  • getElementsByName(elementName): 获取具有相同name值的元素集合;
原文地址:https://www.cnblogs.com/sunshine21/p/10633575.html