JavaScript笔记(三)


基于对象:js内置的对象或者类
面向对象:自己创建对象或者类


三、面向对象的JavaScript

1. 对象应用

1.1. 声明和实例化

对象的创建方式是用关键字 new 后面跟上实例化的类的名字:

var oObject = new Object();
var oStringObject = new String();

下面这种方式也可以,不推荐。
var oObject = new Object;
var oStringObject = new String;

1.2. 早绑定和晚绑定

// 晚绑定(后期绑定):动态语言的特点。属性和方法在运行过程中添加的。
// java:前期绑定,静态语言的特点,先编译后执行,先定义好
var obj = new Object();
obj.name = "张三";
obj.age = 24;
obj.study = function(){
	alert("张三在学习");
}
	obj.study();

2. 对象作用域

2.1. 公用、私有和受保护作用域

ECMAScript 中只存在一种作用域 - 公用作用域。
由于缺少私有作用域,开发者确定了一个规约,说明哪些属性和方法应该被看做私有的。这种规约规定在属性前后加下划线:

obj._color_ = "blue";

2.2. 静态变量/方法

ECMAScript 没有静态作用域
不过,它可以给构造函数提供属性和方法。

function sayHello() {  // 相当于 var sayHello = f()  函数也是变量,可以加属性sayHello.alternate
  alert("hello");
}
sayHello.alternate = function() {
  alert("hi");
}

sayHello();		//输出 "hello"
sayHello.alternate();	//输出 "hi"

2.3. 关键字 this

// this
var oCar = new Object; //创建一辆汽车
oCar.color = "red"; // 汽车颜色
oCar.showColor = function() { // 给汽车赋一个方法
	alert(this.color); // this代表shouColor方法属于哪一个对象 oCar.showColor当然是oCar
	// 为什么不直接使用oCar.color? 解决两个对象同时调用此方法
};
oCar.showColor(); //输出 "red"


// 原因:
var oCar1 = new Object;
oCar1.color = "red";
oCar1.showColor = showColor;  //不加括号是变量,加括号是调用。
// 写成 var shouColor = function(){alert(this.color); } 就好理解了。此写法更流行

var oCar2 = new Object;
oCar2.color = "blue";
oCar2.showColor = showColor;

function showColor() {
	alert(this.color); // oCar1和oCar2都调用此方法。oCar1调用时this就是oCar1,oCar2同理
};		
			
oCar1.showColor(); //输出 "red"
oCar2.showColor(); //输出 "blue"

3. 定义类和对象

3.1 工厂方式

原始方式
// 原始方式。在另外页面创建汽车,也需要重写一遍
			var oCar = new Object; // 创建空对象
			oCar.color = "blue"; // 动态添加属性和方法
			oCar.doors = 4;
			oCar.mpg = 25;
			oCar.showColor = function() {
				alert(this.color);
			};
工厂方式
// 工厂方式:把创建的对象封装在一个函数中,给个返回值
			// 放在外部js文件中,可多次调用。属性值可以通过传参更改
			function createCar() {
				var oTempCar = new Object;
				oTempCar.color = "blue";
				oTempCar.doors = 4;
				oTempCar.mpg = 25;
				oTempCar.showColor = function() {
					alert(this.color);
				};
				return oTempCar;
			}
			var oCar1 = createCar();
为函数传递参数
// 传参
			function createCar(sColor, iDoors, iMpg) {
				var oTempCar = new Object;
				oTempCar.color = sColor;
				oTempCar.doors = iDoors;
				oTempCar.mpg = iMpg;
				oTempCar.showColor = function() { // 每调用一次创建一次
					alert(this.color);
				};
				return oTempCar;
			}

			var oCar2 = createCar("blue", 3, 25);
			oCar2.showColor(); //输出 "blue"
在工厂函数外定义对象的方法

前面的例子中,每次调用函数 createCar(),都要创建新函数 showColor(),意味着每个对象都有自己的 showColor() 版本。而事实上,每个对象都共享同一个函数。

			function showColor() { // 所有对象共享同一个方法
				alert(this.color);
			}

			function createCar(sColor, iDoors, iMpg) {
				var oTempCar = new Object;
				oTempCar.color = sColor;
				oTempCar.doors = iDoors;
				oTempCar.mpg = iMpg;
				oTempCar.showColor = showColor;
				return oTempCar;
			}

			var oCar1 = createCar("red", 4, 23);
			var oCar2 = createCar("blue", 3, 25);
			oCar1.showColor(); //输出 "red"
			oCar2.showColor(); //输出 "blue"

3.2. 构造函数方式

// 构造函数方式。java原理一样
			function Car(sColor, iDoors, iMpg) {
				this.color = sColor;
				this.doors = iDoors;
				this.mpg = iMpg;
				this.showColor = function() {
					alert(this.color);
				};
			}
			
			// 调用:new Car
			var oCar1 = new Car("红色", 4, 23);  // this就是new出来的函数的对象。
			// 不用new就是函数,没有返回值,会报错
			oCar1.showColor();  // 调用对象的方法
			var oCar2 = new Car("blue", 3, 25);

3.3. 原型方式(prototype 属性)

该方式利用了对象的 prototype 属性,可以把它看成创建新对象所依赖的原型。
首先用空构造函数来设置类名。然后所有的属性和方法都被直接赋予 prototype 属性。
调用 new Car() 时,原型的所有属性都被立即赋予要创建的对象,意味着所有 Car 实例存放的都是指向 showColor() 函数的指针。

// 原型方法。 
			function Car() {}  // car所有的对象自然的具备下面这些属性和方法

			Car.prototype.color = "blue";
			Car.prototype.doors = 4;
			Car.prototype.mpg = 25;
			Car.prototype.showColor = function() {   // 只会创建一个,在本体上。
				alert(this.color);
			};

			var oCar1 = new Car();   // 所有 Car 实例存放的都是指向 showColor() 函数的指针
			oCar1.showColor();
			var oCar2 = new Car();

问题:

  • 这个构造函数没有参数。使用原型方式,不能通过给构造函数传递参数来初始化属性的值,因为 Car1 和 Car2 的 color 属性都等于 “blue”,doors 属性都等于 4,mpg 属性都等于 25。这意味着必须在对象创建后才能改变属性的默认值。
  • 一个对象被改动,都被改动
			function Car() {}

			Car.prototype.color = "blue";
			Car.prototype.doors = 4;
			Car.prototype.mpg = 25;
			Car.prototype.drivers = new Array("Mike", "John");
			Car.prototype.showColor = function() {
				alert(this.color);
			};

			var oCar1 = new Car();
			var oCar2 = new Car();

			oCar1.drivers.push("Bill");  // 串了

			alert(oCar1.drivers); //输出 "Mike,John,Bill"
			alert(oCar2.drivers); //输出 "Mike,John,Bill"

3.4. 混合的构造函数/原型方式

混合方式: 属性–构造函数;方法–原型方式

		<script>
			// 混合方式: 属性--构造函数;方法--原型方式
			function Car(sColor, iDoors, iMpg) {
				this.color = sColor;
				this.doors = iDoors;
				this.mpg = iMpg;
				this.drivers = new Array("Mike", "John");
			};
			Car.prototype.showColor = function() {
				alert(this.color);
			}
			
			
			var oCar1 = new Car();
			var oCar2 = new Car();
			oCar1.drivers.push("Bill");
			alert(oCar1.drivers); //输出 "Mike,John,Bill"
			alert(oCar2.drivers); //输出 "Mike,John"
		
		</script>

3.5. 动态原型方法

		<script>
			function Car(sColor, iDoors, iMpg) {
				this.color = sColor;
				this.doors = iDoors;
				this.mpg = iMpg;
				this.drivers = new Array("Mike", "John");

				if(typeof Car._initialized == "undefined") {
					Car.prototype.showColor = function() {
						alert(this.color);
					}
					Car._initialized = true;
				}
			}
		</script>

3.6. 建议方式

目前使用最广泛的是混合的构造函数/原型方式。此外,动态原始方法也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。
不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。

四、DOM(文档对象模型)

1. DOM模型概述

DOM(Document Object Model)文档对象模型。
HTML就是一棵树,要修改的话,需要先把树加载到内存中,在内存中的树就是DOM。
DOM采用直观、一致的方式对结构化文档进行模型化处理,形成一颗结构化的文档树,从而提供访问、修改该文档的简易编程接口。

2. DOM树和节点

所有 HTML 元素(节点)均可被修改,也可以创建或删除节点。

3. Document 对象

每个载入浏览器的 HTML 文档都会成为 Document 对象。Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。Document对象无需我们自己创建,Document对象是由浏览器帮我们生成。通过window.document便可以直接调用(window.可以省略)

Document对象查找:  只有id是单数
    getElementById():通过节点的id属性,查找对应节点。 // 返回一个元素
    getElementsByName():通过节点的name属性,查找对应节点。  // 返回数组
    getElementsByTagName():通过节点名称,查找对应节点。
    getElementsByClassName():通过节点class属性,查找对应节点。
使用Document对象的方法创建节点:
    createElement(tagName):创建元素节点。
    createTextNode(data):创建文本节点。(例如动态的给span标签添加内容)

4. 访问HTML元素

4.1. 根据节点访问HTML元素(getElement(s)By)

getElementById()和getElementsByName()方法属于document的方法。
getElementsByTagName()和getElementsByClassName()方法属于所有元素节点的方法。也就是说可以

// 只获取表格里的input标签:方法一
var inp = document.getElementById("tab").getElementsByTagName("input");  // table下的input		
for(var i = 0; i < inp.length; i++) {
	console.info(inp[i]); // 浏览器控制台输出
}

4.2. 根据CSS选择器访问HTML元素(querySelector(All)())

  • querySelector:返回HTML文档中第一个符合选择器参数的HTML元素
// 只获取表格里的input标签:方法二
var inp = document.querySelector("#tab").getElementsByTagName("input");	
for(var i = 0; i < inp.length; i++) {
	console.info(inp[i]); // 浏览器控制台输出
}
  • querySelectorAll:返回所有符合CSS选择器的HTML元素
// 方法三:
var inp = document.querySelector("#tab").querySelectorAll("input");
for(var i = 0; i < inp.length; i++) {
	console.info(inp[i]); // 浏览器控制台输出
}

4.3. 利用节点关系访问HTML元素(有坑)

Node parentNode: 返回当前节点的父节点。只读属性。(√)

  • 这6个是大坑!!!!!不推荐用。
    下面的六个都把换行当成text元素,所以前一个兄弟可能不是你想象的那个
Node previousSibling:返回当前节点的前一个兄弟节点。 只读属性。
Node nextSibling: 返回当前节点的下一个兄弟节点。只读属性。
Node[] childNodes: 返回当前节点的所有子节点。 只读属性。
Node[] getElementsByTagName(tagName): 返回当前节点的具有指定标签名的所有子节点。
Node firstChild: 返回当前节点的第一个子节点。 只读属性。
Node lastChild: 返回当前节点的最后一个子节点。 只读属性。
  • 这六个不考虑空格,只考虑有效元素
// 不考虑空格,只考虑有效元素
Element parentElement: 返回当前节点的父元素。只读属性。
Element previousElementSibling:返回当前节点的前一个兄弟元素。 只读属性。
Element nextElementSibling: 返回当前节点的下一个兄弟元素。只读属性。
Element[] children: 返回当前节点的所有子元素。 只读属性。
Element firstElementChild: 返回当前节点的第一个子元素。 只读属性。
Element lastElementChild: 返回当前节点的最后一个子元素。 只读属性。

  • 坑举例:
		<table>
			<tr>
				<td>按钮</td>
				<td id="tdButtons">
					<input type="button" value="注册" onclick="submitForm()" />
					<input type="reset" value="取消" />
					<input type="button" value="增加元素" id="addElement" />
				</td>
			</tr>
		</table>
// 坑:previousSibling 并不能给取消按钮加背景色?为什么呢
document.getElementById("addElement").previousSibling.style.backgroundColor="red"

查看它的兄弟节点是什么:把换行当成了类型为text的元素

// 查看一下兄弟节点是什么
			var cs = document.getElementById("tdButtons").childNodes;
			for (var i=0; i<cs.length; i++){
				console.info(cs[i])
			}

在这里插入图片描述
解决方法:
使用previousElementSibling替换previousSibling。
只获得所有子节点使用children。

document.getElementById("addElement").previousElementSibling.style.backgroundColor = "red";
var cs = document.getElementById("tdButtons").children;
for (var i=0; i<cs.length; i++){
	console.info(cs[i])
}

4.4. 访问列表框、下拉菜单选项

select元素(length/options)

form:返回select元素所在的表单对象,只读属性。
length:返回select元素的选项个数。只读属性。
options:返回select元素里所有选项组成的数组,只读属性。

selectedIndex:返回下拉列表中选中选项的索引,如果有多个选项被选中,则只返回第一个被选中选项的索引,读写属性。
type:返回下拉列表的类型,即是否允许多选。如果允许多选,则返回select-multiple。如果不支持多选,则返回select-one。
multiple:将select元素变为多选。

		<table>
			<tr>
				<td>学历</td>
				<td >
					<select id="degree">
						<!--value为数据库的值,方便快速查询 option中间的文本为了显示给用户-->
						<option value="1">博士</option>
						<option value="2">硕士</option>
						<option value="3">本科生</option>
						<option value="4">专科生</option>
					</select>
				</td>
			</tr>
		</table>
		var sel = document.getElementById("degree");
		console.info(sel.length);
		console.info(sel.options);
		for (var i=0;i<sel.length; i++){
			// sel.options[i]是对象;
			// sel.options[i].text是option标签之前的文本;
			// sel.options[i].value 是option中value的值
			console.info(sel.options[i].text)   // 
		}
		
		// 查看类型
		console.info(sel.type);  // select默认就是单选:select-one
		sel.multiple = true;    // 更改为多选。 尽量在html中写 <select multiple="multiples">
		console.info(sel.type);
select选项

select元素的options属性可以访问列表项,传入指定索引即可访问指定列表项。在DOM中HTMLOptionELement类表示列表项。

select.option[index]: 返回select元素的index+1个选项。
selected:返回该选项是否被选中,通过修改该属性可以动态改变该选项是否被选中。
text:返回该选项呈现的文本。就是和之间文本。
value:返回每个选项的value属性。
form: 返回包含该选项所处select元素的表单对象。
defaultSelected: 返回该选项默认是否被选中。 只读属性。
index: 返回该选项在select元素中的索引,只读属性。

sel.options[2].selected = true;  // 建议在html中改。能在html中不要再js中写  <option selected="selected">

4.5. 访问表格子元素


		<table id="tab">
			<tr>
				<td>用户名</td>
				<td>
					<input type="text" id="userName" />
				</td>
			</tr>
			<tr>
				<td>手机号码</td>
				<td><input type="tel" /></td>
			</tr>
			<tr>
				<td></td>
				<td>
					<input type="submit" value="注册" />
					<input type="reset" value="取消" />
					<input type="button" value="替换表格" onclick="replaceTable()"/>
				</td>
			</tr>
		</table>
var tab = document.getElementById("tab");
for (var i =0; i<tab.rows.length; i++){   
	// console.info(tab.rows[i]) // table里的每一行代码--对象
	// console.info(tab.rows[i].innerHTML)  // innerHTML:每一行标签(tr)里面的代码
	for (var j=0; j<tab.rows[i].cells.length; j++){
//		console.info(tab.rows[i].cells[j]);  // 每个td
		console.info(tab.rows[i].cells[j].innerHTML);  // td里的代码
	}
}

5. 修改HTML元素

先访问到,再修改
innerHTML:大部分的HTML元素的呈现内容由该属性控制。标签的内容,不包含标签。
value:表单控件如 的呈现内容。有value值的都可以修改
className: 修改HTML元素的CSS样式,该属性是一个class选择器名。
style:修改HTML元素的内联CSS样式。
options[index]:直接对元素指定列表项赋值,可改变列表框、下拉菜单的指定列表项。

			function replaceTable() {
				var form1 = document.getElementById("form1");
				form1.innerHTML = "<p>替换整个表格</p>"
			}

6. 增加HTML元素

6.1. 创建和复制节点

创建节点(createElement)

创建节点使用document对象的createElement方法来实现。
比如创建一个div:
var a = document.createElement(“div”);

复制节点(cloneNode)

通过Node的cloneNode()方法可以复制一个已有节点,该方法的语法格式如下。
Node cloneNode(boolean deep): 复制当前节点。
当deep为true时,表示在复制当前节点的同时,复制该节点的全部后代节点;
当deep为false时,表示仅复制当前节点。

6.2. 添加节点(添加子节点,都需要先获取父节点)

  • appendChild(Node newNode):将newNode添加到当前节点的最后一个子节点。
  • insertBefore(Node newNode,Node refNode):在refNode节点之前插入newNode节点。(之前插入节点)
  • replaceChild(Node newChild,Node oldChild): 将oldChild节点替换成newChild节点。
<form action="/Login" method="post">
	<table>
		<tr>
			<td></td>
			<td id="tdButtons">
				<input type="submit" value="注册" />
				<input type="reset" value="取消" />
				<input id="addElement" type="button" value="添加节点" onclick="addEle()" />
			</td>
		</tr>
	</table>
</form>
<script>
	// 添加节点两个步骤:
	// 1. 创建或复制节点
	// 2. 添加节点
	function addEle(){
	// 再添加节点之后添加span
	// 创建元素
	var v = document.createElement("span"); // span行内元素
	v.innerText = "我是被动态创建的";
				
	// 在节点“之后”添加节点
	//document.getElementById("tdButtons").appendChild(v);
				
	// 在节点“之前”添加节点
	document.getElementById("tdButtons").insertBefore(v, document.getElementById("addElement"));
	}			
</script>

6.3. 为列表框、下拉菜单添加选项

<form action="/Login" method="post">
			<table>
				<tr>
					<td>学历</td>
					<td>
						<select id="degree">
							<option value="1">博士</option>
							<option value="2">硕士</option>
							<option value="3">本科生</option>
							<option value="4">专科生</option>
						</select>
					</td>
				</tr>
				<tr>
					<td></td>
					<td id="tdButtons">
						<input type="submit" value="注册" />
						<input type="reset" value="取消" />
						<input id="addElement" type="button" value="添加学历选项" onclick="addEle()" />
					</td>
				</tr>
			</table>
		</form>

		<script>
			function addEle() {
				// 添加学历
				
				// 创建选项:使用createElement()方法或者
				// 构造器 new Option(text,value,defaultSelected,selected)
				var opt = new Option("博士后", "5", false, true);
				// 都是针对父元素操作
				var sel = document.getElementById("degree");
				
				// 方法一:appendChild(option)方法	
//				sel.appendChild(opt);
				// 方法二: add(option, beforeEle)在before选项之前添加option选项。更灵活
				// 如果想将option选项添加到最后,则将before指定为null。
//				sel.add(opt, null)
				// 在指定的选项之前添加
				sel.add(opt, sel.options[2]);  // 在本科之前
				// 方法三:直接为<select/>的指定选项赋值。
			}

7. 删除HTML元素

7.1. 删除节点(先获取父节点,删除某个子节点)

删除节点需要借助其父节点,Node对象提供了如下方法来删除子节点。
removeChild(oldNode): 删除oldNode子节点。
从父节点中删除该子节点后,该子节点就是在文档中消失。

7.2. 删除列表框、下拉菜单选项

删除列表框、下拉菜单的选项有两种方法:

  1. 利用HTMLOptionElement对象的remove()方法删除选项。
  2. 直接将指定选项赋值为null。

如果想要删除某个列表框、下拉菜单的全部选项,没有必要采用循环的方式逐一删除每个选项,将列表框或下拉菜单的innerHTML属性赋值为null,即可一次性删除该列表框的全部选项。

7.3. 删除表格的行或单元格

function delEle() {
	var sel = document.getElementById("degree");
	// 一、删除节点--removeChild(oldNode): 删除oldNode子节点。
	sel.removeChild(sel.options[2]);
				
	// 二、删除列表框、下拉菜单选项 两种方法:
	// 1. 利用HTMLOptionElement对象的remove()方法删除选项。
	// 2. 直接将指定选项赋值为null。
	// 如果想要删除某个列表框、下拉菜单的全部选项,直接将列表框或下拉菜单
	// 的innerHTML属性赋值为null,即可一次性删除该列表框的全部选项。
				
	// 三、删除表格的行或单元格:
	// 删除表格指定的表格行使用HTMLTableElement 类对象的下列方法:
	// deleteRow(long index): 删除表格中index索引处的行。
	// 删除表格行指定的单元格,使用HTMLRowElement对象的如下方法:
	// deleteCell(long index): 删除某行 index 索引处的单元格。		
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值