目录
一、函数高级
循环绑定:
使用循环绑定会出现的问题及解决方案:
二、面向对象
3、构造函数(ES5)
三、JS选择器
1、getElement系列(最严谨)
2、querySelector系列(最方便)
3、通过id名直接获取
4.JS中操作页面标签全局属性,映射到HYML中
四、JS中的事件(基础)
五、 JS处理操作页面:
1.操作页面内容:
2.操作页面样式
这篇博客我们先将上篇博客中没有介绍完的函数部分介绍完,然后再介绍函数高级
一、函数高级
1、函数回调
函数回调的本质:在一个函数中(调用函数),当满足一定条件,调用参数函数(回调函数)
回调函数作为调用函数的参数传入
回调函数通过参数将调用还是内部数据传出
// 回调的函数
function callback(data) {}
// 逻辑函数
function func(callback) {
// 函数回调
if (callback) callback(data);
}
2、闭包函数
什么是闭包: 局部的函数 (被一个函数包裹的函数)
为什么使用闭包:
1.一个函数要使用另一个函数的局部变量
2.闭包会持久化包裹自身的函数的局部变量
3.解决循环绑定
闭包目的:不允许提升变量作用域时,该函数的局部变量需要被其他函数使用
闭包本质:函数的嵌套,内层函数称之为闭包
闭包的解决案例:①影响局部变量的生命周期,持久化局部变量;②解决变量污染
闭包的模板示例:
function outer() {
var data = {}
function inner() {
//1.在inner函数中,使用了outer的局部变量num
return data;
}
return inner;
}
//2.借助闭包,将局部变量data的生命周期提升了
var innerFn=outer()
var data=innerFn()
循环绑定:
.html文件
<ul>
<li>列表项</li>
<li>列表项</li>
<li>列表项</li>
</ul>
循环绑定:
.js文件
var lis = document.querySelector('li');
for (var i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
// 打印列表项的索引
console.log(i);
}
}
使用循环绑定会出现的问题及解决方案:
出现的问题: 变量污染
例如:
在这里使用var来循环绑定的时候,没有办法产生局部作用域,所以每次产生的i值都会被下一次的新i值所替代,就会导致每个块的点击事件中的i值都是一样的,也就是每个点击事件的序号或者说index都是一样的,这就是我们所说的变量污染
for (var i = 0; i < divs.length; i++) {
// i = 0 | 1 | 2 | 3
// 循环绑定
divs[i].onclick = function () {
console.log("***", i)
}
}
// i = 3
console.log(">>>", i);
解决方案:
1.获取局部作用域(块级作用域)解决
使用块级作用域来解决变量污染的问题, 原理就是使得每次循环都产生新的块级作用域, 在本次循环中的i值只在产生它的作用域中能够被访问到, 在作用域外面是访问不到的, 这就解决了每次i 的值都被覆盖的情况, 采用这种办法可以解决变量污染的问题
for (let i = 0; i < divs.length; i++) {
// {i=0 <= i} {i=1 <= i} {i=2 <= i}
// i = 3
// 循环绑定
divs[i].onclick = function () {
console.log("***", i)
}
} // for运行结束, i=3会被销毁
console.log(">>>", i)
2.利用闭包解决循环绑定中的变量污染问题
// 使用闭包解决变量污染的格式一(比较明了)
for (var i = 0; i < divs.length; i++) {
(function () {
var index = i;
divs[index].onclick = function () {
console.log("###", index)
}
})()
// 使用闭包解决变量污染的格式二(格调高一点)
/*
(function (index) {
divs[index].onclick = function () {
console.log("###", index)
}
})(i)
*/
// 使用闭包解决变量污染的格式三(格局更明显)
/*
(function (i) {
divs[i].onclick = function () {
console.log("###", i)
}
})(i)
*/
}
3.利用标签属性解决
在循环的时候直接将本次循环的 i 值添加给标签的index属性, 这样每次循环都能给不同的标签添加不同的 i 值,从而进行区分 解决变量污染的问题
for (var i = 0; i < divs.length; i++) {
divs[i].index = i;
divs[i].onclick = function () {
// console.log("###", i)
console.log(this.index)
}
}
二、面向对象
对象: 特征与行为的结合体, 是一个具象的实体
JS对象语法:
//单一对象
var obj={
// 属性(以key="value"的形式存在)
name:"Zero",
// 方法
teach:function(){
console.log("教学");
}
}
// 对象使用属性与方法, 采用.语法
console.log(obj.name);
obj.teach();
1、属性与方法(都是以key:"value"的形式存在的)
1.1 key的类型为字符串类型
在访问的时候,可以使用下面两种方式: obj.key | obj["key"]
js支持的标识符可以省略引号,反之不可以省略, 不支持的标识符访问方式: 不可以采用点语法,需要采用[ ]语法, eg: obj["background-color"]
var obj = {
name: "name",
"person-age": 18
}
// 访问
obj.name | obj["name"]
obj.["person-age"]
1.2 对象可以任意添加或删除属性
拓展: 获取的页面元素就是标签对象, 可以对其添加任意属性
var obj = {}; | var obj = new Object();
// 属性
obj.prop = "";
// 方法
obj.func = function () {}
// 删除属性与方法
delete obj.prop
delete obj.func
// 添加
obj.age = 18 //如果age的key已存在就是修改, 不存在就是添加键值对, 添加的key任意
// 注: 获取的页面元素(标签对象)也可以任意添加/删除 属性
2、类字典结构使用
结构
var dict = {name: "zero", age: 18}
拓展
var dict = {"my-name": "zero", fn: function () {}, fun () {}}
使用
dict.name | dict["my-name"] | dict.fn()
3、构造函数(ES5)
声明与普通函数一样,只是函数采用大驼峰体命名规则
构造函数内部属性方式不同于普通函数
ES5中还没有引入类的概念, 所以使用构造函数来模拟类的存在
我们目前一般都是使用ES5中的构造函数来当做类的使用
function People(name, age) { //类似于python中的类来使用
this.name = name; //this代表 Person构造函数实例化出的所有具体对象中的某一个
this.age = age;
this.eat = function () {
return 'eat';
}
}
如何使用构造函数中的属性与方法
//1.通过构造函数实例化出具体对象
//2.通过对象.语法调用属性与方法
var p1 = new Person('allen',18);
var p2 = new Person('eric',19);
console.log(p1.name)
console.log(p2.name)
p1.eat();
p2.eat();
4、继承(ES5)
定义一个父级
// 父级
function Sup(name) {
this.name = name;
this.fn = function () {
console.log('fn class');
}
}
// 原型
console.log(Sup.prototype);
console.log(sup.__proto__);
// 子级
function Sub(name) {
// 继承属性
Sup.call(this, name);
}
// 继承方法
Sub.prototype = new Sup;
// 创建子级对象
var sub = new Sub("subClass");
// 使用属性
console.log(sub.name);
// 使用方法
sub.fn();
// 指向自身构造函数
Sub.prototype.constructor = Sub;
5、类及继承(ES6)
// 父类
class People {
// 构造器: 完成对象的声明与初始化
// 属性在构造器中声明并完成初始化
constructor (name, age) {
this.name = name;
this.age = age;
}
// 类中规定实例方法
eat () {
console.log('吃吃吃');
}
// 类方法: 给类使用的
static create () {
console.log('诞生');
}
}
// 子类(使用extends继承父类)
class Student extends People {
constructor (name, age) {
// super关键词
super(name, age)
}
}
ES6中类的使用:
//1.实例化类的对象
let p1=new People('嘿嘿');
//2.使用属性与方法
console.log(p1.name)
p1.eat()
ES6中的类方法介绍:
类方法一般是由类来直接进行调用的,不建议使用由类实例化出的对象来调用,因为一般类方法都是一些功能类(工具类)的方法
class Tool { // 功能类(工具类)中的方法都定义为类方法
static max (num1, num2) {
return num1 > num2 ? num1 : num2;
}
}
// 通过Tool类来求两个数中的大值, 需要Tool类的对象出现吗? 不需要 => 功能有类直接使用
console.log(Tool.max(666, 888));
JS中的主动抛异常
throw "自定义异常";
onsole.log("上面如果出现了异常, 逻辑将会被强制停止,后边的代码不会被执行");
var num = 10 / 0;
console.log(num)
三、JS选择器
什么是js选择器: 将js与html建立起连接
js中一般称标签为页面元素
我们这小节中涉及到的几个对象名词的范围大小:
window > document > html > body
window不仅包括显示页面中的所有内容,还包括窗口上方的内容
所有显示页面中的内容(展现给用户 看的),都是属于文档(document)对象的内容,包括<!doctype html>
在文档中(document)中出现的所有内容都是document中的节点
HTML包括html标签内的所有内容
body包括bady标签内的所有内容
节点(了解):在文档(document)中出现的所有内容都是document中的节点
节点(node): 标签节点(元素element) | 注释节点 | 文本节点 | <!doctype>节点
标签节点指的是一个完整的标签
文本节点指的是标签之间的空白符合字符(包括两个标签之间的空白符)
1、getElement系列(最严谨)
该选择器是动态的: 当元素有变化时,会自动识别
获取文档中的标签 => document对象通过点语法去获取具体的目标标签元素
getElement选择标签的方法:
1.通过id名获取页面中出现的第一个唯一满足条件的页面元素
该方法只能由document调用
原因: 我们要保证一个文档中一个id只能出现一次,doctument检索的就是文档
而某父级标签只能检索自身内部区域,doctument可以保证文档中只能是一个id,而父级标签只能检索自身标签内部区域,documtnt可以保证文档中自身内部id不重复,能不能保证与外界不重复?
答案是不能的, 所以从安全角度出发,获取唯一对象的getRlementByID方法只能由能确定唯一id的对象来调用,能被document调用,不能被sup来调用
var body = document.getElementById('id名');
console.log(body)
2、通过class名获取所有满足条件的页面元素
该方法可以由document及任意页面元素对象调用
返回值为HTMLCollection (一个类数组结果的对象,使用方式同数组)
没有匹配到任何结果返回空HTMLCollection对象 ([])
取到列表之后可以使用索引来取到我们需要的相应元素
var divs = document.getElementsByClassName('class名');
console.log(divs)
3.通过tag(标签)名获取所有满足条件的页面元素
该方法可以由document及任意页面元素对象调用
返回值为HTMLCollection (一个类数组结果的对象,使用方式同数组)
没有匹配到任何结果返回空HTMLCollection对象 ([])
取到列表之后可以使用索引来取到我们需要的相应元素
document.getElementsByTagName('tag名');
2、querySelector系列(最方便)
参数里边是采用css选择器的语法
对id检索是不严谨的
querySelector选择标签的方法:
1.获取第一个匹配到的页面元素
该方法可以由document及任意页面对象调用/
var div = document.querySelector('css语法选择器');
console.log(div)
2.获取所有匹配到的页面元素(检索所有满足结果)
该方法可以由document及任意页面对象调用
返回值为NodeList (一个类数组结果的对象,使用方式同数组)
取到列表之后可以使用索引来取到我们需要的相应元素
没有匹配到任何结果返回空NodeList对象 ([])
参数中也是采用css选择器的语法
var divs = document.querySelectorAll('css语法选择器');
console.log(divs)
3、通过id名直接获取
可以通过id名直接获取对应的页面元素对象,但是不建议使用
如使用console.log(id名)可以直接进行打印
4.JS中操作页面标签全局属性,映射到HYML中
// 获取页面标签ele的alert全局属性的值,如果没有该全局属性结果为null
ele.getAttribute("alert")
ele.setAttribute("att_key","attr_value");
//页面标签ele已有该全局属性,就是修改值, 没有就是添加该全局属性并赋相应值
注: 一般应用场景,结合css的属性选择器完成样式修改
四、JS中的事件(基础)
什么是事件: 页面标签在满足某种条件下可以完成指定功能的这种过程,称之为事件
某种条件: 如鼠标点击标签: 单击事件 | 鼠标双击标签: 双击事件 | 鼠标悬浮标签: 悬浮事件 | 键盘按下: 键盘按下事件
指定功能: 开发者根据实际需求完成相应的功能实现
钩子函数: 就是满足某种条件被系统回调的函数(完成指定功能)
点击事件: 明确激活钩子的条件= 激活钩子后该处理什么逻辑指定完成功能
事件使用简单案例:
var div = document.querySelector(".div"); // 找到的是第一个.div
div.onclick = function () {
// alert(123)
this.style.backgroundColor = "pink";
}
// 明确第一个及第二个
var divs = document.querySelectorAll('.div');
divs[1].ondblclick = function () {
divs[0].style.backgroundColor = "yellow";
}
事件使用案例:(事件控制标题栏)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>js事件控制标题栏</title>
<style>
.part1 div {
100px;
height: 30px;
text-align: center;
line-height: 30px;
float: left;
cursor: pointer;
}
.part1 {
overflow: hidden;
}
h2 {
height: 30px;
}
</style>
</head>
<body>
<div class="part1">
<div class="b1">标题栏</div>
<div class="b2">标题栏</div>
<div class="b3">标题栏</div>
<div class="b4">标题栏</div>
</div>
<h2></h2>
</body>
</html>
第一种方式:使用事件一步一步实现
<script>
var b1 = document.querySelector('.b1');
// 鼠标悬浮事件
b1.onmouseenter = function () {
console.log("鼠标悬浮上了");
// 悬浮上后,该标签的字体颜色变化橘色
this.style.color = "#FF6700";
}
// 需求并非为鼠标移走,去除颜色
b1.onmouseleave = function () {
this.style.color = "#000";
}
</script>
第二种方式:
使用循环绑定的方式进行多个标题的控制
在这里使用var和let进行循环绑定时的区别:
var是没有块级作用域的概念的,也就是说在这里使用var进行循环绑定,i 的值在循环外边也是可以访问的,在循环的时候就会不断被修改,在本题中,i 的值最终会被修改为4
使用let的时候let具有块级作用域的概念,在每次循环都是会产局部作用域的,在局部作用域中产生的变量,在外部不能被访问的,所以使用了let之后,每次循环 i 的值都是新的,这就简单解决了变量污染的问题
在这里还要注意在JS中函数的定义和调用不是严格遵守先定义后调用的原则的, 它交给浏览器解析的时候会有一个编译过程,会将文档中产生的所有名称存放起来,所以在函数定义的上边进行函数的调用也是没有问题的,在编译过程结束之后才会执行函数里边的代码体
<script>
// 制作数据
var data = ["标题1", "标题2", "标题3", "标题4"];
var divs = document.querySelectorAll('.part1 div');
console.log(divs);
// 循环绑定 => 会出现变量(i)污染
for (let i = 0; i < divs.length; i++) {
divs[i].onmouseenter = function () {
// 打印自身索引值
console.log(i);
// 将自身颜色变为橘色,其他兄弟颜色变为黑色
// 就是i为橘色, 非i为黑色
changeColor(i);
// 悬浮内容
changeContent(i)
}
}
// console.log(i);
// 自定义的修改颜色的方法
function changeColor(index) {
for (let i = 0; i < divs.length; i++) {
// 先不管三七二十一,全改成黑色
divs[i].style.color = "black";
// 如果是目标选中标签,它的颜色再重新设置为橘色
if (i == index) {
divs[i].style.color = "#FF6700";
}
}
}
var h2 = document.querySelector('h2');
// 修改内容
function changeContent(index) {
h2.innerText = data[index];
}
</script>
五、 JS处理操作页面:
在进行页面操作之前,必须要先获取页面元素:
比如我们通过类名获取元素:
var d1 = document.querySelector('.d1');
var d2 = document.querySelector('.d2');
var d3 = document.querySelector('.d3');
1.操作页面内容:
innerText是获取文本内容的
box.innerText
可以设值, 也可以获取值
var text = d1.innerText;
// 获取内容
console.log(text);
// 修改(删除)内容
d1.innerText = "";
d1.innerText = "修改后的文本内容";
读写 style属性 样式
d1.style.backgroundColor = 'red';
// 1.操作的为行间式
// 2.可读可写
// 3.具体属性名采用小驼峰命名法
② 操作标签内容
box.innerHTML
可以设值, 也可以获取值, 能解析html语法代码
box.outerHTML
获取包含自身标签信息的所有子内容信息
// 获取
var html = d2.innerHTML;
console.log(html)
// 修改
d2.innerHTML = "<b>加粗的文本</b>"; // 可以解析html语法的代码
// d2.innerText = "<b>加粗的文本</b>";
// 了解
console.log(d2.innerHTML); // 只是标签内部的子标签与子内容
console.log(d2.outerHTML); // 不仅包含标签内部的子标签与子内容,还包含自身标签信息
2.操作页面样式
1.获取 页面样式
var bgColor = d3.style.backgroundColor; // 只能获取行间式
console.log(bgColor);
2. 修改
d3.style.backgroundColor = "yellow"; // 只能修改行间式
行间式的我们可以进行修改了,那问题就来了
问题: 那用内联外联设置的样式如何获取?
内联与外联设置的样式叫: 计算后样式
getComputedStyle(目标标签, 伪类(null填充)).具体的样式
bgColor = window.getComputedStyle(d3, null).backgroundColor; // 兼容性较差
console.log(bgColor);
// 可以获取计算后样式, 也可以获取行间式, 但它为只读
bgColor = getComputedStyle(d3, null).getPropertyValue('background-color'); // 兼容性较好
console.log(bgColor);
// 一些不常用的属性会出现浏览器之间的兼容问题, 通过添加前缀来处理
console.log(d3.style);
// chrome: -webkit-
// ie: -ms-
// opera: -o-
// eg: 背景颜色
// 推荐
getComputedStyle(页面元素对象, 伪类).getPropertyValue('background-color');
// 不推荐
getComputedStyle(页面元素对象, 伪类).backgroundColor;
// IE9以下
页面元素对象.currentStyle.getAttribute('background-color');
页面元素对象.currentStyle.backgroundColor;
// 1.页面元素对象由JS选择器获取
// 2.伪类没有的情况下用null填充
// 3.计算后样式为只读
// 4.该方式依旧可以获取行间式样式 (获取逻辑最后的样式)
操作样式小结:
box.style.样式名 ==> 可以设值,也可以获取,但操作的只能是行间式
getComputedStyle(box, null).样式名 ==> 只能获取值,不能设值, 能获取所有方式设置的值(行间式 与 计算后样式)
注: 获取计算后样式,需要关注值的格式
结合 css 操作样式
页面元素对象.className = ""; // 清除类名
页面元素对象.className = "类名"; // 设置类名
页面元素对象.className += " 类名"; // 添加类名
---------------------
原文:https://blog.csdn.net/Onion_cy/article/details/85101977