基于对象:js内置的对象或者类
面向对象:自己创建对象或者类
对象的创建方式是用关键字 new 后面跟上实例化的类的名字:
var oObject = new Object();
var oStringObject = new String();
下面这种方式也可以,不推荐。
var oObject = new Object;
var oStringObject = new String;
// 晚绑定(后期绑定):动态语言的特点。属性和方法在运行过程中添加的。
// java:前期绑定,静态语言的特点,先编译后执行,先定义好
var obj = new Object();
obj.name = "张三";
obj.age = 24;
obj.study = function(){
alert("张三在学习");
}
obj.study();
ECMAScript 中只存在一种作用域 - 公用作用域。
由于缺少私有作用域,开发者确定了一个规约,说明哪些属性和方法应该被看做私有的。这种规约规定在属性前后加下划线:
obj._color_ = "blue";
ECMAScript 没有静态作用域
不过,它可以给构造函数提供属性和方法。
function sayHello() { // 相当于 var sayHello = f() 函数也是变量,可以加属性sayHello.alternate
alert("hello");
}
sayHello.alternate = function() {
alert("hi");
}
sayHello(); //输出 "hello"
sayHello.alternate(); //输出 "hi"
// 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"
// 原始方式。在另外页面创建汽车,也需要重写一遍
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"
// 构造函数方式。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);
该方式利用了对象的 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();
问题:
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"
混合方式: 属性–构造函数;方法–原型方式
<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>
<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>
目前使用最广泛的是混合的构造函数/原型方式。此外,动态原始方法也很流行,在功能上与构造函数/原型方式等价。可以采用这两种方式中的任何一种。
不过不要单独使用经典的构造函数或原型方式,因为这样会给代码引入问题。
DOM(Document Object Model)文档对象模型。
HTML就是一棵树,要修改的话,需要先把树加载到内存中,在内存中的树就是DOM。
DOM采用直观、一致的方式对结构化文档进行模型化处理,形成一颗结构化的文档树,从而提供访问、修改该文档的简易编程接口。
所有 HTML 元素(节点)均可被修改,也可以创建或删除节点。
每个载入浏览器的 HTML 文档都会成为 Document 对象。Document 对象使我们可以从脚本中对 HTML 页面中的所有元素进行访问。Document对象无需我们自己创建,Document对象是由浏览器帮我们生成。通过window.document便可以直接调用(window.可以省略)
Document对象查找: 只有id是单数
getElementById():通过节点的id属性,查找对应节点。 // 返回一个元素
getElementsByName():通过节点的name属性,查找对应节点。 // 返回数组
getElementsByTagName():通过节点名称,查找对应节点。
getElementsByClassName():通过节点class属性,查找对应节点。
使用Document对象的方法创建节点:
createElement(tagName):创建元素节点。
createTextNode(data):创建文本节点。(例如动态的给span标签添加内容)
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]); // 浏览器控制台输出
}
// 只获取表格里的input标签:方法二
var inp = document.querySelector("#tab").getElementsByTagName("input");
for(var i = 0; i < inp.length; i++) {
console.info(inp[i]); // 浏览器控制台输出
}
// 方法三:
var inp = document.querySelector("#tab").querySelectorAll("input");
for(var i = 0; i < inp.length; i++) {
console.info(inp[i]); // 浏览器控制台输出
}
Node parentNode: 返回当前节点的父节点。只读属性。(√)
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])
}
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中写
console.info(sel.type);
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中写
<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里的代码
}
}
先访问到,再修改
innerHTML:大部分的HTML元素的呈现内容由该属性控制。标签的内容,不包含标签。
value:表单控件如 的呈现内容。有value值的都可以修改
className: 修改HTML元素的CSS样式,该属性是一个class选择器名。
style:修改HTML元素的内联CSS样式。
options[index]:直接对元素指定列表项赋值,可改变列表框、下拉菜单的指定列表项。
function replaceTable() {
var form1 = document.getElementById("form1");
form1.innerHTML = "替换整个表格
"
}
创建节点使用document对象的createElement方法来实现。
比如创建一个div:
var a = document.createElement(“div”);
通过Node的cloneNode()方法可以复制一个已有节点,该方法的语法格式如下。
Node cloneNode(boolean deep): 复制当前节点。
当deep为true时,表示在复制当前节点的同时,复制该节点的全部后代节点;
当deep为false时,表示仅复制当前节点。
<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>
<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]); // 在本科之前
// 方法三:直接为的指定选项赋值。
}
删除节点需要借助其父节点,Node对象提供了如下方法来删除子节点。
removeChild(oldNode): 删除oldNode子节点。
从父节点中删除该子节点后,该子节点就是在文档中消失。
删除列表框、下拉菜单的选项有两种方法:
如果想要删除某个列表框、下拉菜单的全部选项,没有必要采用循环的方式逐一删除每个选项,将列表框或下拉菜单的innerHTML属性赋值为null,即可一次性删除该列表框的全部选项。
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 索引处的单元格。
}