构造函数的原型和对象原型之间的区别与DOM操作
一、构造函数和对象原型
任何一个函数都有一个原型属性:prototype
function f1 () {}
console.dir(f1);
以上是声明了一个函数f1,并在控制台打印函数的相关对象属性:
prototype对于普通函数没有什么用,对于构造函数才有用构造函数是对象工厂,是用来创建对象的对象也叫“实例”,实例:实际案例。JS中没有”类”的概念,它是基于原型的语言,所以可简单的将构造函数当成“类”。构造函数必须使用“new”来调用,普通函数不需要。new的过程就是类的实例化过程,就是创建一个对象的过程创建对象的过程,就叫“类的实例化”。
1.1 构造函数
用户创建对象的函数,为了与普通函数进行区别,一般首字母会大写;
构造函数有prototype属性,该属性指向原型对象。
以下是声明一个构造函数:
function User(name, email) {
this.name = name;
this.email = email;
}
创建一个实例化对象user:
const user = new User('残破的蛋蛋', 'admin@admin.cn);
console.log(user);
此时,可以使用instanceof方法判断user是否属于User:
console.log(user instanceof User); // true
此时,如果我们向user对象的proto属性添加一个salary:
user.__proto__.salary = 8899;
console.log(user.salary); // 8899
1.2 原型对象
- 有constructor属性,指向构造函数。
1.3 实例对象
再实例化一个对象user1,并在控制台打印出来这个对象,同时将构造函数也打印出来:
const user1 = new User('残破的蛋蛋', 'admin@admin.cn);
console.log(user);
console.dir(User);
从上述案例,可以看出来,当前对象上的原型属性跟构造函数上的原型属性完全相等。
console.log(user1.__proto__ === User.prototype); // true
总结:
由构造函数实例化的每一个对象都有proto属性;
实例的原型(_ _proto_ _)永远指向它的构造函数的原型,实例的原型从构造函数的原型继承成员(属性/方法)
二、获取DOM元素的常用方法
<ul id="box">
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
<li class="item">item4</li>
<li class="item">item5</li>
<li class="item">item6</li>
</ul>
1.返回匹配的元素集合中的第一个。
const li = document.querySelector('.item');
- 注意
Nodelist是浏览器内置的集合类型,属于类数组。Array.from(),…rest,都可以将变量转为真正的数组。
let lisArr = Array.from(lis);
console.log(lisArr);
let larr = [...lisArr];
console.log(larr);
// Nodelist可以用forEach进行遍历
lis.forEach((item, index, larr) => {
console.log(item, index, larr);
});
2.返回匹配的元素集合所有成员。
const list = document.querySelectorAll('.item');
3.根据标签(tag)获取元素。
const ul = document.getElementsByTagName('ul');
4.根据id选择器获取元素。
const id = document.getElementById('box');
5.根据class选择器获取元素
const classNames = document.getElementsByClassName('item');
三、DOM元素的增删改查
- 案例:定义如下ul列表:
<ul id="list">
<li class="item">item1</li>
<li class="item">item2</li>
<li class="item">item3</li>
<li class="item">item4</li>
<li class="item">item5</li>
</ul>
首先拿到ul元素:
const ul = document.querySelector('ul');
1.创建元素。
const li = document.createElement('li');
1.2.向页面中添加子元素。
ul.appendChild(li);
1.3.对元素添加内容有两种:innerText、innerHTML,二者的区别是前者只能解析成字符串,后者可以将html元素解析出来并显示到页面中。
li.innerText = "item6";
li.innerInnerHTML = "<i style="color: red">item7</i>";
- 效果图:
还可以使用insertAdjacentHTML将html字符串直接解析为dom元素,它接收两个参数:
- 语法:
element.insertAdjacentHTML(position, string);
position
插入DOM元素的指定位置,它有4个值,分别为:
‘beforebegin’:元素自身的前面。
‘afterbegin’:插入元素内部的第一个子节点之前。
‘beforeend’:插入元素内部的最后一个子节点之后。
‘afterend’:元素自身的后面。
string
要被解析为HTML元的字符串。
- 实例
let htmlStr = '<li><i style="color: red;">item7</i></li>';
ul.insertAdjacentHTML('beforeEnd', htmlStr);
- 效果图:
1.4.如果要向文档中批量添加元素,可以使用文档片段来解决一个一个的插入造成文档页面每次都需要刷新(抖动)的问题。
首先创建一个临时文档片段:
const frag = document.createDocumentFragment();
也可以用构造函数来创建临时文档对象:
const frag = new DocumentFragment();
for (let i = 0; i < 5; i++) {
li1 = document.createElement('li');
li1.textContent = `item${i+1}`;
// 将生成的元素节点临时的挂载到文档中
frag.appendChild(li1);
}
ul.appendChild(frag);
- 效果图:
2.更新元素
- 案例:更新第三个li节点为h3
let h3 = document.querySelector('h3');
document.querySelector('li:nth-of-type').replaceWith(h3);
如果要是从更新父节点下的某个子节点,可以使用replaceChild
,例如更新ul下的最后一个子节点:
li = document.querySelector('li:last-of-type');
ul.replaceChild(h3, li);
3.删除元素
从DOM元素中移除子节点使用removeChild
,例如:移除ul列表下的第三个li:
ul.removeChild(document.querySelector('#list li:nth-of-type(3)'));
- 效果图:
注意:removeChild()方法返回的是被删除的节点。
4.遍历查询元素
// 4.1 获取所有的子元素
console.log(ul.children);
// 4.2 获取所有子元素的数量
console.log(ul.children.length);
console.log(ul.childElementCount);
// 4.3 获取第一个元素
console.log(ul.firstElementChild);
// 4.4 获取最后一个元素
console.log(ul.lastElementChild);
// 4.5 获取父节点,需要在子节点上调用
console.log(ul.lastElementChild.parentElement);
// 4.6 获取前一个兄弟,案例:获取第三个li的前一个兄弟元素
const third = document.querySelector('#list li:nth-of-type(3)');
console.log(third.previousElementSibling);
// 4.7 获取后一个兄弟
console.log(third.nextElementSibling);