rray.splice()方法是在數(shù)組中插入或刪除元素的通用方法。不同于slice()和concat(),splice()會(huì)修改調(diào)用的數(shù)組。
push()和pop()方法允許將數(shù)組當(dāng)做棧來使用,push()方法在數(shù)組的尾部添加一個(gè)或多個(gè)元素,并返回?cái)?shù)組新的長度。pop()方法則相反:它刪除數(shù)組的最后一個(gè)元素,減少數(shù)量數(shù)組長度并返回它的刪除的值。
unshift()和shift()方法的行為非常類似于push()和pop(),不一樣的是前者是在數(shù)組的頭部而非尾部進(jìn)行元素的插入和刪除操作。unshift()在數(shù)組的頭部添加一個(gè)或多個(gè)元素,并將已存在的元素移動(dòng)到更高索引的位置來獲得足夠的空間,最后返回?cái)?shù)組新的長度。shift()刪除數(shù)組的第一個(gè)元素并將其返回,然后把所有的隨后的元素下移一個(gè)位置來填補(bǔ)數(shù)組頭部的空缺。
tostring()和toLocaleString()數(shù)組和其他JavaScript對(duì)象一樣擁有toString()方法。針對(duì)數(shù)組,該方法將其每個(gè)元素轉(zhuǎn)化為字符串(如有必要將調(diào)用元素的toString()方法)并且輸出用逗號(hào)分隔的字符串列表。
forEach()方法從頭至尾遍歷數(shù)組,為每個(gè)元素調(diào)用指定的函數(shù)。如上所述,傳遞的函數(shù)座位forEach()的第一個(gè)參數(shù)。
map() map()方法將調(diào)用的數(shù)組的每個(gè)元素傳遞給指定的函數(shù),并返回一個(gè)數(shù)組,它包含該函數(shù)的返回值。
filter()方法返回的數(shù)組元素是調(diào)用的數(shù)組的一個(gè)子集。傳遞的函數(shù)是用來邏輯判定的:該函數(shù)返回true或false。
every()和some()方法是數(shù)組的邏輯判定:它們對(duì)數(shù)組元素應(yīng)用指定的函數(shù)進(jìn)行判定,返回true和false。
reduce()和reduceRight()方法使用指定的函數(shù)將數(shù)組元素進(jìn)行組合,生成單個(gè)值。這在函數(shù)式編程中是常見的操作,也可以稱為"注入"和"折疊"。
這一篇文章將講述Redis中的list類型命令,同樣也是通過demo來講述,其他部分這里就不在贅述了。
項(xiàng)目Github地址:https://github.com/rainbowda/learnWay/tree/master/learnRedis/case-list
demo功能是隊(duì)列,整個(gè)demo的大致頁面如下。左邊是存儲(chǔ)到Redis中的數(shù)據(jù),右邊是從Redis中彈出的數(shù)據(jù)。
首先定義一個(gè)存儲(chǔ)list的key
private static final String LIST_KEY="list:1";
隊(duì)列的key就用list:1
redis操作對(duì)象
private RedisTemplate redisTemplate; //string 命令操作對(duì)象 private ValueOperations valueOperations; //list 命令操作對(duì)象 private ListOperations listOperations;
list在Redis中的結(jié)構(gòu)可以看下圖(圖片來源于Redis in Action)。
頭部插入
命令介紹
接下來看看demo中頭部插入的功能,點(diǎn)擊下圖中頭部插入按鈕,然后在彈出框中填入數(shù)字0,點(diǎn)擊提交后整個(gè)頭部插入流程結(jié)束??梢钥吹阶筮叺年?duì)列數(shù)據(jù)出現(xiàn)了一條{"data":"0"} 數(shù)據(jù),在數(shù)據(jù){"data":"1"} 上面。
來看看后臺(tái)的方法
@RequestMapping(value="/leftPop",method=RequestMethod.GET) public Object leftPop(){ return listOperations.leftPop(LIST_KEY); }
如果需要在Redis中操作,可以敲下面的命令
lpush list:1 "{\"data\":\"0\"}"
尾部插入
命令介紹
接下來看看demo中尾部插入的功能,點(diǎn)擊下圖中尾部插入按鈕,然后在彈出框中填入數(shù)字11,點(diǎn)擊提交后整個(gè)新增流程結(jié)束。可以看到左邊的隊(duì)列數(shù)據(jù)出現(xiàn)了一條{"data":"11"} 數(shù)據(jù),在數(shù)據(jù){"data":"10"}下面。
來看看后臺(tái)的方法
@RequestMapping(value="/rightPop",method=RequestMethod.GET) public Object rightPop(){ return listOperations.rightPop(LIST_KEY); }
如果需要在Redis中操作,可以敲下面的命令
rpush list:1 "{\"data\":\"11\"}"
命令介紹
同樣先看看相關(guān)的獲取值命令
后臺(tái)查詢方法,將新增的內(nèi)容查詢出來
@RequestMapping(value="/getList",method=RequestMethod.GET) public List getList(){ List list=listOperations.range(LIST_KEY, 0, -1); //可以用size獲取成員長度 //listOperations.size(LIST_KEY); return list; }
頭部彈出
接下來看看頭部彈出的功能,點(diǎn)擊下圖中頭部彈出按鈕,可以看到左邊的隊(duì)列頂部數(shù)據(jù)減少了,在右邊彈出的數(shù)據(jù)出現(xiàn)了左邊隊(duì)列數(shù)據(jù)消失的數(shù)據(jù)。
來看看后臺(tái)的方法
@RequestMapping(value="/leftPop",method=RequestMethod.GET) public Object leftPop(){ return listOperations.leftPop(LIST_KEY); }
如果需要在Redis中操作,可以敲下面的命令
lpop list:1
尾部彈出
接下來看看尾部彈出的功能,點(diǎn)擊下圖中尾部彈出按鈕,可以看到左邊的隊(duì)列尾部數(shù)據(jù)減少了,在右邊彈出的數(shù)據(jù)出現(xiàn)了左邊隊(duì)列數(shù)據(jù)消失的數(shù)據(jù)。
來看看后臺(tái)的方法
@RequestMapping(value="/rightPop",method=RequestMethod.GET) public Object rightPop(){ return listOperations.rightPop(LIST_KEY); }
如果需要在Redis中操作,可以敲下面的命令
rpop list:1
RPOPLPUSH和BRPOPLPUSH
這兩個(gè)命令作用其實(shí)是相同的,只不過BRPOPLPUSH是阻塞的,當(dāng)沒有數(shù)據(jù)時(shí),會(huì)一直阻塞,直到有數(shù)據(jù)。
在Redis官方文檔中,用RPOPLPUSH命令舉了兩個(gè)例子,一個(gè)是Reliable queue(安全的隊(duì)列 ),另一個(gè)是Circular list(循環(huán)列表)。
Reliable queue(安全的隊(duì)列 )
Redis通常都被用做一個(gè)處理各種后臺(tái)工作或消息任務(wù)的消息服務(wù)器。 一個(gè)簡單的隊(duì)列模式就是:生產(chǎn)者把消息放入一個(gè)列表中,等待消息的消費(fèi)者用 RPOP 命令(用輪詢方式), 或者用 BRPOP 命令(如果客戶端使用阻塞操作會(huì)更好)來得到這個(gè)消息。
然而,因?yàn)橄⒂锌赡軙?huì)丟失,所以這種隊(duì)列并是不安全的。例如,當(dāng)接收到消息后,出現(xiàn)了網(wǎng)絡(luò)問題或者消費(fèi)者端崩潰了, 那么這個(gè)消息就丟失了。
RPOPLPUSH (或者其阻塞版本的 BRPOPLPUSH) 提供了一種方法來避免這個(gè)問題:消費(fèi)者端取到消息的同時(shí)把該消息放入一個(gè)正在處理中的列表。 當(dāng)消息被處理了之后,該命令會(huì)使用 LREM 命令來移除正在處理中列表中的對(duì)應(yīng)消息。
另外,可以添加一個(gè)客戶端來監(jiān)控這個(gè)正在處理中列表,如果有某些消息已經(jīng)在這個(gè)列表中存在很長時(shí)間了(即超過一定的處理時(shí)限), 那么這個(gè)客戶端會(huì)把這些超時(shí)消息重新加入到隊(duì)列中。
翻譯來自 http://www.redis.cn/commands/rpoplpush.html
Circular list(循環(huán)列表)
RPOPLPUSH 命令的 source 和 destination 是相同的話, 那么客戶端在訪問一個(gè)擁有n個(gè)元素的列表時(shí),可以在 O(N) 時(shí)間里一個(gè)接一個(gè)獲取列表元素, 而不用像 LRANGE 那樣需要把整個(gè)列表從服務(wù)器端傳送到客戶端。
上面這種模式即使在以下兩種情況下照樣能很好地工作: 有多個(gè)客戶端同時(shí)對(duì)同一個(gè)列表進(jìn)行旋轉(zhuǎn)(rotating):它們會(huì)取得不同的元素,直到列表里所有元素都被訪問過,又從頭開始這個(gè)操作。 有其他客戶端在往列表末端加入新的元素。
這個(gè)模式讓我們可以很容易地實(shí)現(xiàn)這樣一個(gè)系統(tǒng):有 N 個(gè)客戶端,需要連續(xù)不斷地對(duì)一批元素進(jìn)行處理,而且處理的過程必須盡可能地快。 一個(gè)典型的例子就是服務(wù)器上的監(jiān)控程序:它們需要在盡可能短的時(shí)間內(nèi),并行地檢查一批網(wǎng)站,確保它們的可訪問性。
值得注意的是,使用這個(gè)模式的客戶端是易于擴(kuò)展(scalable)且安全的(reliable),因?yàn)榧词箍蛻舳税呀邮盏降南G失了, 這個(gè)消息依然存在于隊(duì)列中,等下次迭代到它的時(shí)候,由其他客戶端進(jìn)行處理。
翻譯來自 http://www.redis.cn/commands/rpoplpush.html
案例-約瑟夫問題
約瑟夫問題(有時(shí)也稱為約瑟夫斯置換),是一個(gè)出現(xiàn)在計(jì)算機(jī)科學(xué)和數(shù)學(xué)中的問題。在計(jì)算機(jī)編程的算法中,類似問題又稱為約瑟夫環(huán)。
人們站在一個(gè)等待被處決的圈子里。 計(jì)數(shù)從圓圈中的指定點(diǎn)開始,并沿指定方向圍繞圓圈進(jìn)行。 在跳過指定數(shù)量的人之后,執(zhí)行下一個(gè)人。 對(duì)剩下的人重復(fù)該過程,從下一個(gè)人開始,朝同一方向跳過相同數(shù)量的人,直到只剩下一個(gè)人,并被釋放。
問題即,給定人數(shù)、起點(diǎn)、方向和要跳過的數(shù)字,選擇初始圓圈中的位置以避免被處決。
來自維基百科 https://zh.wikipedia.org/wiki/%E7%BA%A6%E7%91%9F%E5%A4%AB%E6%96%AF%E9%97%AE%E9%A2%98
思路
定義一個(gè)list key為josephus,利用
RPOPLPUSH josephus josephus
命令來構(gòu)造循環(huán)鏈表,每當(dāng)數(shù)到3時(shí),使用rpop
rpop josephus
命令彈出
代碼實(shí)現(xiàn)
public class JosephusProblem extends RedisBaseConnection { @Test public void test() { //構(gòu)造數(shù)據(jù) for (int i=1; i <=41; i++) { listOperations.leftPush("josephus", String.valueOf(i)); } int index=1; while (listOperations.size("josephus") > 0) { //當(dāng)數(shù)到3時(shí),彈出 if (index==3) { System.out.println(listOperations.range("josephus", 0, -1)); System.out.println("當(dāng)前被殺的人是:" + listOperations.rightPop("josephus")); index=0; } else { listOperations.rightPopAndLeftPush("josephus", "josephus"); } index++; } } }
整個(gè)代碼步驟如下
運(yùn)行結(jié)果有點(diǎn)長,這里只截圖最后一部分的結(jié)果,如下
約瑟夫問題代碼請(qǐng)點(diǎn)擊JosephusProblem.java (https://github.com/rainbowda/learnWay/blob/master/learnRedis/command/src/main/java/com/learnRedis/list/JosephusProblem.java?spm=a2c4e.11153940.blogcont623190.24.73ec20a8Mr05v3&file=JosephusProblem.java)
建議學(xué)習(xí)的人最好每個(gè)命令都去敲下,加深印象。下面詩句送給你們。
紙上得來終覺淺,絕知此事要躬行?!鲎浴抖棺x書示子聿》
本文來自阿里云云棲社區(qū),未經(jīng)許可禁止轉(zhuǎn)載。
更多資訊,盡在云棲科技快訊~
來科技快訊看新聞鴨~
快點(diǎn)關(guān)注我認(rèn)識(shí)我愛上我啊~~~
內(nèi)容是《Web前端開發(fā)之Javascript視頻》的課件,請(qǐng)配合大師哥《Javascript》視頻課程學(xué)習(xí)。
Element.innerHTML屬性:
操作元素內(nèi)HTML內(nèi)容,即可設(shè)置或獲取使用HTML代碼表示的元素的后代;
在讀取時(shí),該屬性返回與調(diào)用元素的所有子節(jié)點(diǎn)(包括元素、注釋和文本節(jié)點(diǎn))對(duì)應(yīng)的HTML代碼字會(huì)串,如:
<div id="mydiv">
<h2>零點(diǎn)程序員</h2>
<ul id="myList">
<li>HTML</li>
<li class="current">CSS</li>
<li>JavaScript</li>
</ul>
</div>
<script>
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerHTML);
</script>
注:不同瀏覽器返回的文本格式有可能不同,比如,部分低版本會(huì)把所有標(biāo)簽轉(zhuǎn)換為大寫;另外,瀏覽器會(huì)按照原先文檔的格式返回,包括空格和縮進(jìn);
在寫入時(shí),會(huì)將給定的字符串解析為DOM子樹,將用這個(gè)DOM子樹替換調(diào)用元素原先的所有子節(jié)點(diǎn);如果設(shè)置的值是文本沒有HTML標(biāo)簽,其結(jié)果就是純文本,也就是文本節(jié)點(diǎn),此時(shí),如果該文本節(jié)點(diǎn)包含字符&、<或>, innerHTML將這些字符分別返回為&、<和>;
mydiv.innerHTML="零點(diǎn)程序員 & zeronetwork 主講><b>\"王唯\"</b>";
console.log(mydiv.innerHTML);
mydiv.innerHTML="零點(diǎn)程序員";
設(shè)置元素的innerHTML屬性將會(huì)刪除該元素的所有后代,因此,如果要保留原來的內(nèi)容,可以在innerHTML屬性的基礎(chǔ)上,可以使用+=進(jìn)行賦值,也就達(dá)到了追加內(nèi)容的效果;
mydiv.innerHTML +="<b>大師哥王唯</b>";
如果設(shè)置innerHTML屬性時(shí),使用了不合法的HTML代碼,瀏覽器會(huì)自動(dòng)修正,但要避免出現(xiàn)這種問題;
另外,不允許document對(duì)象使用該屬性,如果使用了,會(huì)靜默失??;
設(shè)置了innerHTML屬性后,可以像訪問文檔中的其他節(jié)點(diǎn)一樣訪問新創(chuàng)建的節(jié)點(diǎn);
console.log(mydiv.childNodes);
從本質(zhì)上來看,設(shè)置innerHTML屬性,瀏覽器會(huì)把給定的值被解析為HTML或者XML,結(jié)果就是一個(gè)DocumentFragment對(duì)象,其中保存著代表元素的DOM節(jié)點(diǎn),然后再append到元素中;
innerHTML也有一些限制,在多數(shù)瀏覽器中,通過innerHTML插入的<script> 元素不會(huì)被執(zhí)行,因?yàn)橛锌赡軙?huì)產(chǎn)生潛在的安全問題;
var content=document.getElementById("content");
content.innerHTML="<script>alert('wangwei');<\/script>";
即使如此,使用innerHTML屬性也不能消除潛在的風(fēng)險(xiǎn),比如,繞過<script>標(biāo)簽,把腳本綁定到相關(guān)的事件中;
mydiv.innerHTML="<img src='nourl' onerror='alert(\"加載圖片出錯(cuò)啦\")'>";
通過innerHTML寫入<style>元素就可以運(yùn)行;如:
mydiv.innerHTML="<style>body{background-color:purple;}</style>";
// 放在head中
document.head.innerHTML +="<style>body{background-color:purple;}</style>";
console.log(document.head.innerHTML);
在設(shè)置innerHTML屬性時(shí),雖然元素的所有子元素被替換,其仍被保存在內(nèi)存中,如果事先有變量在引用這些子元素,在設(shè)置innerHTML后,這些變量仍將保持對(duì)原始子元素的引用;
var mydiv=document.getElementById("mydiv");
var h2=mydiv.querySelector("h2");
mydiv.innerHTML="新內(nèi)容";
console.log(h2);
mydiv.appendChild(h2);
并不是所有元素都有innerHTML屬性,不支持的有<col> <colgroup> <frameset> <head> <html> <style> <table> <tbody> <thead> <tfoot> <title> <tr>
無論什么時(shí)候插入外界的HTML內(nèi)容時(shí),都應(yīng)該對(duì)HTML進(jìn)行無害化處理,IE8提供了window.toStaticHTML()方法,接受一個(gè)HTM字符串,返回一個(gè)經(jīng)過無害化處理后的版本;
var mydiv=document.getElementById("mydiv");
var text="<a href='#' onclick='alert(\"hi\")'>zeronetwork</a>";
// mydiv.innerHTML=text;
var sanitized=window.toStaticHTML(text); // [?s?n?ta?zd]
console.log(sanitized); // 非IE會(huì)拋出異常
mydiv.innerHTML=sanitized;
小示例:
使用innerHTML創(chuàng)建一種機(jī)制用于將消息記錄到頁面中的一個(gè)元素中;
<style>
.box{width: 600px;height: 300px;
border:1px solid black; padding: 2em; overflow: hidden scroll;}
</style>
<div class="box">
<h2>日志:</h2>
<div class="log"></div>
</div>
<script>
function log(msg){
var logEle=document.querySelector(".log");
var time=new Date().toLocaleTimeString();
logEle.innerHTML +=time + ": " + msg + "<br/>";
}
// log("打印一些數(shù)據(jù)");
// 定義一個(gè)事件處理程序
function logEvent(event){
var msg="Event <strong>" + event.type + "</strong> at <em>" +
event.clientX + "," + event.clientY + "</em>";
log(msg);
}
// 綁定事件處理程序
var boxEle=document.querySelector(".box");
boxEle.addEventListener("mousedown", logEvent);
boxEle.addEventListener("mouseup", logEvent);
boxEle.addEventListener("click", logEvent);
boxEle.addEventListener("mouseenter", logEvent);
boxEle.addEventListener("mouseleave", logEvent);
</script>
Element.outerHTML屬性:
與innerHTML屬性基本一致,不同點(diǎn)是,innerHTML是訪問和設(shè)置元素的所有子節(jié)點(diǎn),而outerHTML屬性不僅包括它的所有子節(jié)點(diǎn),也包括它本身;
console.log(mydiv.outerHTML);
mydiv.outerHTML="<p><h2>零點(diǎn)網(wǎng)絡(luò)</h2></p>";
如果元素沒有父元素,即如果它是文檔的根元素,在設(shè)置其outerHTML屬性將拋出異常,如:
document.documentElement.outerHTML="content"; // 異常
這個(gè)屬性應(yīng)用的機(jī)會(huì)非常少;
HTMLElement.innerText屬性:
可以操作元素中包含的所有文本,最初是由IE實(shí)現(xiàn)的,后來被納入標(biāo)準(zhǔn)中;
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerText);
mydiv.innerText="零點(diǎn)程序員";
console.log(mydiv.innerText);
輸出一個(gè)文檔樹時(shí),無論文本位于文檔樹中的什么位置,會(huì)按照由淺入深的順序,將子文檔樹中的所有文本拼接起來;
<div id="content">
<p>零點(diǎn)網(wǎng)絡(luò)<strong>zerontwork</strong>是一家從事IT教育的公司</p>
<ul>
<li>HTML</li>
<li>CSS</li>
<li>Javascript</li>
</ul>
</div>
<script>
var content=document.getElementById("content");
console.log(content.innerText);
// 返回
// 零點(diǎn)網(wǎng)絡(luò)zerontwork是一家從事IT教育的公司
//
// HTML/
// CSS
// Javascript
</script>
由于不同瀏覽器處理空白字符的方式不同,因此輸出的文本可能會(huì)也可能不會(huì)包含原始的HTML代碼中的縮進(jìn);
使用innerText屬性設(shè)置內(nèi)容時(shí),會(huì)移除原先所有的子節(jié)點(diǎn),將永遠(yuǎn)只會(huì)生成當(dāng)前節(jié)點(diǎn)的一個(gè)子文本節(jié)點(diǎn);如果設(shè)置的內(nèi)容包括HTML標(biāo)簽,會(huì)自動(dòng)被轉(zhuǎn)碼,也就是說,會(huì)對(duì)所有出現(xiàn)在文本中的HTML語法字符進(jìn)行編碼(>、<、”、&);
mydiv.innerText="<h2>wangwei</h2>"; // < > 會(huì)被轉(zhuǎn)義
因?yàn)樵谠L問innerText屬性時(shí),其會(huì)過濾掉html標(biāo)簽,所以可以利用它的這個(gè)特點(diǎn),快速過濾掉元素的HTML標(biāo)簽,即把innerText設(shè)置為innerText;
content.innerText=content.innerText;
console.log(content.innerText);
如果在設(shè)置innerHTML屬性時(shí),賦給的就是純文本字符串,那它就與innerText屬性作用一樣了;
var mydiv=document.getElementById("mydiv");
mydiv.innerText="零點(diǎn)網(wǎng)絡(luò) zeronetwork";
mydiv.innerHTML="零點(diǎn)網(wǎng)絡(luò) zeronetwork";
mydiv.innerText="零點(diǎn)網(wǎng)絡(luò)\nzeronetwork"; // 有br
mydiv.innerHTML="零點(diǎn)網(wǎng)絡(luò)\nzeronetwork"; // 無br,但源碼格式有換行
因?yàn)閕nnerHTML是解析html標(biāo)簽的,而\n不是標(biāo)簽,所以當(dāng)作空格被忽略了;但在innerText中,瀏覽器遇到\n,就會(huì)執(zhí)行換行,所以把它解析為<br>;
在實(shí)際使用中,如果要過濾html標(biāo)簽,可以使用正則,如:
// 去除html標(biāo)簽可以使用正則
content.innerHTML=content.innerHTML.replace(/<.+?>/img,"");
console.log(content.innerText); // 沒有格式<br>
console.log(content.innerHTML); // 沒有格式<br>
HTMLElement.outerText屬性:
與innerText一樣,只不過替換的是元素(包括子節(jié)點(diǎn))本身;其是一個(gè)非標(biāo)準(zhǔn)屬性;
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerText);
console.log(mydiv.outerText); // 返回值與innerText一致
在讀取文本值時(shí),outerText和innerText的結(jié)果完全一樣;
但在寫模式下,outerText就完全不同了,其本身都會(huì)被新的文本節(jié)點(diǎn)都替代,從文檔中被刪除,但其仍然被保存在內(nèi)存中,如果有變量引用,還可以再利用;
mydiv.outerText="零點(diǎn)程序員";
console.log(mydiv); // 依然保留著原有的引用
FF不支持outerText屬性,如:
mydiv.outerText="零點(diǎn)程序員"; // 在FF中失效
// 在FF中返回undefined,如果有上一行,會(huì)打印出“零點(diǎn)程序員”,但這和內(nèi)置的outerText沒有關(guān)系
console.log(mydiv.outerText);
在實(shí)際使用中,只會(huì)用到innerHTML和innerText,其他兩個(gè)一般不用,也沒有多大的實(shí)際意義;
Node.textContent屬性:
DOM3規(guī)定了一個(gè)屬性textContent,該屬性被定義在Node接口中,它的作用類似innerText屬性,返回一個(gè)節(jié)點(diǎn)及其后代的所有文本內(nèi)容;
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerText);
console.log(mydiv.textContent); // 返回值與innerText基本一致,但格式不一樣
如果設(shè)置textContent屬性,會(huì)刪除該元素的所有子節(jié)點(diǎn),并被替換為包含指定字符串的一個(gè)單獨(dú)的文本節(jié)點(diǎn);
var mydiv=document.getElementById("mydiv");
mydiv.textContent="大師哥王唯";
mydiv.textContent="<h3>大師哥王唯</h3>"; // 會(huì)被轉(zhuǎn)碼
console.log(mydiv.textContent);
console.log(mydiv.childNodes); // NodeList [text]
如果節(jié)點(diǎn)是文本節(jié)點(diǎn),此屬性可用于取代 nodeValue 屬性,如;
var h2=document.querySelector("h2").firstChild; // 取得文本節(jié)點(diǎn)
console.log(h2.textContent); // zeronetwork
console.log(h2.nodeValue); // zeronetwork
h2.nodeValue="零點(diǎn)程序員";
console.log(h2.textContent); // 零點(diǎn)程序員
console.log(h2.nodeValue); // 零點(diǎn)程序員
可以看出,兩者是聯(lián)動(dòng)的;
如果事先有變量引用著它的后代節(jié)點(diǎn),即使節(jié)點(diǎn)使用該方法移除所有后代節(jié)點(diǎn),但被引用的后代節(jié)點(diǎn)依然存在,可以被再次利用;
var content=document.getElementById("content");
var h2=content.querySelector("h2"); // content中的h2
content.textContent="王唯";
console.log(content.textContent);
console.log(h2); // <h2>zeronetwork</h2>
console.log(h2.parentElement); // null
var mydiv=document.getElementById("mydiv");
mydiv.appendChild(h2);
與innerText屬性的區(qū)別:
兩者的返回的內(nèi)容并不完全一樣,比如在輸出的格式上其與innerText是不同的,其會(huì)保留代碼中的空白符;同時(shí),innerText針對(duì)表格,會(huì)試圖保留表格的格式;
var mytable=document.getElementById("mytable");
console.log(mytable.innerText);
console.log(mytable.textContent);
textContent屬性會(huì)返回元素的所有內(nèi)容,包括其中的樣式和腳本代碼,而innerText只返回能呈現(xiàn)在頁面上的元素;
// 在mydiv中添加<style>和<script>標(biāo)簽
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerText); // 不包括<style>和<script>
// 包括<style>和<script>標(biāo)簽內(nèi)的內(nèi)容,但該標(biāo)簽被過濾了
console.log(mydiv.textContent);
既然innerText只返回能呈現(xiàn)在頁面上的元素,所以它的返回值會(huì)受CSS樣式的影響,不會(huì)返回被CSS隱藏的元素的文本;
<!-- textContent返回值沒有變化,但innerText不包括"HTML"和"CSS" -->
<ul id="mylist">
<li style="visibility: hidden;">HTML</li>
<li style="display: none;">CSS</li>
<li>JavaScript</li>
</ul>
textContent屬性能返回文本節(jié)點(diǎn)的文本內(nèi)容,而innerText會(huì)返回undefined;如果是文本節(jié)點(diǎn)調(diào)用textContent屬性,其返回值與nodeValue一致;
innerHTML有可能會(huì)引發(fā)安全問題,但textConent卻不會(huì);
mydiv.innerHTML="<img src='nourl' onerror='alert(\"加載圖片出錯(cuò)啦\")'>";
mydiv.textContent="<img src='nourl' onerror='alert(\"加載圖片出錯(cuò)啦\")'>";
console.log(mydiv.childNodes); // index.html:20 NodeList [text]
第一行的onerror會(huì)被執(zhí)行,第二行不會(huì)執(zhí)行,并且其被解析為文本節(jié)點(diǎn),如此,textContent不會(huì)引發(fā)安全問題;
所有主流的瀏覽器都支持textContent屬性,但I(xiàn)E8及以下不支持,可以包裝一個(gè)兼容的函數(shù):
function getInnerText(element){
return (typeof element.textContent=="string") ? element.textContent : element.innerText;
}
function setInnerText(element, text){
if(typeof element.textContent=="string")
element.textContent=text;
else
element.innerText=text;
}
document.write(getInnerText(content));
setInnerText(content, "零點(diǎn)程序員");
或者直接定義在Node.prototype中:
if(Object.defineProperty
&& Object.getOwnPropertyDescriptor
&& !Object.getOwnPropertyDescriptor(Node.prototype, "textContent")){
(function(){
var innerText=Object.getOwnPropertyDescriptor(HTMLElement.prototype, "innerText");
Object.defineProperty(Node.prototype, "textContent",{
get: function(){
return innerText.get.call(this);
},
set: function(s){
return innerText.set.call(this, s);
}
});
})();
}
<script>元素中的文本:
內(nèi)聯(lián)的<script>元素有一個(gè)text屬性用來獲取它們的文本;
<script>
console.log("function");
function func(){return true;}
</script>
<script>
var script=document.getElementsByTagName("script")[0];
console.log(script.innerText);
console.log(script.textContent);
console.log(script.text); // 三者輸出一致
</script>
如果將<script>元素的type屬性設(shè)置為”text/x-custom-data”,就表明了腳本為不可執(zhí)行的Javascript代碼,如此,Javascript解析器將忽略該腳本,這也使得<script>元素可以被用來嵌入任意文本內(nèi)容;
<script type="text/x-custom-data">
console.log("function");
function func(){return true;}
</script>
<script>
var script=document.getElementsByTagName("script")[0];
console.log(script.innerText);
console.log(script.textContent);
console.log(script.text); // 三者輸出一致
</script>
<script type="text/x-custom-data">
<div style="border:1px solid red; width:300px;">
<h2>視頻教程</h2>
</div>
</script>
<script>
var script=document.getElementsByTagName("script")[0];
var mydiv=document.getElementById("mydiv");
mydiv.innerHTML=script.text;
</script>
Element.insertAdjacentHTML(position, text)方法:
該方法會(huì)將任意的HTML字符串text解析為Element元素,并將結(jié)果節(jié)點(diǎn)插入到DOM樹中的指定的元素”相鄰”的position位置;該方法最早是在IE4中出現(xiàn)的;它接收兩個(gè)參數(shù):插入位置和要插入的HTML文本;
第一個(gè)參數(shù)position的可能值:
第二個(gè)參數(shù)text為HTML字符串,如果瀏覽器無法解析,會(huì)拋出錯(cuò)誤,如;
var mydiv=document.getElementById("mydiv");
mydiv.insertAdjacentHTML("beforebegin","<p>前一個(gè)同輩元素</p>");
mydiv.insertAdjacentHTML("afterbegin","<p>作為第一個(gè)子元素</p>");
mydiv.insertAdjacentHTML("beforeend","<p>最后一個(gè)子元素</p>");
mydiv.insertAdjacentHTML("afterend","<p>后一個(gè)同輩元素</p>");
insertAdjacentHTML()方法同innerHTML屬性一樣,會(huì)遇到安全問題,在使用該屬性插入HTML內(nèi)容時(shí),需要轉(zhuǎn)義之后才能使用;
另外,如果元素沒有子元素的時(shí)候,其和innerHTML就非常相像了;
var newdiv=document.createElement("div");
newdiv.insertAdjacentHTML("afterbegin", "<p>零點(diǎn)程序員</p>");
// 同以下
newdiv.innerHTML="<p>零點(diǎn)程序員</p>";
document.body.appendChild(newdiv);
需要注意的是,如果position為beforebegin或afterend,那該元素必須具有一個(gè)parent元素;
var newdiv=document.createElement("div");
// 異常:The element has no parent,此時(shí)newdiv并沒有被添加到DOM樹中,它并沒有父節(jié)點(diǎn),但是如果把下面行互換一下,就可以了;
newdiv.insertAdjacentHTML("afterend", "<p>零點(diǎn)程序員</p>");
document.body.appendChild(newdiv);
基于insertAdjacentHTML()方法定義一個(gè)更符合語義邏輯的一個(gè)對(duì)象,如:
// Insert.before()、Insert.after()、Insert.atStart()和Insert.atEnd()
var Insert={
before: function(e,h) {
if(e.parentElement)
e.insertAdjacentHTML("beforebegin", h);
},
after: function(e,h) {
if(e.parentElement)
e.insertAdjacentHTML("afterend", h);
},
atStart: function(e,h) {e.insertAdjacentHTML("afterbegin", h);},
atEnd: function(e,h) {e.insertAdjacentHTML("beforeend", h);}
};
var mydiv=document.getElementById("mydiv");
Insert.before(mydiv, "<h2>zeronetwork</h2>");
// 或者
// 假定where值為before、after、innerfirst和innerlast
function insertHTML(el, where, html){
if(!el) return false;
var _where="beforeend";
switch(where){
case "before":
_where="beforebegin";
break;
case "after":
_where="afterend";
break;
case "innerfirst":
_where="afterbegin";
break;
case "innerlast":
_where="beforeend";
break;
default:
_where="beforeend";
break;
}
if(_where=="beforebegin" || _where=="afterend"){
if(!el.parentElement)
return false;
}
el.insertAdjacentHTML(_where, html);
}
var mydiv=document.getElementById("mydiv");
insertHTML(mydiv, "innerfirst", "<h2>zeronetwork</h2>");
小示例,添加商品:
<div class="container">
<div class="formdiv">
<label>商品:</label><input type="text" id="product" /><br/>
<label>價(jià)格:</label><input type="text" id="price" /><br/>
<label>數(shù)量:</label><input type="text" id="quantity" /><br/>
<button id="btnAdd">添加</button>
</div>
<table class="table">
<thead>
<tr>
<th>序號(hào)</th><th>商品</th><th>價(jià)格</th><th>數(shù)量</th><th>金額</th>
</tr>
</thead>
<tbody id="data"></tbody>
</table>
</div>
<script>
var id=1;
var btnAdd=document.getElementById("btnAdd");
btnAdd.addEventListener("click",function(e){
var content=document.getElementById("data");
var product=document.getElementById("product").value;
var price=document.getElementById("price").value;
var quantity=document.getElementById("quantity").value;
var total=price * quantity;
var newEntry="<tr>" +
"<td>" + id + "</td>" +
"<td>" + product + "</td>" +
"<td>" + price + "</td>" +
"<td>" + quantity + "</td>" +
"<td>" + total + "</td>" +
"</tr>";
content.insertAdjacentHTML('afterbegin', newEntry);
id++;
},false);
</script>
Element.insertAdjacentText(position, text)方法:
該方法與insertAdjacentHTML()類似,只不過插入的是純文本內(nèi)容,它的作用是將一個(gè)給定的文本text插入到相對(duì)于被調(diào)用的元素的給定position位置;
position的值insertAdjacentHTML()中的position是一樣的;
var mydiv=document.getElementById("mydiv");
mydiv.insertAdjacentText("afterbegin","王唯");
mydiv.insertAdjacentText("afterend","zeronetwork");
如果text是html字符串,也會(huì)被當(dāng)作純文本進(jìn)行處理,如:
// 頁面輸出:<h2>王唯</h2>
mydiv.insertAdjacentText("afterbegin","<h2>王唯</h2>");
Element. insertAdjacentElement(position, element)方法:
將一個(gè)給定的元素節(jié)點(diǎn)插入到相對(duì)于被調(diào)用的元素的給定的position位置;與insertAdjacentHTML()方法類似,只不過插入的是一個(gè)節(jié)點(diǎn)對(duì)象;該方法會(huì)返回一個(gè)Element對(duì)象;
var mydiv=document.getElementById("mydiv");
var div=document.createElement("div");
div.innerHTML="<h2>zeronetwork</h2>";
div.style.width="200px";
div.style.height="100px";
div.style.backgroundColor="lightgray";
var newdiv=mydiv.insertAdjacentElement("beforeend", div);
console.log(div===newdiv); // true
github上有人分享了一個(gè)包裝的方法,就是利用以上原生的方法;
// 把一個(gè)節(jié)點(diǎn)插入到DOM樹中的一個(gè)位置
function dominsert(parent, child, position){
var pos=position || 'beforeend';
if(typeof child==='string')
dominsert.html(parent, child, pos);
else
dominsert.element(parent, child, pos);
}
// 使用原生的insertAdjacentHTML()方法
dominsert.html=function(parent, child, position){
parent.insertAdjacentHTML(position, child);
};
// 使用原生的insertAdjacentElement()或insertBefore()方法
dominsert.element=function(parent, child, position){
if(parent.insertAdjacentElement)
parent.insertAdjacentElement(position, child);
else{
switch (position){
case "beforebegin":
parent.parentNode.insertBefore(child, parent);
break;
case "afterbegin":
parent.insertBefore(child, parent.firstChild);
break;
case "beforeend":
parent.appendChild(child);
break;
case "afterend":
parent.parentNode.insertBefore(child, parent.nextSibling);
break;
}
}
};
var mydiv=document.getElementById("mydiv");
dominsert(mydiv,"<span>web前端</span>");
dominsert(mydiv, "<b>零點(diǎn)程序員</b>", 'beforebegin');
console.log(mydiv);
內(nèi)存和性能問題:
使用以上的方法替換子節(jié)點(diǎn)可能會(huì)導(dǎo)致瀏覽器的內(nèi)存占用問題,尤其是在IE中,問題更加明顯;
如果被刪除的子樹中的元素設(shè)置了事件處理程序或者引用了一個(gè)Javascript對(duì)象作為屬性,被刪除的元素與事件處理程序或引用的JS對(duì)象之間的綁定關(guān)系在內(nèi)存中并沒有一并刪除;如果這種情況頻繁出現(xiàn),頁面占用的內(nèi)存數(shù)量就會(huì)明顯增加;因此,在使用innerHTML、outerHTML屬性和insertAdjacentHTML()方法時(shí),最好手工先移除要被替換的元素的所有事件處理程序和JS對(duì)象屬性;
不要反復(fù)地使用innerHTML插入HTML;
var arr=["HTML","CSS","JavaScript"];
var ul=document.getElementById("myList");
for(var i=0,len=arr.length; i < len; i++){
ul.innerHTML +="<li>" + arr[i] + "</li>";
}
,最好的做法是:單獨(dú)構(gòu)建字符串變量,再一次性的把結(jié)果賦給innerHTML;
console.time("insert");
var lisHTML="";
for(var i=0,len=arr.length; i<len;i++){
lisHTML +="<li>" + arr[i] + "</li>";
}
ul.innerHTML=lisHTML;
console.timeEnd("insert");
adjacent三個(gè)方法與insertBefore()、appendChild()和innerHTML的比較;
在某些時(shí)候,這些方法屬性都可以達(dá)到同樣的目的,但在實(shí)際開發(fā)中,要針對(duì)當(dāng)時(shí)的情況,選擇一個(gè)合適的方法,沒有哪個(gè)方法就一定比另外的方法更好,只有相對(duì)的合適;
同時(shí),這三個(gè)方法的性能雖然不一樣,但相差不大,幾乎可以忽略;
insertAdjacentHTML()與innerHTML屬性的性能:
insertAdjacentHTML()方法不會(huì)重新解析它正在使用的元素,因此它不會(huì)破壞元素內(nèi)的現(xiàn)有元素,這就避免了額外的序列化步驟,但使用innerHTML時(shí),特別是在原有的基礎(chǔ)上追加元素時(shí),都會(huì)對(duì)原有的元素重新序列化,因此,前者比后者效率更快;
appendChild()與insertAdjacentHTML()方法的性能;
// time 10ms
console.time("append");
for(var i=0; i<1000; i++)
mydiv.appendChild(document.createElement("div"));
console.timeEnd("append");
// tim 30ms
console.time("adjacent");
for(var i=0; i<1000; i++)
mydiv.insertAdjacentHTML("beforeend","<div></div>");
console.timeEnd("adjacent");
可以看到appendChild()方法比insertAdjacentHTML()方法快很多,但是改進(jìn)以上代碼后,為其添加有文本內(nèi)容的元素,如;
// time 30ms多
console.time("append");
for(var i=0; i<1000; i++){
var div=document.createElement("div");
var h2=document.createElement("h2");
h2.appendChild(document.createTextNode("零點(diǎn)程序員"));
div.appendChild(h2);
var p=document.createElement("p");
p.appendChild(document.createTextNode("由大師哥王唯主講"));
div.appendChild(p);
mydiv.appendChild(div);
}
console.timeEnd("append");
// time 40ms多
console.time("adjacent");
for(var i=0; i<1000; i++)
mydiv.insertAdjacentHTML("beforeend","<div><h2>零點(diǎn)程序員</h2><p>由大師哥王唯主講</p></div>");
console.timeEnd("adjacent");
可以看到,兩者相差10ms,幾乎可以忽略不計(jì);
比較appendChild()與insertAdjacentElement方法的性能;
如:把測(cè)試appendChild()方法中的mydiv.appendChild(div)改成mydiv.insertAdjacentElement("beforeend", div);即可;
發(fā)現(xiàn)兩者幾乎相同;
比較insertBefore()與以上兩者的性能;
如:把測(cè)試appendChild()方法中的mydiv.appendChild(div),改成mydiv.insertBefore(div, mydiv.lastChild);,結(jié)束也大同小異;
小實(shí)例,排序表格;
基于表格指定列中單元格的值來進(jìn)行排序;
<table id="mytable" border="1">
<thead>
<tr>
<th>ID</th><th>Name</th><th>Sex</th>
</tr>
</thead>
<tbody>
<tr>
<td>1</td><td>wangwei</td><td>女</td>
</tr>
<tr>
<td>2</td><td>jingjing</td><td>男</td>
</tr>
<tr>
<td>3</td><td>juanjuan</td><td>女</td>
</tr>
</tbody>
</table>
<script>
// 根據(jù)指定表格每行第n個(gè)單元格的值,對(duì)第一個(gè)<tbody>中的行進(jìn)行排序
// 如果存在comparator函數(shù)則使用它,否則按字母表順序比較
function sortrows(table, n, comparator){
var tbody=table.tBodies[0]; // 第一個(gè)<tbody>,可能是隱式創(chuàng)建的
var rows=tbody.getElementsByTagName("tr"); // tbody中所有行
rows=Array.prototype.slice.call(rows, 0); // 變成數(shù)組
// 基于第n個(gè)<td>元素的值進(jìn)行排序
rows.sort(function(row1, row2){
var cell1=row1.getElementsByTagName("td")[n]; // 獲得第n個(gè)單元格
var cell2=row2.getElementsByTagName("td")[n]; // 同上
var val1=cell1.textContent || cell1.innerText; // 獲得文本內(nèi)容
var val2=cell2.textContent || cell2.innerText;
if(comparator) return comparator(val1,val2); // 進(jìn)行排序
if(val1 < val2) return -1;
else if(val1 > val2) return 1;
else return 0;
});
// rows中已經(jīng)排好序,在tbody中按它們的順序把行添加到最后
// 這將自動(dòng)把它們從當(dāng)前位置移走,并不是刪除,而是移動(dòng)
for(var i=0; i<rows.length; i++){
tbody.appendChild(rows[i]);
}
}
// 查找元素的<th>元素,讓它們可單擊,可以按該列排序
function makeSortable(table){
var headers=table.getElementsByTagName("th");
for(var i=0; i<headers.length; i++){
(function(n){
headers[i].onclick=function() {
sortrows(table, n);
};
}(i));
}
}
var mytable=document.getElementById("mytable");
makeSortable(mytable);
</script>
小實(shí)例,生成目錄表:
<style>
#TOC{border:solid black 1px; margin:10px; padding: 10px;}
.TOCEntry{}
.TOCEntry a{text-decoration: none;}
.TOCLevel1{font-size: 2em;}
.TOCLevel2{font-size: 1.5em; margin-left: 1em;}
.TOCSectNum::after{content: ": ";}
</style>
<script>
// 當(dāng)執(zhí)行這個(gè)函數(shù)時(shí)會(huì)去文檔中查找id為"TOC"的元素;
// 如果這個(gè)元素不存在,就創(chuàng)建一個(gè)元素
// 生成的TOC目錄應(yīng)當(dāng)具有自己的CSS樣式,整個(gè)目錄區(qū)域的樣式className設(shè)置為"TOCEntry";
// 為不同層級(jí)的目錄標(biāo)題定義不同的樣式,<h1>標(biāo)簽生成的標(biāo)題className為"TOCLevel1",
// <h2>標(biāo)簽生成的標(biāo)題className為”TOCLevel2“,以此類推;段編號(hào)的樣式為"TOCSectNum"
function createToc(){
// 查找TOC容器元素,如果不存在,則在文檔開頭處創(chuàng)建一個(gè)
var toc=document.getElementById("TOC");
if(!toc){
toc=document.createElement("div");
toc.id="TOC";
document.body.insertBefore(toc, document.body.firstChild);
}
// 查找所有的標(biāo)題元素
var headings;
if(document.querySelectorAll)
headings=document.querySelectorAll("h1,h2,h3,h4,h5,h6");
else
headings=findHeadings(document.body, []);
// 遞歸遍歷document的body,查找標(biāo)題元素
function findHeadings(orrt, sects){
for(var c=root.firstChild; c!=null; c=c.nextSibling){
if(c.nodeType !==1) continue;
if(c.tagName.length==2 && c.tagName.charAt(0)=="H")
sects.push(c);
else
findHeadings(c, sects);
}
return sects;
}
// 初始化一個(gè)數(shù)組來保存跟蹤章節(jié)號(hào)
var sectionNumbers=[0,0,0,0,0,0];
// 循環(huán)找到所有標(biāo)題元素
for(var h=0; h<headings.length; h++){
var heading=headings[h];
// 跳過在TOC容器中的標(biāo)題元素
if(heading.parentNode==toc) continue;
// 獲取標(biāo)題的級(jí)別
var level=parseInt(heading.tagName.charAt(1));
if(isNaN(level) || level < 1 || level > 6) continue;
// 對(duì)于該標(biāo)題級(jí)別增加sectionNumbers對(duì)應(yīng)的數(shù)字
// 并重置所有標(biāo)題比它級(jí)別低的數(shù)字為零
sectionNumbers[level-1]++;
for(var i=level; i<6; i++) sectionNumbers[i]=0;
// 將所有標(biāo)題級(jí)的章節(jié)號(hào)組合產(chǎn)生一個(gè)章節(jié)號(hào),如2.3.1
var sectionNumber=sectionNumbers.slice(0, level).join(".");
// 為標(biāo)題級(jí)別增加章節(jié)號(hào)
// 把數(shù)字放在<span>中,使得其可以秀樣式修飾
var span=document.createElement("span");
span.className="TOCSectNum";
span.innerHTML=sectionNumber;
heading.insertBefore(span, heading.firstChild);
// 用命名的錨點(diǎn)將標(biāo)題包起來,以便為它增加鏈接
var anchor=document.createElement("a");
anchor.name="TOC" + sectionNumber;
heading.parentNode.insertBefore(anchor, heading);
anchor.appendChild(heading);
// 為該節(jié)創(chuàng)建一個(gè)鏈接
var link=document.createElement("a");
link.href="#TOC" + sectionNumber; // 鏈接目標(biāo)地址
link.innerHTML=heading.innerHTML; // 鏈接文本與實(shí)際標(biāo)題一致
// 將鏈接放在一個(gè)div中,div用基于級(jí)別名字的樣式修飾
var entry=document.createElement("div");
entry.className="TOCEntry TOCLevel" + level;
entry.appendChild(link);
// 該div添加到TOC容器中
toc.appendChild(entry);
}
};
window.onload=function(){createToc();}
</script>
Web前端開發(fā)之Javascript
*請(qǐng)認(rèn)真填寫需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。