javascript学习笔记(2)

文章介绍:javascript中的面向对象编程,遍历DOM。

一,面向对象编程

1,面向对象编程简介,

    面向对象编程相对面向过程编程而言,面向过程编程方式的特点是把数据保存到变量里,然后由一系列指令操作变量。每个指令(或一系列指令,比如函数)都能创建,删除或修改数据,显得数据与代码在某种程度上是“分离”的。

    在面向对象编程(oop)方式中,程序指令与其操作的数据密切关联。换句话说oop把程序的数据包含在"对象"的独立体里,每个对象都有自己的属性(数据)和方法(指令)。

    与面向过程编程方式相比,面向对象编程有不少优点,比如:代码复用,封装,继承。

2,创建对象

(1)创建直接实例,

javascript中有一个内置对象object,利用它可以创建一个空白的对象:

myNewObject = new Object();

这样就得到了一个崭新的对象myNewObject,此时它还没有任何属性和方法,因此没有任何实际功能。可以像下面这样添加属性和方法:

//添加属性
myNewObject.info = 'I am a shiny new object';

//添加方法
function myFunc(){
	alert(this.info);
	};
myNewObject.showInfo = myFunc;

#在把函数myFunc关联到.showInfo属性时只使用了函数名称,而没有包含括号。这是因为我们是要把函数myFunc()的定义赋予mynewObject.showInfo方法。如果加了括号,相当于执行函数然后将函数的返回值赋予变量。

(2)使用关键字this

    当我们在函数中使用this函数的时候,this指向函数的"父对象"。

    在函数最初声明时,它的父对象是全局对象window,window对象并没有名为info的属性,如果直接调用myFunc()函数,会发送错误。

(3)匿名函数

    前面的代码是这样的:

function myFunc(){

    alert(this.info);

};

myNewObject.showInfo = myFunc;

    同样的功能可以这样实现:

myNewObject.showInfo = function(){

    alert(this.info);

};

(4)使用构造函数

    如果只需要某个对象的一个实例,使用直接创建对象实例的方法还算不错。但如果要创建同意个对象的多个实例,使用这种方式就要反复重复整个过程:创建对象,添加属性,定义方法等。

    如果要创建可能具有多个实例的对象,更好的方式是使用"对象构造函数"。它会创建某种模板,方便实现多次实例化。

    查看下面打代码,其中并没有使用new Object(),而是先声明一个函数没有ObjectType(),然后在它的定义里使用关键字this添加属性和方法。

function myObjectType(){
	this.info = 'I am a shiny new object';
	this.showInfo = function(){
		alert(this.info);
		}
	this.setInfo = function(newInfo){
		this.info = newInfo;
		}

    这段代码添加了一个属性info,两个方法showInfo和setInfo,前一个方法显示info属性当前保存的值;后移个方法接收一个参数newInfo,用它的值覆盖info的值。

(5)对象实例化

    在定义了构造函数后,可以方便地创建对象的实例:

    var myNewObject = new myObjectType();

(6)构造参数函数

    在把对象实例化时,还可以通过给构造函数传递一个或多个参数来定制对象。在下面的代码里,构造函数的定义包含了一个参数personName,它的值会赋予构造函数的name属性。以后在实例化两个对象时,我们给每个实例都传递了一个姓名作为参数。

var myNewObject = new myObjectType();

function Person(personName){
	this.name = personName;
	this.info = 'I am called '+ this.name;
	this.showInfo = function(){
		alert(this.info);
		}
	}
var person1 = new Person('Adam');
var person2 = new Person('Eve');

3,使用prototype扩展和继承对象

(1)扩展对象

    例子:给它添加一个新方法sayHello。

Person.prototype.sayHello = function(){

    alert(this.name + " says hello");

}

(2)继承

    继承是指从一种对象类型创建另一种对象类型,新对象类型继承老对象类型的属性和方法,还可以可选地添加自己的属性和方法。通过这种方式,我们可以先设计出“通用”的对象类型,然后继承来不断细化它们来得到更特定的类型,这样可以节省很多工作。   

    javascript模拟实现继承的方式也是使用关键字prototype。

    例子:从Pet对象中继承Dog

//先定义一个Pet对象
function Pet(){
	this.animal = "";
	this.name = "";
	this.setAnimal = function(newAnimal){
		this.animal = newAnimal;
		}
	this.setName = function(newName){
		this.name = newName;
		}

//定义一个Dog对象
function Dog(){
	this.breed = "";
	this.setBreed = function(newBreed){
		this.breed = newBreed;
		}
	}

从Pet继承属性和方法,

Dog.prototype = new Pet();

这样就不仅可以访问Dog里的属性和方法,还可以访问Pet里的属性和方法:

var myDog = new Dog();
myDog.setName("Alan");
myDog.setBreed("Greyhound");
alert(myDog.name + " is a "+myDog.breed);

#使用javascript还可以扩展javascript内置的对象。

4,封装

    封装是面向对象编程的一种能力,表示把数据和指令封装到对象内部。其具体实现方法在不同的语言里有所区别。对于javascript来说,在构造函数内部声明的变量只能在对象内部使用,对于外部是不可见的。构造函数内部声明的函数也是这样的。

    如果想从外部访问这些变量和函数,需要在赋值时使用关键字this,这时它们就成为了对象的属性和方法。

二,遍历DOM

1,DOM节点

(1)节点类型

        nodetype值和节点类型:1,元素 2,属性 3,文本 4,CDATA区域 5,实体引用 6,实体  7,执行指令  8,HTML注释   9,文档  10,文档类型(DTD) 11,文档片段  12,标签。

(2)childNodes属性

    每个节点都有一个childNodes属性。这个类似数组的属性包含了当前节点的全部子节点的集合,我们可以访问这些子节点的信息。

    childNodes集合称为"节点列表"(NodeList),其中的项目以数值进行索引。集合(在大多数情况下)的表现类似于数组,我们可以像访问数组元素一样访问集合里的项目,还可以像对待数组一样遍历集合的内容,但有些数组方法是不能用的,比如push()和pop()。

    节点列表是一个动态集合,这表示集合的任何改变都会立即反映到列表。

    使用childNodes属性

    利用childNodes属性返回的集合,我们可以查看程序清单里<ol>元素的内容。编写一个简单的程序,读取<ol>元素的子节点,并且放回列表里的总数。

    首先,利用<ol>的id获取它:

    var olElement = document.getElementById("toDoList");

    现在,<ol>元素的子节点就包含在这个对象里了:

    olElement.childNodes

    由于我们只想操作子节点里的<li>元素,所以在遍历childNodes集合时,只统计nodeType == 1(也就是HTML元素)的节点,忽略其他的元素(比如注释和空白)。处理集合的方式与数组很相似,比如这里使用length属性(就像对数组使用该属性一样)

    var count = 0;

    for(var i =0;i<olElement.childNodes.length;i++){

        if(olElement.childNodes[i].nodeType == 1) count++;

}

(3)firstChild 和 lastChild

    在childNodes数组里可以使用firstChild和lastChild选择数组中的第一个和最后一个元素

(4)parentNode属性

    parentNode属性保存节点的父节点。

(5)nextSibling 和 previousSibling

    兄弟节点是指同样具有相同父节点的那些节点。perviousSibling和nextSibling属性分别返回节点的前一个和后一个兄弟节点,如果不存在相应的节点,就返回NULL。

(6)节点值

    DOM节点的nodeValue属性返回保存在节点里的值,我们一般用它返回文本节点里的内容。

    从前面统计列表项目数量的范例出发,获取页面的<p>元素里包含的文本。为此,我们需要访问相应的<p>节点,找到它包含的文本节点,再利用nodeValue属性返回其中的信息:

var text = '';
var pElement = document.getElementById("toDoNotes");
for(var i=0;i<pElement.childNodes.length;i++)
{
	if (pElement.childNodes[i].nodeType == 3){
		text += pElement.childNodes[i].nodeValue;
		};
	}
alert("The paragraph says:\n\n" + text );
(7)节点名称

    nodeName属性以字符串形式返回节点的名称。这个属性是只读的,不能修改它的值。

    当nodeName返回元素名称时,并不包括HTML源代码里使用的尖括号<>。

var pElement = document.getElementById("toDoNotes");

alert(pElement.nodeName);

nodeName属性的返回值

  • nodeType 1 节点类型:元素 nodeName值:元素(标签)名称
  • nodeType 2 节点类型:属性 nodeName值:属性名称
  • nodeType 3 节点类型:文本 nodeName值:字符串“#text”

2,利用getElementsByTagName()选择元素

    前面介绍过利用document对象的getElementById()方法访问页面里的元素。document的另一个方法getElementsByTagName可以获取特定的全部标签,将其保存在一个数组里。

    和getElementById()一样,getElementsByTagName()方法也接收一个参数,然而,它需要的参数并不是元素的ID,而是标签的名称。

3,读取元素的属性

    HTML元素通常会具有一些属性,保存着相关的信息:

     <div id="id1" title="report">Here is some text.</div>

    属性通常放置在标签的前半部分,其形式是"属性=值"。属性本身是所在元素的子节点

    在获得了目标元素之后,就可以利用getAttribute()方法读取它的属性值:

var myNode = doccument.getElementById("id1");
alert(myNode.getAttribute("title"));

    上面的两行代码会在alert对话框里显示"report"。如果尝试访问不存在的属性。getAttribute()会返回null。利用这个特性可以检测一个节点元素是否定义了特定的属性

4,DOM操作

(1)创建节点

    给DOM数添加新节点需要两个步骤:

1,首先是创建一个新节点。节点创建之后处于某种"不确定状态",它的确存在,但不属于DOM树的任何位置,也就不会出现在浏览器窗口里。

2,接下来把接待你添加到DOM树的指定位置,它就成为页面的组成部分了。

    接下来介绍document对象用于创建节点的一些方法。

createElement()

    createElement()方法可以新建任何类型的标准HTML元素,比如段落,区间,表格,列表等。

    假设我们要新建一个<div>元素,为此,只需要把相关的节点名称(也就是"div")传递给createElement方法:

var newDiv = document.createElement("div");

新的<div>元素就存在了,但目前还没有内容,没有属性,在DOM树立也没有位置。稍后就会介绍如何解决这些问题。

createTextNode()

    页面里有很多HTML元素需要文本形式的内容,这就需要使用createTextNode()方法。它的工作方式类似于createElement(),但是它的参数不是nodeName,而是元素需要的文本内容:

var newTextNode = document.createTextNode("here is some text content.");

cloneNode()

    重复劳动是最没有意义的,如果文档中已有的节点与需要新建的节点很像,就可以使用cloneNode()来新建节点。

    和createElement()和createTextNode()方法不同,cloneNode()接受一个单个的参数,这是一个True或false的布尔值。

    当参数为true时,表示不仅要复制节点,还要复制它的全部子节点:

var myDiv = document.getElementById("id1");
var newDiv = myDiv.cloneNode(true);

    上述代码让javascript复制了元素及其子节点,这样myDiv里的文本(保存在元素的文本子节点里)就会完整的复制到新的<div>元素。

    如果是下面这样的代码:

    var newDiv = myDiv.cloneNode(false);

    新建的<div>元素与原始元素相同,但是没有子节点。它会具有一样的属性(当然,前提是原始节点的类型是元素节点)。

#注意在复制一个节点的时候,记得要修改新的元素的id,因为一个文档中id值应该是唯一的。

(2)操作子节点

    前面新建的节点不在DOM树的任何位置,因此并没有上面实际的意义。document对象具有一些特定的方法,专门用于在DOM树里放置节点,接下来介绍他们。

    appendChild()

    把新节点添加到DOM数的最简单方法也许就是把它作为文档中已有节点的一个子节点。这只需要获取父节点,然后调用appendChild()方法:

var newText = document.createTextCode("here is some text content:");
var myDiv = document.getElementById("id1");
myDiv.appendChild(newText);

这段代码新建一个文本节点,并且把它添加为现有<div> (id为id1)的子节点。

    appendChild()方法总是在已有的最后一个子节点之后添加子节点,所以添加的节点会成为父节点的lastChild。

    appendChild()方法不仅可以用于文本节点,而且可以用于各种类型的节点。

    insertBefore()

    appendChild()总是把新的子节点添加到子节点的末尾,而insertBefore()方法可以指定一个子节点,然后把新节点插入到它前面。

    这个方法有两个参数:要插入的新节点,指示插入位置的节点(插入到这个节点的前面)。

<div id="id1">
	<p id="para1">this paragraph contains some text</p>
	<p id="para2">hers is some more text</p>
</div>
<!//新建一个段落!>
var newPare = document.createElement("p")
<!指明父节点,以及想要在哪个子节点之前插入:!>
var myDiv = document.getElementById("id1");
var para2 = document.getElementById("para2");
myDiv.insertBefore(newPara,para2);

    replaceChild()

    replaceChild()方法可以把父元素现有的一个子节点替换为另一个子节点。它有两个参数,一个是新的子节点,另一个是现有的子节点。           replaceChild(newElement,oldElement)    

    一个使用replaceChild()的例子

<!DOCTYPE html>
<html>
<head>
	<title>Replace Page Element</title>
	<script>
		function replaceHeading(){
			var newH2 = document.createElement("h2");
			var newH2Text = document.createTextNode("welcome!");
			newH2.appendChild(newH2Text);
			var myDiv = document.getElementById("id1");
			var oldP = document.getElementById("para1");
			myDiv.replaceChild(newH2,oldP);
			}
		window.onload = function(){
			document.getElementById("btn").onclick = replaceHeading;
			}
	</script>
</head>
<body>
	<div id="id1">
		<p id = "para1">Welcome to my web page.</p>
		<p id = "para2">Please take a look around.</p>
		<input id="btn" value="replace Element" type="button" />
	</div>
</body>
</html>

    removeChild()

    removeChild()方法专门用于从DOM数里删除子节点。

var myDiv = document.getElementById("id1");
var myPara = document.getElementById("para2");
myDiv.removeChild(myPara);

removeChild()方法的返回值是对删除节点的引用,在需要时,可以利用它对已经删除的节点实现进一步操作:

var removedItem = myDiv.removeChild("myPara");
alert('Item whit id' + removedItem.getAttribute("id") + ' has been removed.');
(3)编辑元素属性

    前一章介绍过使用getAttribute()方法读取元素属性。还有一个相应的setAttribute()方法可以为元素节点创建属性并赋值。它有两个参数,一个是要添加的属性,另一个是属性值。此外,设置现有属性的值就会改变该属性的值。也可以使用这一方法来有效编辑已有的属性的值:

var myPara = document.getElementById("para1");
myPare.setAttribute("title","hello");
(4)动态加载javascript文件

    在有些情况下,我们需要给已经在浏览器中加载的页面随时加载javascript代码,为此可以利用createElement()动态新建<script>元素,其中包含需要的代码,然后把这个元素添加到页面的DOM。

var scr = document.createElement("script");
src.setAttribute("src","newScript.js");
document.head.appendChild(scr);

    由于appendChild()方法把新节点添加到最后一个子节点之后,所以新的<script>元素会位于页面的<head>部分的末尾。

    注意,如果以这种方式动态加载javascript源文件,在文件加载之前,页面不能使用其中包含的代码。

    在使用这些额外代码之前,最好先进行检测。

    几乎全部现代浏览器在脚本完成下载之后都会触发一个onload事件,它与window.onload事件的工作方式类似,只不过后者是在页面完成时加载触发,而前者是在外部资源(本例是javascript源文件)完整下载并可以使用时触发:

    src.onload = function(){

    ...新代码在加载完成之后要执行的操作...

       }

5,一个使用DOM动态创建菜单的例子

动态创建菜单范例的HTML文件

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Scripting the DOM</title>
	<script src= "menu.js"></script>
	<script>window.onload = makeMenu ;</script>
</head>
<body>
	<h1>h1</h1>
	<h2>h2</h2>
	<p>p1</p>
	<h2>h3</h2>
	<p>p2</p>
	<h2>h4</h2>
	<p>p3</p>
	<h2>h5</h2>
	<p>p4</p>
	<h2>h6</h2>
	<p>p5</p>
</body>
</html>

menu.js的javascript代码

function makeMenu(){
	//获取所有h2元素
	var h2s = document.getElementsByTagName("h2")
	//为菜单创建一个新的页面元素
	var menu = document.createElement("div")
	//创建一个UL元素,并将其添加到菜单div
	var menuUI = document.createElement("ul")
	menu.appendChild(menuUI);
	//遍历H2元素
	for(var i =0;i<h2s.length;i++){
		//获取h2元素的文本节点
		var itemText = h2s[i].childNodes[0].nodeValue;
		//添加一个列表项
		var menuLi = document.createElement("li");
		menuUI.appendChild(menuLi);
		var menuLiA = document.createElement("a");
		menuLiA = menuLi.appendChild(menuLiA);
		//设置链接的href
		menuLiA.setAttribute("href","#item"+i);
		//设置链接的文本
		var menuText = document.createTextNode(itemText);
		menuLiA.appendChild(menuText);
		//创建相应的锚点元素
		var anc = document.createElement("a");
		anc.setAttribute("name","item"+i);
		//将锚点元素添加到标题列
		document.body.insertBefore(anc,h2s[i]);
	}
	//将菜单添加到页面顶部
	document.body.insertBefore(menu,document.body.firstChild);
}

脚本运行的结果


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值