一. 函數(shù)
函數(shù)名實際上是一個指向函數(shù)對象的指針
- 聲明函數(shù)的幾種方式
自定義函數(shù)(函數(shù)聲明)
function fun() {
//函數(shù)的實現(xiàn)
}
fun(); //調(diào)用函數(shù)
函數(shù)直接量聲明(函數(shù)表達式)
var fun = function() {
//函數(shù)實現(xiàn)
}
fun(); //調(diào)用函數(shù)
使用對象聲明函數(shù)
var fun = new Function("函數(shù)的實現(xiàn)");
fun(); //調(diào)用函數(shù)
- 代碼運行時,解析器會率先讀取函數(shù)聲明,并使其在執(zhí)行任何代碼之前可用,至于函數(shù)表達式,必須等到解析器執(zhí)行到它所在的代碼行,才會真正被解釋執(zhí)行

- 執(zhí)行環(huán)境與作用域鏈
執(zhí)行環(huán)境定義了變量或者函數(shù)有權(quán)訪問的其他數(shù)據(jù),每個執(zhí)行環(huán)境都有一個與之相關(guān)聯(lián)的變量對象,環(huán)境中定義的所有變量和函數(shù)都保存在這個對象中
每個函數(shù)都有自己的執(zhí)行環(huán)境,全局執(zhí)行環(huán)境是最外圍的一個執(zhí)行環(huán)境,當(dāng)執(zhí)行某個函數(shù)時,函數(shù)的環(huán)境就會被推入一個環(huán)境棧中,函數(shù)執(zhí)行完后,環(huán)境就會出棧
當(dāng)代碼在一個環(huán)境中執(zhí)行時,會創(chuàng)建變量對象的一個作用域鏈,并賦值給執(zhí)行環(huán)境的一個特殊的內(nèi)部屬性(即[[Scope]])
作用域鏈的本質(zhì)是一個指向變量對象的指針列表
作用域鏈的用途是保證對執(zhí)行環(huán)境有權(quán)訪問的變量和函數(shù)的有序訪問,作用域鏈的前端始終是當(dāng)前執(zhí)行環(huán)境的變量對象,下一個變量對象來自包含環(huán)境,末端始終是全局執(zhí)行環(huán)境的變量對象


- 其他
在函數(shù)內(nèi)部使用this關(guān)鍵字表示函數(shù)的調(diào)用者
使用函數(shù)名.length可獲得函數(shù)形參的個數(shù),函數(shù)名.caller指向調(diào)用該函數(shù)的函數(shù),如果是在全局調(diào)用,則為null
函數(shù)內(nèi)部arguments是一個存放函數(shù)實參的數(shù)組,arguments.length可以獲取實參的個數(shù)
函數(shù)內(nèi)部arguments.callee代表函數(shù)本身
二. DOM
DOM:document object model 文檔對象模型
- 節(jié)點(node)
標簽是節(jié)點,元素是節(jié)點,屬性是節(jié)點,文字是節(jié)點,一切皆節(jié)點
| 節(jié)點類型 | nodeType | nodeName | nodeValue | 創(chuàng)建方法 |
|---|---|---|---|---|
| 文檔(Document) | 9 | #document | null | |
| 元素節(jié)點(Element) | 1 | 元素標簽名稱 | null | createElement |
| 文本節(jié)點(Text) | 3 | #text | 文本的內(nèi)容 | createTextNode |
| 注釋節(jié)點(Comment) | 8 | #comment | 注釋的內(nèi)容 | createComment |
| 文檔類型(DocumentType) | 10 | docType名稱 | null | 不能動態(tài)創(chuàng)建,通過document.doctype獲取 |
| 特性節(jié)點(Attr) | 2 | 特性的名稱 | 特性的值 | createAttribute |
| 文檔片段(DocumentFragment) | 11 | #document-fragment | null | createDocumentFragment |
獲取元素節(jié)點
getElementById:通過id獲取對應(yīng)的元素,是唯一的
getElementsByTagName:通過標簽名獲取所有同種標簽
getElementsByClassName:通過類名獲取所有同類元素
querySelector:通過css選擇符,獲取匹配的第一個元素
querySelectorAll:通過css選擇符,獲取匹配的所有元素
matchesSelector:判斷調(diào)用元素是否與傳入的css選擇符匹配其他獲取節(jié)點的方式
<div id="box">
<div>1</div>
<div id="box1">
<span>1</span>
<span>2</span>
<span>3</span>
</div>
<div>3</div>
<div>4</div>
<div>5</div>
</div>
box1.parentNode:父節(jié)點box
box1.childElementCount:返回子元素的個數(shù)
box1.nextSibling:下一個兄弟節(jié)點,box1與3號div之間的換行
box1.nextElementSibling:下一個兄弟元素節(jié)點,3號div
box1.previousSibling:上一個兄弟節(jié)點,box1與1號div之間的換行
box1.previousElementSibling:上一個兄弟元素節(jié)點,1號div
box1.firstChild:第一個子節(jié)點,1號span前面的換行
box1.firstElementChild:第一個子元素節(jié)點,1號span
box1.lastChild:最后一個子節(jié)點,3號span后面的換行
box1.lastElementChild:最后一個子元素節(jié)點,3號span
box1.childNodes:所有的子節(jié)點,4個換行加3個span(共7個),可以通過nodeType來判斷是否為元素節(jié)點,元素節(jié)點為1
box1.children:獲取所有的子元素節(jié)點,3個span
- 節(jié)點操作
創(chuàng)建節(jié)點 createElement()
var box1 = document.createElement('div');
添加節(jié)點,添加的都是子節(jié)點
appendChild('節(jié)點') 添加節(jié)點到元素的最后面
insertBefore('新節(jié)點', '參考節(jié)點') 添加節(jié)點到參考節(jié)點的前面
insertBefore('新節(jié)點', null)等價于appendChild()
var box = document.getElementById('box');
box.appendChild(box1);
刪除節(jié)點 removeChild()
box.removeChild(box1);
克隆節(jié)點 cloneNode()
box.cloneNode(); //只克隆box節(jié)點
box.cloneNode(true); //克隆box及內(nèi)部所有節(jié)點
某個節(jié)點是否是另一個節(jié)點的后代contains()
box.contains(p) // 節(jié)點p是否是節(jié)點box的后代
- 節(jié)點特性
獲取特性 getAttribute(特性名)
var box = document.getElementById('box');
var className = box.getAttribute('class');
設(shè)置特性 setAttribute(特性名,特性值)
box.setAttribute('class', 'demo');
刪除特性 removeAttribute(特性名)
box.removeAttribute('title'); //box的title特性被刪除
通過attributes屬性遍歷元素的所有特性
for (let attr of box.attributes) {
console.log(attr.nodeName)
console.log(attr.nodeValue)
}
- 文本節(jié)點操作
- appendData:將text添加到節(jié)點的末尾
- deleteData(offset, count):從offset位置開始刪除count個字符
- insetData(offset, text):在offset位置插入text
- replaceData(offset, count, text):用text替換從offset位置開始到offset+count為止處的文本
- splitText(offset):從offset位置將當(dāng)前的文本節(jié)點分成兩個文本節(jié)點
let div = document.createElement('div')
let text = document.createTextNode('hello world!')
div.appendChild(text)
document.body.appendChild(div)
console.log(div.childNodes.length) // 1
console.log(div.firstChild.nodeValue) // hello world!
div.firstChild.splitText(5)
console.log(div.childNodes.length) // 2
console.log(div.firstChild.nodeValue) // hello
- substringData(offset, count):提取從offset位置開始到offset+count為止處的字符串
- normalize()
一般情況下, 每個元素只有一個文本子節(jié)點,某些情況下可能包含多個文本子節(jié)點,可以使用normalize()方法將所有的文本節(jié)點合并成一個
let div = document.createElement('div')
let text1 = document.createTextNode('hello ')
div.appendChild(text1)
let text2 = document.createTextNode('world!')
div.appendChild(text2)
document.body.appendChild(div)
console.log(div.childNodes.length) // 2
div.normalize()
console.log(div.childNodes.length) // 1
console.log(div.firstChild.nodeValue) // hello world!
- documentFragment文檔片段
給一個已經(jīng)存在的ul元素中添加3個li元素,如果逐個添加,會導(dǎo)致瀏覽器反復(fù)渲染,因此可以使用文檔片段一次性添加
let ul = document.getElementById('list') // 文檔中有一個id為‘list’的ul元素
let fragment = document.createDocumentFragment()
for (let i = 0; i < 3; i++) {
let li = document.createElement('li')
li.innerHTML = `item${i}`
fragment.appendChild(li)
}
ul.appendChild(fragment)
通過classList屬性操作類名
add(value):添加類名
contains(value):類名列表是否包含該類名
remove(value):從類名列表中刪除指定類名
toggle(value):如果類名列表中有該類名,則刪除,否則添加焦點管理
通過document.activeElement屬性可以獲取DOM中當(dāng)前獲得焦點的元素
通過document.hasFocus()方法可以用于確定文檔是否獲得了焦點插入標記
innerHTML:讀模式下返回調(diào)用元素所有的子節(jié)點,寫模式下其值會被解析為DOM子樹,替換調(diào)用元素原來的所有子節(jié)點
outerHTML:讀模式下返回調(diào)用元素本身及所有的子節(jié)點,寫模式下其值會創(chuàng)建新的DOM子樹并替換整個調(diào)用元素
insertAdjacentHTML():插入標記,接受兩個參數(shù),插入的位置和要插入的HTML文本,第一個參數(shù)必須是下列值之一
beforebegin:在當(dāng)前元素之前插入一個緊鄰的同輩元素
afterbegin:在當(dāng)前元素前端插入一個子元素
beforeend:在當(dāng)前元素末端插入一個子元素
afterend:在當(dāng)前元素之后插入一個緊鄰的同輩元素
innerText:讀模式下返回調(diào)用元素中包含的所有文本內(nèi)容,寫模式下會將其值以文本的形式替換調(diào)用元素的所有子元素
<div id='content'>
<p>This is a <strong>paragraph</strong> with a list following it.</p>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3</li>
<ul/>
</div>
// 對于這個例子中的div元素而言,其innerText屬性返回下列字符串,由于瀏覽器的不同,也可能不包含原始HTML代碼中的縮進
This is a paragraph with a list following it.
Item 1
Item 2
Item 3
outerText:讀模式下與innerText的結(jié)果相同,但在寫模式下會替換整個調(diào)用元素
三. DOM遍歷
使用NodeIterator和TreeWalker可以對DOM結(jié)構(gòu)執(zhí)行深度優(yōu)先(從上至下,從左往右)的遍歷操作

- NodeIterator
使用document.createNodeIterator()方法創(chuàng)建,接受4個參數(shù)
- root:想要作為遍歷起點的節(jié)點
- whatToShow:遍歷節(jié)點的過濾類型,常用的有以下幾種
1.NodeFilter.SHOW_ALL:顯示所有類型的節(jié)點
2.NodeFilter.SHOW_ELEMENT:顯示元素節(jié)點
3.NodeFilter.SHOW_TEXT:顯示文本節(jié)點
4.NodeFilter.SHOW_ATTRIBUTE:顯示屬性節(jié)點 - filter:節(jié)點過濾的函數(shù),如果應(yīng)該訪問給定的節(jié)點,則返回NodeFilter.FILTER_ACCEPT,否則返回NodeFilter.FILTER_SKIP。沒有過濾函數(shù)傳null
- entityReferenceExpansion:是否擴展實體引用,在HTML頁面中沒有用
NodeIterator類型的主要方法是nextNode()(不過濾的情況下,該方法返回的是起點節(jié)點)和previousNode()
<div id='div1'>
<p>Hello world!</p>
<ul>
<li>List Item 1</li>
<li>List Item 2</li>
<li>List Item 3</li>
</ul>
</div>
// 遍歷li元素
let div = document.getElementById('div1')
let filter = function(node) {
return node.tagName.toLowerCase() === 'li' ? NodeFilter.FILTER_ACCEPT : NodeFilter.FILTER_SKIP
}
let iterator = document.createNodeIterator(div, NodeFilter.SHOW_ELEMENT, filter)
let node = iterator.nextNode()
while (node !== null) {
alert(node.tagName)
node = iterator.nextNode()
}
- TreeWalker
使用document.createTreeWalker()方法創(chuàng)建,接受與createNodeIterator相同的4個參數(shù),從起點節(jié)點的第一個子節(jié)點開始。除了包括nextNode()(不過濾的情況下,該方法返回的是起點節(jié)點的第一個子節(jié)點)和previousNode()方法外,還提供下列方法
- parentNode():遍歷到當(dāng)前節(jié)點的父節(jié)點
- firstChild():遍歷到當(dāng)前節(jié)點的第一個子節(jié)點
- lastChild():遍歷到當(dāng)前節(jié)點的最后一個子節(jié)點
- nextSibling():遍歷到當(dāng)前節(jié)點的下一個同輩節(jié)點
- previousSibling():遍歷到當(dāng)前節(jié)點的上一個同輩節(jié)點
參數(shù)filter函數(shù)返回的值有所不同,除了NodeFilter.FILTER_ACCEPT與NodeFilter.FILTER_SKIP外,還可以使用NodeFilter.FILTER_REJECT。區(qū)別是FILTER_SKIP跳過相應(yīng)節(jié)點繼續(xù)前進到下一個節(jié)點,F(xiàn)ILTER_REJECT會跳過相應(yīng)節(jié)點及子節(jié)點
上面的例子中,如果使用TreeWalker遍歷,且filter返回值改為NodeFilter.FILTER_REJECT,則不會有任何結(jié)果,因為ul及其子節(jié)點都會被跳過
該類型還有一個屬性為currentNode,表示遍歷到的當(dāng)前元素,修改該值,可以修改遍歷的起點
四. offset
通過offset可以獲取元素尺寸,offset屬性是只讀的,只能獲取值,不能賦值
offsetWidth,offsetHeight
offsetWidth:元素的寬度,offsetHeight:元素的高度
offsetWidth = width + padding + border
offsetWidth = height + padding + borderoffsetTop,offsetLeft
offsetTop:元素到已定位父級元素上邊的距離
offsetleft:元素到已定位父級元素左邊的距離
從父級的padding開始算,border不算,也就是到父級元素邊框的距離
如果父級都沒有定位,則以頂級元素(一般為html)為準offsetParent
返回最近的已定位的父級元素
與parentNode的區(qū)別:parentNode獲取的是父元素,無論是否定位,offsetParent是獲取已定位的父級元素,如果都沒有定位,則結(jié)果為bodyoffsetTop與style.top的區(qū)別
offsetTop只讀,style.top可讀寫
offsetTop是數(shù)值(50),style.top是帶有單位的字符串("50px")
任何元素都有offsetTop,而只有定位的盒子才有style.top
style.top只能得到行內(nèi)樣式,js設(shè)置的樣式都是行內(nèi)樣式
五. scroll
當(dāng)內(nèi)容超出元素,且元素overflow為scroll時,元素可滾動
通過scroll可以獲取到元素滾動的尺寸
scrollTop,scrollLeft
scrollTop:向上滾動的距離
scrollLeft:向左滾動的距離獲取網(wǎng)頁scrollTop的方法
谷歌及未聲明DTD的瀏覽器:document.body.scrollTop,document.body.scrollLeft
火狐及其他瀏覽器:document.documentElement.scrollTop,document.documentElement.scrollLeft
ie9以上及最新瀏覽器:window.pageYOffset,window.pageXOffset
兼容性寫法
var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
scrollTo(x, y)
滾動內(nèi)容到指定的位置scrollWidth,scrollHeight
如果盒子的內(nèi)容沒有超過盒子,則為盒子的寬高(不包括border),否則為內(nèi)容的寬高(包括padding)

六. client
通過client可以獲取元素的可視區(qū)域
clientWidth,clientHeight
元素可視區(qū)域的寬度,包括padding,不包括border
可理解為不含border的offsetWidth與offsetHeightclientTop,clientLeft
clientTop:上邊框的寬度
clientLeft:左邊框的寬度client與offset、scroll的區(qū)別

七. 其他
HTML基本結(jié)構(gòu)訪問方法
文檔:document
body:document.body
title:document.title
head:document.head
html:document.documentElement檢測窗口區(qū)域
window.innerWidth,window.innerHeight:窗口的寬高
document.documentElement.clientWidth:窗口的寬高,不包括滾動條寬高
document.body.clientWidth:body的寬高,包括padding,不包括border
window.screen.width,window.screen.height:屏幕的分辨率事件冒泡
當(dāng)一個元素上的事件被觸發(fā)的時候,該元素的所有祖先元素都會觸發(fā)此事件
不是所有的事件都能冒泡,以下事件不能冒泡:blur、focus、load、unload
阻止冒泡的方法:
一般瀏覽器event.stopPropagation()
ie瀏覽器event.cancelBubble = true選中文字
獲取選中的文字:
一般瀏覽器:window.getSelection().toString()
ie:document.selection.createRange().text
取消選中:
一般瀏覽器:window.getSelection().removeAllRanges()
ie瀏覽器:document.selection.empty()各種坐標
pageX、pageY:相對于頂級元素
clientX、clientY:相對于瀏覽器窗口
screenX、screenY:相對于屏幕
offsetX、offsetY:相對于觸發(fā)事件的元素
layerX、layerY:如果觸發(fā)事件的元素有定位或者overflow不為visible,則相對于該元素,否則相對于已定位或overflow不為visible的父元素,若沒有,相對于頂級元素