分类目录归档:javascript

DOM节点类型——12种DOM节点类型

前面的话

DOM是javascript操作网页的接口,全称为文档对象模型(Document Object Model)。它的作用是将网页转为一个javascript对象,从而可以使用javascript对网页进行各种操作(比如增删内容)。浏览器会根据DOM模型,将HTML文档解析成一系列的节点,再由这些节点组成一个树状结构。DOM的最小组成单位叫做节点(node),文档的树形结构(DOM树)由12种类型的节点组成。

总括

一般地,节点至少拥有nodeType、nodeName和nodeValue这三个基本属性。节点类型不同,这三个属性的值也不相同

nodeType

nodeType属性返回节点类型的常数值。不同的类型对应不同的常数值,12种类型分别对应1到12的常数值

元素节点              Node.ELEMENT_NODE(1)
属性节点              Node.ATTRIBUTE_NODE(2)
文本节点              Node.TEXT_NODE(3)
CDATA节点              Node.CDATA_SECTION_NODE(4)
实体引用名称节点       Node.ENTRY_REFERENCE_NODE(5)
实体名称节点          Node.ENTITY_NODE(6)
处理指令节点          Node.PROCESSING_INSTRUCTION_NODE(7)
注释节点              Node.COMMENT_NODE(8)
文档节点              Node.DOCUMENT_NODE(9)
文档类型节点          Node.DOCUMENT_TYPE_NODE(10)
文档片段节点          Node.DOCUMENT_FRAGMENT_NODE(11)
DTD声明节点            Node.NOTATION_NODE(12)

DOM定义了一个Node接口,这个接口在javascript中是作为Node类型实现的,而在IE8-浏览器中的所有DOM对象都是以COM对象的形式实现的。所以,IE8-浏览器并不支持Node对象的写法

//在标准浏览器下返回1,而在IE8-浏览器中报错,提示Node未定义
console.log(Node.ELEMENT_NODE);//1

nodeName

nodeName属性返回节点的名称

nodeValue

nodeValue属性返回或设置当前节点的值,格式为字符串

接下来,将按照节点类型的常数值对应顺序,从1到12进行详细说明

 

元素节点

元素节点element对应网页的HTML标签元素。元素节点的节点类型nodeType值是1,节点名称nodeName值是大写的标签名,nodeValue值是null

以body元素为例

// 1 'BODY' null
console.log(document.body.nodeType,document.body.nodeName,document.body.nodeValue)
console.log(Node.ELEMENT_NODE === 1);//true

 

特性节点

元素特性节点attribute对应网页中HTML标签的属性,它只存在于元素的attributes属性中,并不是DOM文档树的一部分。特性节点的节点类型nodeType值是2,节点名称nodeName值是属性名,nodeValue值是属性值

现在,div元素有id=”test”的属性

<div id="test"></div>
<script>
var attr = test.attributes.id;
//2 'id' 'test'
console.log(attr.nodeType,attr.nodeName,attr.nodeValue)
console.log(Node.ATTRIBUTE_NODE === 2);//true    
</script>

 

文本节点

文本节点text代表网页中的HTML标签内容。文本节点的节点类型nodeType值是3,节点名称nodeName值是’#text’,nodeValue值是标签内容值

现在,div元素内容为’测试’

<div id="test">测试</div>
<script>
var txt = test.firstChild;
//3 '#text' '测试'
console.log(txt.nodeType,txt.nodeName,txt.nodeValue)
console.log(Node.TEXT_NODE === 3);//true    
</script>

 

CDATA节点

CDATASection类型只针对基于XML的文档,只出现在XML文档中,表示的是CDATA区域,格式一般为

<![CDATA[
]]>

该类型节点的节点类型nodeType的值为4,节点名称nodeName的值为’#cdata-section’,nodevalue的值是CDATA区域中的内容

 

实体引用名称节点

实体是一个声明,指定了在XML中取代内容或标记而使用的名称。 实体包含两个部分, 首先,必须使用实体声明将名称绑定到替换内容。 实体声明是使用 <!ENTITY name “value”> 语法在文档类型定义(DTD)或XML架构中创建的。其次,在实体声明中定义的名称随后将在 XML 中使用。 在XML中使用时,该名称称为实体引用。

实体引用名称节点entry_reference的节点类型nodeType的值为5,节点名称nodeName的值为实体引用的名称,nodeValue的值为null

//实体名称
<!ENTITY publisher "Microsoft Press">
//实体名称引用
<pubinfo>Published by &publisher;</pubinfo>

 

实体名称节点

上面已经详细解释过,就不再赘述

该节点的节点类型nodeType的值为6,节点名称nodeName的值为实体名称,nodeValue的值为null

 

处理指令节点

处理指令节点ProcessingInstruction的节点类型nodeType的值为7,节点名称nodeName的值为target,nodeValue的值为entire content excluding the target

 

注释节点

注释节点comment表示网页中的HTML注释。注释节点的节点类型nodeType的值为8,节点名称nodeName的值为’#comment’,nodeValue的值为注释的内容

现在,在id为myDiv的div元素中存在一个<!– 我是注释内容 –>

<div id="myDiv"><!-- 我是注释内容 --></div>
<script>
var com = myDiv.firstChild;
//8 '#comment' '我是注释内容'
console.log(com.nodeType,com.nodeName,com.nodeValue)
console.log(Node.COMMENT_NODE === 8);//true    
</script>

 

文档节点

文档节点document表示HTML文档,也称为根节点,指向document对象。文档节点的节点类型nodeType的值为9,节点名称nodeName的值为’#document’,nodeValue的值为null

<script>
//9 "#document" null
console.log(document.nodeType,document.nodeName,document.nodeValue)
console.log(Node.DOCUMENT_NODE === 9);//true    
</script>

 

文档类型节点

文档类型节点DocumentType包含着与文档的doctype有关的所有信息。文档类型节点的节点类型nodeType的值为10,节点名称nodeName的值为doctype的名称,nodeValue的值为null

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Document</title>
</head>
<body>
<script>
var nodeDocumentType = document.firstChild;
//10 "html" null
console.log(nodeDocumentType.nodeType,nodeDocumentType.nodeName,nodeDocumentType.nodeValue);
console.log(Node.DOCUMENT_TYPE_NODE === 10);
</script>
</body>
</html>

 

文档片段节点

文档片段节点DocumentFragment在文档中没有对应的标记,是一种轻量级的文档,可以包含和控制节点,但不会像完整的文档那样占用额外的资源。该节点的节点类型nodeType的值为11,节点名称nodeName的值为’#document-fragment’,nodeValue的值为null

<script>
var nodeDocumentFragment = document.createDocumentFragment();    
//11 "#document-fragment" null
console.log(nodeDocumentFragment.nodeType,nodeDocumentFragment.nodeName,nodeDocumentFragment.nodeValue);
console.log(Node.DOCUMENT_FRAGMENT_NODE === 11);//true
</script>

 

DTD声明节点

DTD声明节点notation代表DTD中声明的符号。该节点的节点类型nodeType的值为12,节点名称nodeName的值为符号名称,nodeValue的值为null

 

最后

在这12种DOM节点类型中,有一些适用于XML文档,有一些是不常用的类型。

JavaScript原型链(一)—__proto__的默认指向

JavaScript的原型链系统着实让人头痛,在查阅了各种资料之后,终于总结出了基于几条通用规则和少数例外情况的js原型链逻辑,下面就让我们来一起看看是怎样的一个原理。

虽然JavaScript里一切皆对象,但为了理解原型链系统,我们需要将JavaScript的对象分为对象函数两大类。在此基础上,JavaScript的原型链逻辑遵从以下通用规则:

通用规则

  1. 对象__proto__属性,函数prototype属性;
  2. 对象函数生成;
  3. 生成对象时,对象__proto__属性指向函数prototype属性。

在没有手动修改__proto__属性的指向时,以上三条便是JavaScript默认原型链指向逻辑。

下面我们来从最一般的情况开始,逐步深入的详细解释一下:

1. 一般情况

创建空对象时,实际上我们是用Object函数来生成对象的:
>var o = {}
>o.__proto__ === Object.prototype
true

我们也可以显式的使用Object函数来创建对象:
>var o = Object()
o.__proto__ === Object.prototype
true

当我们使用函数来创建自定义的对象时,上面的规则同样适用:
>function MyObj(){}
>typeof MyObj
"function"
>var mo = new MyObj()
>mo.__proto__ === MyObj.prototype
true

2. 函数对象

既然JavaScript里“一切皆对象”,那函数自然也是对象的一种。对于函数作为对象来说,上面的规则同样适用:

函数对象都是由Function函数生成的:
>function fn(){}
>fn.__proto__ === Function.prototype
true

我们可以看到,把函数当做对象时,生成它的函数就是 Function函数。那Function函数本身呢?同样适用!

Function函数本身作为对象时,生成它的函数是他自身!
>Function.__proto__ === Function.prototype
true

同样我们知道,Object函数也是一个函数对象,那么它是否符合上面的规则呢?当然!

Object函数既然是函数,那生成它的函数自然是Function函数咯:
>Object.__proto__ === Function.prototype
true

3. prototype是谁?

好了,现在我们知道,对象的__proto__属性是从生成它的函数的prototype那里得来的,那我们不禁要问,函数的prototype又是谁?

一般函数默认的prototype是系统自动生成的一个对象:
>function fn(){}
>typeof fn.prototype
"object"
>fn.prototype
{constructor: ƒ}
    constructor: ƒ fn()
    __proto__: Object

>fn.prototype.constructor === fn
true
>fn.prototype.__proto__ === Object.prototype
true

一般函数默认的prototype是一个类型为"object"的对象,它有两个属性:constructor__proto__。其中constructor属性指向这个函数自身,__proto__属性指向Object.prototype,这说明一般函数的prototype属性是由Object函数生成的。

4. 特殊情况

前面我们特别强调了是一般函数,那不一般的函数是谁呢?当然是Object函数和Function函数!
先来看Object.prototype:

>typeof Object.prototype
"object"
>Object.prototype
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ,}
    constructor: ƒ Object()
    hasOwnProperty: ƒ hasOwnProperty()
    isPrototypeOf: ƒ isPrototypeOf()
    propertyIsEnumerable: ƒ propertyIsEnumerable()
    toLocaleString: ƒ toLocaleString()
    toString: ƒ toString()
    valueOf: ƒ valueOf()
    __defineGetter__: ƒ __defineGetter__()
    __defineSetter__: ƒ __defineSetter__()
    __lookupGetter__: ƒ __lookupGetter__()
    __lookupSetter__: ƒ __lookupSetter__()
    get __proto__: ƒ __proto__()
    set __proto__: ƒ __proto__()

可以看到Object函数的prototype属性也是一个类型为"object"的对象,但和一般函数的默认prototype属性不一样的是,它多了一大堆方法,这些方法都是JavaScript对象的系统默认方法。
再仔细看,好像少了什么,对了,Object函数的prototype属性里没有__proto__属性,我们试着把它的__proto__属性打出来看看:

>Object.prototype.__proto__
null

这就是Object函数特殊情况了:Object.prototype.__proto__ === null,我们知道,这就是JavaScript原型链的终点了。
为什么要这样设定呢?
typeof Object.prototype === "object",说明它是一个Object对象,如果它由Object函数生成,于是按照我们上面的通用规则,就该是Object.prototype.__proto__ === Object.prototype
啊哈,问题出现了,Object.prototype.__proto__属性指向了它自身,这样以__proto__属性构成的原型链就再也没有终点了!所以为了让原型链有终点,在原型链的最顶端,JavaScript规定了Object.prototype.__proto__ === null

好,现在再来看Function函数吧:

>typeof Function.prototype
"function"

一上来就不走寻常路,Function函数的prototype属性是一个"function"类型的对象,而不像其他函数是类型为"object"的对象。那是个什么样的函数呢?

>Function.prototype
ƒ () { [native code] }

函数内部是[native code],也就是系统编译好的二进制代码函数,这就暂时没法深究了。现在让我们来看看我们最关心的__proto__属性:

>Function.prototype.__proto__
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ,}
    constructor: ƒ Object()
    hasOwnProperty: ƒ hasOwnProperty()
    isPrototypeOf: ƒ isPrototypeOf()
    propertyIsEnumerable: ƒ propertyIsEnumerable()
    toLocaleString: ƒ toLocaleString()
    toString: ƒ toString()
    valueOf: ƒ valueOf()
    __defineGetter__: ƒ __defineGetter__()
    __defineSetter__: ƒ __defineSetter__()
    __lookupGetter__: ƒ __lookupGetter__()
    __lookupSetter__: ƒ __lookupSetter__()
    get __proto__: ƒ __proto__()
    set __proto__: ƒ __proto__()

怎么有种似曾相识的感觉呢?看起来很像是Object.prototype,让我们来试试:

>Function.prototype.__proto__ === Object.prototype
true

果然就是它!
按照我们最开始提出的通用规则,一个"function"类型的对象,应该是由Function函数生成的,那它的prototype属性应该指向Function.prototype,也就是Function.prototype.__proto__ === Function.prototype。和Object函数同样的问题出现了:循环引用。所以JavaScript规定Function.prototype.__proto__ === Object.prototype,这样既避免了出现循环引用,又让__proto__构成的原型链指向了唯一的终点:Object.prototype.__proto__ === null

5. 总结

至此,我们从最一般的对象一直追溯到了Object函数和Function函数,并找在原型链的顶端发现了两个例外情况,也知道了这两个例外个规定是为了让__proto__构成的原型链存在一个唯一的终点。

现在我们再来看这张JavaScript原型链的图,是不是一目了然了呢?

JavaScript原型链

JavaScript原型链

 

Markdown笔记

如果你是有一个佛(lan)系(duo)的心,但又很文(zhuang)艺(suan)的程序员,并且你对其他Markdown编辑器的使用效果感觉不是很好的话,就用Typora吧……

整理了一下学习笔记~先这二个吧~有空再写~

1.first day 2.The third day