目录 一、函数高级 循环绑定: 使用循环绑定会出现的问题及解决方案: 二、面向对象 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文件
循环绑定: .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)对象的内容,包括 在文档中(document)中出现的所有内容都是document中的节点 HTML包括html标签内的所有内容 body包括bady标签内的所有内容 节点(了解):在文档(document)中出现的所有内容都是document中的节点 节点(node): 标签节点(元素element) | 注释节点 | 文本节点 | 节点 标签节点指的是一个完整的标签 文本节点指的是标签之间的空白符合字符(包括两个标签之间的空白符) 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"; } 事件使用案例:(事件控制标题栏)
js事件控制标题栏 第一种方式:使用事件一步一步实现 第二种方式: 使用循环绑定的方式进行多个标题的控制 在这里使用var和let进行循环绑定时的区别: var是没有块级作用域的概念的,也就是说在这里使用var进行循环绑定,i 的值在循环外边也是可以访问的,在循环的时候就会不断被修改,在本题中,i 的值最终会被修改为4 使用let的时候let具有块级作用域的概念,在每次循环都是会产局部作用域的,在局部作用域中产生的变量,在外部不能被访问的,所以使用了let之后,每次循环 i 的值都是新的,这就简单解决了变量污染的问题 在这里还要注意在JS中函数的定义和调用不是严格遵守先定义后调用的原则的, 它交给浏览器解析的时候会有一个编译过程,会将文档中产生的所有名称存放起来,所以在函数定义的上边进行函数的调用也是没有问题的,在编译过程结束之后才会执行函数里边的代码体 五、 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 = "
加粗的文本"; // 可以解析html语法的代码 // d2.innerText = "
加粗的文本"; // 了解 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