// 回调函数 function callback(data) {} // 逻辑函数 function func(callback) { // 函数回调,判断回调函数是否存在 if (callback) callback(data); } func(callback); // 函数回调的本质:在一个函数中(调用函数),当知足必定条件,调用参数函数(回调函数) // 回调函数做为调用函数的参数传入,知足必定的条件,调用回调函数,回调函数能够获取调用函数中的局部变量 // 回调函数目的:经过参数将调用函数内部数据传出,请求数据 => 数据(return | 函数回调) => 外界,匿名函数的自调用,没有调用者,因此没法获取返回值,只能经过回调函数来实现
<!-- 外部要接收数据 --> <!-- 1.外部给内部提供回调函数(函数名callback) --> <!-- 2.内部将数据反馈给外部回调函数.外部就可使用内部数据 --> <script type="text/javascript"> var callback = function (data) { // 使用数据 console.log(data); } </script> <!-- 请求数据 --> <script type="text/javascript"> // 利用异常处理捕获callback未定义的异常,不作处理 try { // 采用匿名函数自调用请求数据,达到页面一加载就获取到数据 (function (callback) { console.log("开始请求数据..."); // ... var data = [1, 2, 3, 4, 5]; console.log("数据请求完毕!!!"); // 若是回调函数存在,那么回调对应的函数,并将数据携带出去 if (callback) { callback(data); } })(callback) // 请求数据完毕以后,须要让外界获取请求的数据: } catch (err) { } </script>
<script type="text/javascript"> // 钩子:知足条件状况下被系统回调的函数(方法),称之为钩子函数(方法) <=> 回调函数 document.onclick = function (a, b , c) { console.log("点击事件"); console.log(a, b , c); } </script>
function outer() { var data = {} function inner() { return data; } return inner; } // 使用闭包的缘由:不能使用函数回调(调用函数已有固定参数,或不能拥有参数),只能将函数定义到拥有局部变量函数的内部 // 闭包目的:不容许提高变量做用域时,该函数的局部变量须要被其余函数使用 // 闭包本质:函数的嵌套,内层函数称之为闭包 // 闭包的解决案例:①影响局部变量的生命周期,持久化局部变量;②解决循环绑定致使的变量污染
局部变量的生命周期在函数运行结束时就结束,将局部变量传到外部函数,实现了延长局部变量声明周期的效果javascript
<script type="text/javascript"> function outer() { // eg: 请求获得的数据,如何不持久化,方法执行完毕后,数据就会被销毁 var data = [1, 2, 3, 4, 5]; console.log(data); // 经过闭包解决该类问题,因此闭包因此代码都可以随意自定义 function inner() { return data; } // 数据被inner操做返回,inner属于outer,属于须要outer将inner返回出去(跟外界创建起联系) return inner; } // 将局部变量生命周期提高于inner函数相同,inner存在,局部变量data就一直存在 var inner = outer(); console.log(inner()); </script>
变量污染:前几回变量的定义,被最后一次定义覆盖。html
// 在循环绑定中,onclick函数中的变量i指向的内存地址,通过循环以后i变成了5,因此每一个元素事件运行的时候变量i都是5 var list = document.getElementById("ulDemo").getElementsByTagName("li"); for (var i = 0; i < list.length; i++) { var li = list[i]; li.onclick= function () { alert(i); } }
利用闭包解决:java
var lis = document.querySelectorAll('ul li'); // 2.循环绑定 for (var i = 0; i < lis.length; i++) { // 解决的原理:一共产生了5个外层函数,存储的形参i的值分别是0, 1, 2, 3, 4 // 内层函数也产生了5个,且和外层函数一一对应,打印的i就是外层函数的形参i // 外层函数 (function (i) { // 内层函数:闭包 lis[i].onclick = function () { alert(i) } })(i) } console.log(i);
.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); } } // 循环绑定会致使变量污染,解决方法以下: // 1.获取局部(块级)做用域解决:在ES5中没有块级做用域,而在ES6中有块级做用域 // 2.闭包解决,如:1、2.2 利用闭包解决循环绑定所带来的变量污染 // 3.对象属性解决
// 在ES5中没有块级做用域,在ES6中有块级做用域,因此只要将 var 改成 let 便可解决变量污染 let lis = document.querySelectorAll('li'); for (let i = 0; i < lis.length; i++) { lis[i].onclick = function () { alert(i) } }
<script type="text/javascript"> var lis = document.querySelectorAll('li'); for (var i = 0; i < lis.length; i++) { // lis[i]依次表明五个li页面元素对象 // 给每个li设置一个(临时)属性 lis[i].index = i; // 第一个li的index属性存储的就是索引0,以此类推,最后一个存储的是索引4 lis[i].onclick = function () { // var temp = lis[i].index; // lis[i]中的i同样存在变量污染 var temp = this.index; // 当前被点击的li alert(temp) // temp => this.index(lis[i].index) => i(索引) } } </script>
// 建立对象 var obj = {}; | var obj = new Object(); // 前者通常是建立一个对象是用,后者在须要建立多个对象是用 // 属性 obj.属性名 = ""; // 方法 obj.func = function () {} // 删除属性与方法 delete obj.prop delete obj.func
JS中没有字典(键值对存储数据的方式),但能够经过对象实现字典方式存储数据,并使用数据es6
var dict = {name: "zero", age: 18}
// key在JS标识符语法支持状况下,能够省略引号,但key为js标识符不支持的语法状况下,必须添加引号 var dict = {"my-name": "zero", fn: function () {}, fun () {}}
dict.name | dict["my-name"] | dict.fn()
// 增 dict.key4 = true; console.log(dict); // 删 delete dict.key4; console.log(dict); // 改 dict["my-key3"] = [5, 4, 3, 2, 1]; console.log(dict); // 查 console.log(dict.key1); console.log(dict["key1"]);
function People(name, age) { this.name = name; this.age = age; this.eat = function () { return 'eat'; } }
// 父级 function Sup(name) { this.name = name; this.fn = function () { console.log('fn class'); } } // 原型 console.log(Sup.prototype); console.log(sup.__proto__); // 子级 function Sub(name) { // 继承属性,在继承函数中由被继承(父级)函数调用,传入继承函数的this与被继承函数建立属性对属性进行赋值的全部须要的数据(name) Sup.call(this, name); } // 继承方法,利用prototype原型,将new Sup赋值给Sub.prototype Sub.prototype = new Sup; // 建立子级对象 var sub = new Sub("subClass"); // 使用属性 console.log(sub.name); // 使用方法 sub.fn(); // 指向自身构造函数 Sub.prototype.constructor = Sub;
// 案例 // 1.完成继承,必须拥有两个构造函数 // 2.一个函数要使用另一个函数的属性与方法,须要对其进行继承(属性与方法的复用) // 3.属性的继承call方法,在继承函数中由被继承函数调用,传入继承函数的this与被继承函数建立属性对属性进行赋值的全部须要的数据,eg:如Sup有name属性,那么能够经过call将Sub的name传给Sup // 4.方法的继承prototype原型,将new Sup赋值给Sub.prototype function Sup(name) { // 属性存放某个值 this.name = name; // 方法完成某项功能 this.func = function () { console.log("func"); } } var sup = new Sup("supClass"); console.log(sup.name); sup.func(); // 相似于子级 function Sub(name) { // 属性的继承 Sup.call(this, name); } // 方法的继承 Sub.prototype = new Sup; var sub = new Sub("subClass"); console.log(sub.name); sub.func();
// 父类 class People { // 构造器 constructor (name, age) { this.name = name; this.age = age; } // 实例方法 eat () { console.log('吃吃吃'); } // 类方法 static create () { console.log('诞生'); } } // 子类 class Student extends People { constructor (name, age) { // super关键词 super(name, age) } }
应用场景:完成JS自启动画;完成CSS没法完成的动画闭包
// 一次性定时器 /* 异步执行 setTimeout(函数, 毫秒数, 函数所需参数(能够省略)); */ console.log("开始"); setTimeout(function (data) { console.log(data); }, 1000, "数据"); console.log("结束"); // 持续性定时器 /*异步执行 setInterval(函数, 毫秒数, 函数所需参数(能够省略)); */ console.log("又开始"); var timer = setInterval(function() { // timer变量,是定时器编号,是普通的数字类型 console.log("呵呵"); }, 1000) console.log(timer); console.log("又结束");
// 清除定时器 // 1.持续性与一次性定时器一般都应该有清除定时器操做 // 2.清除定时器操做能够混用 clearTimeout() | clearInterval() // 3.定时器的返回值就是定时器编号,就是普普统统的数字类型 document.onclick = function () { console.log("定时器清除了"); clearInterval(timer); // clearTimeout(timer); } // 清除全部定时器 // 若是上方建立过n个定时器,那么timeout值为n+1 var timeout = setTimeout(function(){}, 1); for (var i = 0; i < timeout; i++) { // 循环将编号[0, n]全部定时器都清除一次 clearTimeout(i) } // 1.容许重复清除 // 2.容许清除不存在的定时器编号