avaScript 数组用于在单一变量中存储多个值。
var cars=["Saab", "Volvo", "BMW"];
数组是一种特殊的变量,它能够一次存放一个以上的值。
如果您有一个项目清单(例如,汽车品牌列表),在单个变量中存储汽车品牌应该是这样的:
var car1="Saab";
var car2="Volvo";
var car3="BMW";
不过,假如您希望遍历所有汽车并找到一个特定的值?假如不是三个汽车品牌而是三百个呢?
解决方法就是数组!
数组可以用一个单一的名称存放很多值,并且还可以通过引用索引号来访问这些值。
使用数组文本是创建 JavaScript 数组最简单的方法。
var array-name=[item1, item2, ...];
var cars=["Saab", "Volvo", "BMW"];
空格和折行并不重要。声明可横跨多行:
var cars=[
"Saab",
"Volvo",
"BMW"
];
请不要最后一个元素之后写逗号(比如 "BMW",)。
可能存在跨浏览器兼容性问题。
下面的例子也会创建数组,并为其赋值:
var cars=new Array("Saab", "Volvo", "BMW");
以上两个例子效果完全一样。无需使用 new Array()。
出于简洁、可读性和执行速度的考虑,请使用第一种方法(数组文本方法)。
我们通过引用索引号(下标号)来引用某个数组元素。
这条语句访问 cars 中的首个元素的值:
var name=cars[0];
这条语句修改 cars 中的首个元素:
cars[0]="Opel";
var cars=["Saab", "Volvo", "BMW"];
document.getElementById("demo").innerHTML=cars[0];
[0] 是数组中的第一个元素。[1] 是第二个。数组索引从 0 开始。
这条语句修改了 cars 中第一个元素的值:
cars[0]="Opel";
var cars=["Saab", "Volvo", "BMW"];
cars[0]="Opel";
document.getElementById("demo").innerHTML=cars[0];
通过 JavaScript,可通过引用数组名来访问完整数组:
var cars=["Saab", "Volvo", "BMW"];
document.getElementById("demo").innerHTML=cars;
数组是一种特殊类型的对象。在 JavaScript 中对数组使用 typeof 运算符会返回 "object"。
但是,JavaScript 数组最好以数组来描述。
数组使用数字来访问其“元素”。在本例中,person[0] 返回 Bill:
var person=["Bill", "Gates", 62];
对象使用名称来访问其“成员”。在本例中,person.firstName 返回 Bill:
var person={firstName:"Bill", lastName:"Gates", age:19};
JavaScript 变量可以是对象。数组是特殊类型的对象。
正因如此,您可以在相同数组中存放不同类型的变量。
您可以在数组保存对象。您可以在数组中保存函数。你甚至可以在数组中保存数组:
myArray[0]=Date.now;
myArray[1]=myFunction;
myArray[2]=myCars;
JavaScript 数组的真实力量隐藏在数组的属性和方法中:
var x=cars.length; // length 属性返回元素的数量
var y=cars.sort(); // sort() 方法对数组进行排序
我们将在下一章学习数组方法。
length 属性返回数组的长度(数组元素的数目)。
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.length; // fruits 的长度是 4
length 属性始终大于最高数组索引(下标)。
fruits=["Banana", "Orange", "Apple", "Mango"];
var first=fruits[0];
fruits=["Banana", "Orange", "Apple", "Mango"];
var last=fruits[fruits.length - 1];
遍历数组的最安全方法是使用 "for" 循环:
var fruits, text, fLen, i;
fruits=["Banana", "Orange", "Apple", "Mango"];
fLen=fruits.length;
text="<ul>";
for (i=0; i < fLen; i++) {
text +="<li>" + fruits[i] + "</li>";
}
您也可以使用 Array.foreach() 函数:
var fruits, text;
fruits=["Banana", "Orange", "Apple", "Mango"];
text="<ul>";
fruits.forEach(myFunction);
text +="</ul>";
function myFunction(value) {
text +="<li>" + value + "</li>";
}
向数组添加新元素的最佳方法是使用 push() 方法:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits.push("Lemon"); // 向 fruits 添加一个新元素 (Lemon)
也可以使用 length 属性向数组添加新元素:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits[fruits.length]="Lemon"; // 向 fruits 添加一个新元素 (Lemon)
添加最高索引的元素可在数组中创建未定义的“洞”:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits[6]="Lemon"; // 向 fruits 添加一个新元素 (Lemon)
很多编程元素支持命名索引的数组。
具有命名索引的数组被称为关联数组(或散列)。
JavaScript 不支持命名索引的数组。
在 JavaScript 中,数组只能使用数字索引。
var person=[];
person[0]="Bill";
person[1]="Gates";
person[2]=62;
var x=person.length; // person.length 返回 3
var y=person[0]; // person[0] 返回 "Bill"
假如您使用命名索引,JavaScript 会把数组重定义为标准对象。
之后,所有数组的方法和属性将产生非正确结果。
var person=[];
person["firstName"]="Bill";
person["lastName"]="Gates";
person["age"]=62;
var x=person.length; // person.length 将返回 0
var y=person[0]; // person[0] 将返回 undefined
在 JavaScript 中,数组使用数字索引。
在 JavaScript 中,对象使用命名索引。
数组是特殊类型的对象,具有数字索引。
没有必要使用 JavaScript 的内建数组构造器 new Array()。
请使用 [] 取而代之!
下面两条不同的语句创建了名为 points 的新的空数组:
var points=new Array(); // 差
var points=[]; // 优
下面两条不同的语句创建包含六个数字的新数组:
var points=new Array(40, 100, 1, 5, 25, 10); // 差
var points=[40, 100, 1, 5, 25, 10]; // 优
new 关键词只会使代码复杂化。它还会产生某些不可预期的结果:
var points=new Array(40, 100); // 创建包含两个元素的数组(40 和 100)
假如删除其中一个元素会怎么样?
var points=new Array(40); // 创建包含 40 个未定义元素的数组!!!
常见的问题是:我如何知晓某个变量是否是数组?
问题在于 JavaScript 运算符 typeof 返回 "object":
var fruits=["Banana", "Orange", "Apple", "Mango"];
typeof fruits; // 返回 object
typeof 运算符返回 "object",因为 JavaScript 数组属于对象。
为了解决这个问题,ECMAScript 5 定义了新方法 Array.isArray():
Array.isArray(fruits); // 返回 true
此方案的问题在于 ECMAScript 5 不支持老的浏览器。
创建您自己的 isArray() 函数以解决此问题:
function isArray(x) {
return x.constructor.toString().indexOf("Array") > -1;
}
假如参数为数组,则上面的函数始终返回 true。
或者更准确的解释是:假如对象原型包含单词 "Array" 则返回 true。
假如对象由给定的构造器创建,则 instanceof 运算符返回 true:
var fruits=["Banana", "Orange", "Apple", "Mango"];
fruits instanceof Array // 返回 true
创建数组,为其赋值,然后输出这些值。
<html>
<body>
<script type="text/javascript">
var mycars=new Array()
mycars[0]="Saab"
mycars[1]="Volvo"
mycars[2]="BMW"
for (i=0;i<mycars.length;i++)
{
document.write(mycars[i] + "<br />")
}
</script>
</body>
</html>
使用 for...in 声明来循环输出数组中的元素。
<html>
<body>
<script type="text/javascript">
var x
var mycars=new Array()
mycars[0]="Saab"
mycars[1]="Volvo"
mycars[2]="BMW"
for (x in mycars)
{
document.write(mycars[x] + "<br />")
}
</script>
</body>
</html>
如何使用 concat() 方法来合并两个数组。
<html>
<body>
<script type="text/javascript">
var arr=new Array(3)
arr[0]="George"
arr[1]="John"
arr[2]="Thomas"
var arr2=new Array(3)
arr2[0]="James"
arr2[1]="Adrew"
arr2[2]="Martin"
document.write(arr.concat(arr2))
</script>
</body>
</html>
如何使用 join() 方法将数组的所有元素组成一个字符串。
<html>
<body>
<script type="text/javascript">
var arr=new Array(3);
arr[0]="George"
arr[1]="John"
arr[2]="Thomas"
document.write(arr.join());
document.write("<br />");
document.write(arr.join("."));
</script>
</body>
</html>
如何使用 sort() 方法从字面上对数组进行排序。
<html>
<body>
<script type="text/javascript">
var arr=new Array(6)
arr[0]="George"
arr[1]="John"
arr[2]="Thomas"
arr[3]="James"
arr[4]="Adrew"
arr[5]="Martin"
document.write(arr + "<br />")
document.write(arr.sort())
</script>
</body>
</html>
如何使用 sort() 方法从数值上对数组进行排序。
<html>
<body>
<script type="text/javascript">
function sortNumber(a, b)
{
return a - b
}
var arr=new Array(6)
arr[0]="10"
arr[1]="5"
arr[2]="40"
arr[3]="25"
arr[4]="1000"
arr[5]="1"
document.write(arr + "<br />")
document.write(arr.sort(sortNumber))
</script>
</body>
</html>
数组对象用来在单独的变量名中存储一系列的值。
我们使用关键词 new 来创建数组对象。下面的代码定义了一个名为 myArray 的数组对象:
var myArray=new Array()
有两种向数组赋值的方法(你可以添加任意多的值,就像你可以定义你需要的任意多的变量一样)。
var mycars=`new Array()`
mycars[0]="Saab"
mycars[1]="Volvo"
mycars[2]="BMW"
也可以使用一个整数自变量来控制数组的容量:
var mycars=`new Array(3)`
mycars[0]="Saab"
mycars[1]="Volvo"
mycars[2]="BMW"
var mycars=`new Array("Saab","Volvo","BMW")`
注意:如果你需要在数组内指定数值或者逻辑值,那么变量类型应该是数值变量或者布尔变量,而不是字符变量。
通过指定数组名以及索引号码,你可以访问某个特定的元素。
下面是代码行:
document.write(mycars[0])
下面是输出:
Saab
如需修改已有数组中的值,只要向指定下标号添加一个新值即可:
mycars[0]="Opel";
现在,以上代码:
document.write(mycars[0]);
将输出:
Opel
我建了一个【前端学习群】,【免费领取学习资料】或学习的同学可以关注我:
前端学习交流 - 知乎
内容是《Web前端开发之Javascript视频》的课件,请配合大师哥《Javascript》视频课程学习。
Element.innerHTML属性:
操作元素内HTML内容,即可设置或获取使用HTML代码表示的元素的后代;
在读取时,该属性返回与调用元素的所有子节点(包括元素、注释和文本节点)对应的HTML代码字会串,如:
<div id="mydiv">
<h2>零点程序员</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>
注:不同浏览器返回的文本格式有可能不同,比如,部分低版本会把所有标签转换为大写;另外,浏览器会按照原先文档的格式返回,包括空格和缩进;
在写入时,会将给定的字符串解析为DOM子树,将用这个DOM子树替换调用元素原先的所有子节点;如果设置的值是文本没有HTML标签,其结果就是纯文本,也就是文本节点,此时,如果该文本节点包含字符&、<或>, innerHTML将这些字符分别返回为&、<和>;
mydiv.innerHTML="零点程序员 & zeronetwork 主讲><b>\"王唯\"</b>";
console.log(mydiv.innerHTML);
mydiv.innerHTML="零点程序员";
设置元素的innerHTML属性将会删除该元素的所有后代,因此,如果要保留原来的内容,可以在innerHTML属性的基础上,可以使用+=进行赋值,也就达到了追加内容的效果;
mydiv.innerHTML +="<b>大师哥王唯</b>";
如果设置innerHTML属性时,使用了不合法的HTML代码,浏览器会自动修正,但要避免出现这种问题;
另外,不允许document对象使用该属性,如果使用了,会静默失败;
设置了innerHTML属性后,可以像访问文档中的其他节点一样访问新创建的节点;
console.log(mydiv.childNodes);
从本质上来看,设置innerHTML属性,浏览器会把给定的值被解析为HTML或者XML,结果就是一个DocumentFragment对象,其中保存着代表元素的DOM节点,然后再append到元素中;
innerHTML也有一些限制,在多数浏览器中,通过innerHTML插入的<script> 元素不会被执行,因为有可能会产生潜在的安全问题;
var content=document.getElementById("content");
content.innerHTML="<script>alert('wangwei');<\/script>";
即使如此,使用innerHTML属性也不能消除潜在的风险,比如,绕过<script>标签,把脚本绑定到相关的事件中;
mydiv.innerHTML="<img src='nourl' onerror='alert(\"加载图片出错啦\")'>";
通过innerHTML写入<style>元素就可以运行;如:
mydiv.innerHTML="<style>body{background-color:purple;}</style>";
// 放在head中
document.head.innerHTML +="<style>body{background-color:purple;}</style>";
console.log(document.head.innerHTML);
在设置innerHTML属性时,虽然元素的所有子元素被替换,其仍被保存在内存中,如果事先有变量在引用这些子元素,在设置innerHTML后,这些变量仍将保持对原始子元素的引用;
var mydiv=document.getElementById("mydiv");
var h2=mydiv.querySelector("h2");
mydiv.innerHTML="新内容";
console.log(h2);
mydiv.appendChild(h2);
并不是所有元素都有innerHTML属性,不支持的有<col> <colgroup> <frameset> <head> <html> <style> <table> <tbody> <thead> <tfoot> <title> <tr>
无论什么时候插入外界的HTML内容时,都应该对HTML进行无害化处理,IE8提供了window.toStaticHTML()方法,接受一个HTM字符串,返回一个经过无害化处理后的版本;
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会抛出异常
mydiv.innerHTML=sanitized;
小示例:
使用innerHTML创建一种机制用于将消息记录到页面中的一个元素中;
<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("打印一些数据");
// 定义一个事件处理程序
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属性基本一致,不同点是,innerHTML是访问和设置元素的所有子节点,而outerHTML属性不仅包括它的所有子节点,也包括它本身;
console.log(mydiv.outerHTML);
mydiv.outerHTML="<p><h2>零点网络</h2></p>";
如果元素没有父元素,即如果它是文档的根元素,在设置其outerHTML属性将抛出异常,如:
document.documentElement.outerHTML="content"; // 异常
这个属性应用的机会非常少;
HTMLElement.innerText属性:
可以操作元素中包含的所有文本,最初是由IE实现的,后来被纳入标准中;
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerText);
mydiv.innerText="零点程序员";
console.log(mydiv.innerText);
输出一个文档树时,无论文本位于文档树中的什么位置,会按照由浅入深的顺序,将子文档树中的所有文本拼接起来;
<div id="content">
<p>零点网络<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);
// 返回
// 零点网络zerontwork是一家从事IT教育的公司
//
// HTML/
// CSS
// Javascript
</script>
由于不同浏览器处理空白字符的方式不同,因此输出的文本可能会也可能不会包含原始的HTML代码中的缩进;
使用innerText属性设置内容时,会移除原先所有的子节点,将永远只会生成当前节点的一个子文本节点;如果设置的内容包括HTML标签,会自动被转码,也就是说,会对所有出现在文本中的HTML语法字符进行编码(>、<、”、&);
mydiv.innerText="<h2>wangwei</h2>"; // < > 会被转义
因为在访问innerText属性时,其会过滤掉html标签,所以可以利用它的这个特点,快速过滤掉元素的HTML标签,即把innerText设置为innerText;
content.innerText=content.innerText;
console.log(content.innerText);
如果在设置innerHTML属性时,赋给的就是纯文本字符串,那它就与innerText属性作用一样了;
var mydiv=document.getElementById("mydiv");
mydiv.innerText="零点网络 zeronetwork";
mydiv.innerHTML="零点网络 zeronetwork";
mydiv.innerText="零点网络\nzeronetwork"; // 有br
mydiv.innerHTML="零点网络\nzeronetwork"; // 无br,但源码格式有换行
因为innerHTML是解析html标签的,而\n不是标签,所以当作空格被忽略了;但在innerText中,浏览器遇到\n,就会执行换行,所以把它解析为<br>;
在实际使用中,如果要过滤html标签,可以使用正则,如:
// 去除html标签可以使用正则
content.innerHTML=content.innerHTML.replace(/<.+?>/img,"");
console.log(content.innerText); // 没有格式<br>
console.log(content.innerHTML); // 没有格式<br>
HTMLElement.outerText属性:
与innerText一样,只不过替换的是元素(包括子节点)本身;其是一个非标准属性;
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerText);
console.log(mydiv.outerText); // 返回值与innerText一致
在读取文本值时,outerText和innerText的结果完全一样;
但在写模式下,outerText就完全不同了,其本身都会被新的文本节点都替代,从文档中被删除,但其仍然被保存在内存中,如果有变量引用,还可以再利用;
mydiv.outerText="零点程序员";
console.log(mydiv); // 依然保留着原有的引用
FF不支持outerText属性,如:
mydiv.outerText="零点程序员"; // 在FF中失效
// 在FF中返回undefined,如果有上一行,会打印出“零点程序员”,但这和内置的outerText没有关系
console.log(mydiv.outerText);
在实际使用中,只会用到innerHTML和innerText,其他两个一般不用,也没有多大的实际意义;
Node.textContent属性:
DOM3规定了一个属性textContent,该属性被定义在Node接口中,它的作用类似innerText属性,返回一个节点及其后代的所有文本内容;
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerText);
console.log(mydiv.textContent); // 返回值与innerText基本一致,但格式不一样
如果设置textContent属性,会删除该元素的所有子节点,并被替换为包含指定字符串的一个单独的文本节点;
var mydiv=document.getElementById("mydiv");
mydiv.textContent="大师哥王唯";
mydiv.textContent="<h3>大师哥王唯</h3>"; // 会被转码
console.log(mydiv.textContent);
console.log(mydiv.childNodes); // NodeList [text]
如果节点是文本节点,此属性可用于取代 nodeValue 属性,如;
var h2=document.querySelector("h2").firstChild; // 取得文本节点
console.log(h2.textContent); // zeronetwork
console.log(h2.nodeValue); // zeronetwork
h2.nodeValue="零点程序员";
console.log(h2.textContent); // 零点程序员
console.log(h2.nodeValue); // 零点程序员
可以看出,两者是联动的;
如果事先有变量引用着它的后代节点,即使节点使用该方法移除所有后代节点,但被引用的后代节点依然存在,可以被再次利用;
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属性的区别:
两者的返回的内容并不完全一样,比如在输出的格式上其与innerText是不同的,其会保留代码中的空白符;同时,innerText针对表格,会试图保留表格的格式;
var mytable=document.getElementById("mytable");
console.log(mytable.innerText);
console.log(mytable.textContent);
textContent属性会返回元素的所有内容,包括其中的样式和脚本代码,而innerText只返回能呈现在页面上的元素;
// 在mydiv中添加<style>和<script>标签
var mydiv=document.getElementById("mydiv");
console.log(mydiv.innerText); // 不包括<style>和<script>
// 包括<style>和<script>标签内的内容,但该标签被过滤了
console.log(mydiv.textContent);
既然innerText只返回能呈现在页面上的元素,所以它的返回值会受CSS样式的影响,不会返回被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属性能返回文本节点的文本内容,而innerText会返回undefined;如果是文本节点调用textContent属性,其返回值与nodeValue一致;
innerHTML有可能会引发安全问题,但textConent却不会;
mydiv.innerHTML="<img src='nourl' onerror='alert(\"加载图片出错啦\")'>";
mydiv.textContent="<img src='nourl' onerror='alert(\"加载图片出错啦\")'>";
console.log(mydiv.childNodes); // index.html:20 NodeList [text]
第一行的onerror会被执行,第二行不会执行,并且其被解析为文本节点,如此,textContent不会引发安全问题;
所有主流的浏览器都支持textContent属性,但IE8及以下不支持,可以包装一个兼容的函数:
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, "零点程序员");
或者直接定义在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>元素中的文本:
内联的<script>元素有一个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属性设置为”text/x-custom-data”,就表明了脚本为不可执行的Javascript代码,如此,Javascript解析器将忽略该脚本,这也使得<script>元素可以被用来嵌入任意文本内容;
<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)方法:
该方法会将任意的HTML字符串text解析为Element元素,并将结果节点插入到DOM树中的指定的元素”相邻”的position位置;该方法最早是在IE4中出现的;它接收两个参数:插入位置和要插入的HTML文本;
第一个参数position的可能值:
第二个参数text为HTML字符串,如果浏览器无法解析,会抛出错误,如;
var mydiv=document.getElementById("mydiv");
mydiv.insertAdjacentHTML("beforebegin","<p>前一个同辈元素</p>");
mydiv.insertAdjacentHTML("afterbegin","<p>作为第一个子元素</p>");
mydiv.insertAdjacentHTML("beforeend","<p>最后一个子元素</p>");
mydiv.insertAdjacentHTML("afterend","<p>后一个同辈元素</p>");
insertAdjacentHTML()方法同innerHTML属性一样,会遇到安全问题,在使用该属性插入HTML内容时,需要转义之后才能使用;
另外,如果元素没有子元素的时候,其和innerHTML就非常相像了;
var newdiv=document.createElement("div");
newdiv.insertAdjacentHTML("afterbegin", "<p>零点程序员</p>");
// 同以下
newdiv.innerHTML="<p>零点程序员</p>";
document.body.appendChild(newdiv);
需要注意的是,如果position为beforebegin或afterend,那该元素必须具有一个parent元素;
var newdiv=document.createElement("div");
// 异常:The element has no parent,此时newdiv并没有被添加到DOM树中,它并没有父节点,但是如果把下面行互换一下,就可以了;
newdiv.insertAdjacentHTML("afterend", "<p>零点程序员</p>");
document.body.appendChild(newdiv);
基于insertAdjacentHTML()方法定义一个更符合语义逻辑的一个对象,如:
// 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>价格:</label><input type="text" id="price" /><br/>
<label>数量:</label><input type="text" id="quantity" /><br/>
<button id="btnAdd">添加</button>
</div>
<table class="table">
<thead>
<tr>
<th>序号</th><th>商品</th><th>价格</th><th>数量</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()类似,只不过插入的是纯文本内容,它的作用是将一个给定的文本text插入到相对于被调用的元素的给定position位置;
position的值insertAdjacentHTML()中的position是一样的;
var mydiv=document.getElementById("mydiv");
mydiv.insertAdjacentText("afterbegin","王唯");
mydiv.insertAdjacentText("afterend","zeronetwork");
如果text是html字符串,也会被当作纯文本进行处理,如:
// 页面输出:<h2>王唯</h2>
mydiv.insertAdjacentText("afterbegin","<h2>王唯</h2>");
Element. insertAdjacentElement(position, element)方法:
将一个给定的元素节点插入到相对于被调用的元素的给定的position位置;与insertAdjacentHTML()方法类似,只不过插入的是一个节点对象;该方法会返回一个Element对象;
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上有人分享了一个包装的方法,就是利用以上原生的方法;
// 把一个节点插入到DOM树中的一个位置
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>零点程序员</b>", 'beforebegin');
console.log(mydiv);
内存和性能问题:
使用以上的方法替换子节点可能会导致浏览器的内存占用问题,尤其是在IE中,问题更加明显;
如果被删除的子树中的元素设置了事件处理程序或者引用了一个Javascript对象作为属性,被删除的元素与事件处理程序或引用的JS对象之间的绑定关系在内存中并没有一并删除;如果这种情况频繁出现,页面占用的内存数量就会明显增加;因此,在使用innerHTML、outerHTML属性和insertAdjacentHTML()方法时,最好手工先移除要被替换的元素的所有事件处理程序和JS对象属性;
不要反复地使用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>";
}
,最好的做法是:单独构建字符串变量,再一次性的把结果赋给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三个方法与insertBefore()、appendChild()和innerHTML的比较;
在某些时候,这些方法属性都可以达到同样的目的,但在实际开发中,要针对当时的情况,选择一个合适的方法,没有哪个方法就一定比另外的方法更好,只有相对的合适;
同时,这三个方法的性能虽然不一样,但相差不大,几乎可以忽略;
insertAdjacentHTML()与innerHTML属性的性能:
insertAdjacentHTML()方法不会重新解析它正在使用的元素,因此它不会破坏元素内的现有元素,这就避免了额外的序列化步骤,但使用innerHTML时,特别是在原有的基础上追加元素时,都会对原有的元素重新序列化,因此,前者比后者效率更快;
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()方法快很多,但是改进以上代码后,为其添加有文本内容的元素,如;
// 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("零点程序员"));
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>零点程序员</h2><p>由大师哥王唯主讲</p></div>");
console.timeEnd("adjacent");
可以看到,两者相差10ms,几乎可以忽略不计;
比较appendChild()与insertAdjacentElement方法的性能;
如:把测试appendChild()方法中的mydiv.appendChild(div)改成mydiv.insertAdjacentElement("beforeend", div);即可;
发现两者几乎相同;
比较insertBefore()与以上两者的性能;
如:把测试appendChild()方法中的mydiv.appendChild(div),改成mydiv.insertBefore(div, mydiv.lastChild);,结束也大同小异;
小实例,排序表格;
基于表格指定列中单元格的值来进行排序;
<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>
// 根据指定表格每行第n个单元格的值,对第一个<tbody>中的行进行排序
// 如果存在comparator函数则使用它,否则按字母表顺序比较
function sortrows(table, n, comparator){
var tbody=table.tBodies[0]; // 第一个<tbody>,可能是隐式创建的
var rows=tbody.getElementsByTagName("tr"); // tbody中所有行
rows=Array.prototype.slice.call(rows, 0); // 变成数组
// 基于第n个<td>元素的值进行排序
rows.sort(function(row1, row2){
var cell1=row1.getElementsByTagName("td")[n]; // 获得第n个单元格
var cell2=row2.getElementsByTagName("td")[n]; // 同上
var val1=cell1.textContent || cell1.innerText; // 获得文本内容
var val2=cell2.textContent || cell2.innerText;
if(comparator) return comparator(val1,val2); // 进行排序
if(val1 < val2) return -1;
else if(val1 > val2) return 1;
else return 0;
});
// rows中已经排好序,在tbody中按它们的顺序把行添加到最后
// 这将自动把它们从当前位置移走,并不是删除,而是移动
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>
小实例,生成目录表:
<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>
// 当执行这个函数时会去文档中查找id为"TOC"的元素;
// 如果这个元素不存在,就创建一个元素
// 生成的TOC目录应当具有自己的CSS样式,整个目录区域的样式className设置为"TOCEntry";
// 为不同层级的目录标题定义不同的样式,<h1>标签生成的标题className为"TOCLevel1",
// <h2>标签生成的标题className为”TOCLevel2“,以此类推;段编号的样式为"TOCSectNum"
function createToc(){
// 查找TOC容器元素,如果不存在,则在文档开头处创建一个
var toc=document.getElementById("TOC");
if(!toc){
toc=document.createElement("div");
toc.id="TOC";
document.body.insertBefore(toc, document.body.firstChild);
}
// 查找所有的标题元素
var headings;
if(document.querySelectorAll)
headings=document.querySelectorAll("h1,h2,h3,h4,h5,h6");
else
headings=findHeadings(document.body, []);
// 递归遍历document的body,查找标题元素
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;
}
// 初始化一个数组来保存跟踪章节号
var sectionNumbers=[0,0,0,0,0,0];
// 循环找到所有标题元素
for(var h=0; h<headings.length; h++){
var heading=headings[h];
// 跳过在TOC容器中的标题元素
if(heading.parentNode==toc) continue;
// 获取标题的级别
var level=parseInt(heading.tagName.charAt(1));
if(isNaN(level) || level < 1 || level > 6) continue;
// 对于该标题级别增加sectionNumbers对应的数字
// 并重置所有标题比它级别低的数字为零
sectionNumbers[level-1]++;
for(var i=level; i<6; i++) sectionNumbers[i]=0;
// 将所有标题级的章节号组合产生一个章节号,如2.3.1
var sectionNumber=sectionNumbers.slice(0, level).join(".");
// 为标题级别增加章节号
// 把数字放在<span>中,使得其可以秀样式修饰
var span=document.createElement("span");
span.className="TOCSectNum";
span.innerHTML=sectionNumber;
heading.insertBefore(span, heading.firstChild);
// 用命名的锚点将标题包起来,以便为它增加链接
var anchor=document.createElement("a");
anchor.name="TOC" + sectionNumber;
heading.parentNode.insertBefore(anchor, heading);
anchor.appendChild(heading);
// 为该节创建一个链接
var link=document.createElement("a");
link.href="#TOC" + sectionNumber; // 链接目标地址
link.innerHTML=heading.innerHTML; // 链接文本与实际标题一致
// 将链接放在一个div中,div用基于级别名字的样式修饰
var entry=document.createElement("div");
entry.className="TOCEntry TOCLevel" + level;
entry.appendChild(link);
// 该div添加到TOC容器中
toc.appendChild(entry);
}
};
window.onload=function(){createToc();}
</script>
Web前端开发之Javascript
信息爆炸的大数据时代,我们每天都被无数的数据包围。如何在这茫茫的数字海洋中迅速找到自己所需的信息?传统的搜索方式或许已经无法满足我们的需求。此时,一种名为“爬虫”的技术逐渐崭露头角,成为了大数据时代中不可或缺的利器。
下面举个小例子讲讲爬虫可以做什么?以Python工具爬取王者荣耀官网的英雄人物头像为例,将网页上的图片爬取并保存,Python爬虫爬取网页图片可以分为四步:明确目的、发送请求、数据解析、保存数据,具体实例操作如下。
1.1 明确目的
打开王者荣耀英雄介绍主页,该主页包含很多种英雄的头像图片,主页网址链接如下。
官网地址:https://pvp.qq.com/web201605/herolist.shtml
1.2 发送请求
使用requests库发送请求,返回状态码显示为200,服务器连接正常。
import requests
u='https://pvp.qq.com/web201605/herolist.shtml'
response=requests.get(u)
print('状态码:{}'.format(response.status_code))
if response.status_code !=200:
pass
else:
print("服务器连接正常")
1.3 数据解析
在数据解析之前,需要提前安装pyquery,pyquery库类似于Beautiful Soup库,初始化的时候,需要传入HTML文本来初始化一个PyQuery对象,它的初始化方式包括直接传入字符串,传入URL,传入文件名等等,这里传入URL,并且查找节点。
#解析数据
from pyquery import PyQuery
doc=PyQuery(html)
items=doc('.herolist>li')#.items()
print(items)
同时遍历,使用find函数查找子节点,遍历爬取图片URL和图片名。
for item in items:
url=item.find('img').attr('src')
#print(url)
urls='http:'+url
name=item.find('a').text()
#print(name)
url_content=requests.get(urls).content
1.4 保存数据
最后保存数据,需要提前新建一个文件夹用于数据存储,同时,存储数据的代码需要写在for循环里面,不然只会保存一张图片。
with open('C:/Users/尚天强/Desktop/王者荣耀picture/'+name+'.jpg','wb') as file:
file.write(url_content)
print("正在下载%s......%s"%(name,urls))
同时加一个计时器,用于计时图片爬取的时长,这里显示图片爬取共计耗时7.03秒。
import time
start=time.time()
…
end=time.time()
print('图片爬取共计耗时{:.2f}秒'.format(end-start))
爬取过程动态演示如下,运行过程很快。
以上我们成功将王者荣耀的英雄人物头像爬取下来,代码文件中有高清头像。
爬虫,这个看似高深莫测的词汇,实则却是我们应对大数据挑战的得力助手。在这个数据无限增长的时代,爬虫为我们开辟了一条快速、高效获取信息的道路,上面的实例需要编程基础,这里给大家介绍使用Bright Data无编程爬取数据。
2.1 Bright Data 注册
要使用Bright Data的功能,首先我们要在其官网注册,使用个人邮箱即可注册,注册完成后的界面如下所示。
官网地址:https://get.brightdata.com/dhsjfx
2.2 主要功能
登录官网后,可以看到在主界面中已经展示了常用的功能:代理&爬虫基础设施与数据集和Web Scraper IDE,分别介绍其功能。
代理&爬虫基础设施:最快且稳定的代理网络,静态动态IP覆盖全球195个国家,告别反爬限制和封锁。包括:
数据集和Web Scraper IDE:不管是完整丰富的大数据集,还是大规模轻松开发数据挖掘抓取工具,都能在此找到。包括:
2.3 代理&爬虫基础设施
在进行网络爬虫工作时,许多网站会采取一些措施来限制或阻止来自特定 IP 地址的访问。这主要是为了防止过度抓取和保护网站数据的隐私。因此,如果你使用的是固定的 IP 地址进行爬虫操作,很可能会遇到访问受限的问题。
为了避免该情况,许多爬虫开发者选择使用代理 IP。代理 IP 是一种隐藏真实 IP 地址的方法,通过代理服务器进行数据传输。当你使用代理 IP 进行爬虫操作时,网站服务器接收到的请求会显示为代理服务器的 IP 地址,而不是你的真实 IP,Bright Data含有多种代理IP功能。
使用代理 IP 的好处在于,你可以更换不同的代理 IP 来访问目标网站,这样即使某个代理 IP 被限制或封禁,你仍然可以通过其他可用的代理 IP 继续进行爬虫操作。此外,使用真实的代理 IP 还可以帮助你更好地模拟真实用户的访问行为,提高爬虫的效率和成功率。
2.4 数据集和Web Scraper IDE
在数据科学和机器学习的世界里,一个庞大的数据集是必不可少的。有时候,为了获得所需的数据,我们需要从网站上抓取信息。而这个过程,虽然必要,但往往也是耗时和复杂的。幸运的是,一些平台和工具已经为我们提供了方便的解决方案。
在Web Scraper IDE中,官方为我们提供了许多知名站点的爬取数据。这意味着,你不需要从零开始,手动地抓取每一个网站。你可以直接使用这些已经爬好的数据集,节省大量的时间和精力。
这些数据集通常覆盖了各种领域,从社交媒体、新闻网站到电子商务平台等。无论你是在进行市场分析、内容生成还是模式识别,都可以在这些数据集中找到你需要的数据。
更令人兴奋的是,这些数据集的质量都是经过严格筛选和清洗的,确保了数据的准确性和完整性。你可以放心地使用这些数据,而无需担心数据的缺失或错误。
使用Web Scraper IDE提供的数据集,可以大大简化数据抓取的过程,使你能够更快地进入数据分析的核心工作。如果你需要快速获取高质量的数据,那么这些官方提供的数据集无疑是你的最佳选择。
2.5 Web Scraper IDE
Bright Data还提供了 web 端的 IDE 工具,并提供了相关的示例代码,你可以直接使用模板和对应的代码!也可以自己自定义爬虫,可以按照你的需求来定制数据集,点击制定按钮即可进入自定义数据集的界面。
这里以爬取豆瓣电影TOP250的数据为例,按照提示的要求填入对应的信息,填写示例的URL时,需要填写至少两条URL的链接,这样才能爬取数据。
接着,对于网页返回的字段可以编辑字段名称、数据类型等,限于爬取的数据信息,并且,返回的数据字段可以做预览,提前查看爬取的数据结果。
数据字段设置好后,就可以点击下载按钮将数据下来下来,这里有JSON和CSV两种数据保存格式,通过预览我们就可以看到爬取的基本数据信息,使用自定义爬取数据也很简单。
借助爬虫,我们可以轻松抓取和整理数据,无论你是需要大规模收集数据,还是需要突破网站封锁,或需要管理你的代理,Bright Data都能为你提供优质的服务,如果你想学习Bright Data更多数据爬取功能,点击阅读原文,申请还可以免费试用,开启你的爬虫之旅!
*请认真填写需求信息,我们会在24小时内与您取得联系。