一、函数高级
1、函数回调
// 回调的函数
function callback(data) {}
// 逻辑函数
function func(callback) {
// 函数回调
if (callback) callback(data);
}
// 函数回调的本质:在一个函数中(调用函数),当满足一定条件,调用参数函数(回调函数)
// 回调函数作为调用函数的参数传入
// 回调函数通过参数将调用还是内部数据传出
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>函数的回调</title>
</head>
<body>
函数的回调
</body>
<script type="text/javascript">
// 函数回调
// 在一个函数(fn)中,满足条件情况下,调用另外一个函数(func)
// 注:func函数 是 fn函数 的参数(函数作为函数参数传入)
// 解决问题:
// 请求数据 => 数据(return | 函数回调) => 外界
function a_fn(data) {
console.log('a_fn');
// 如果要使用数据,那么定义形参接收参数
console.log(data);
}
function b_fn(a_fn) {
var data = "b_fn 的 数据";
console.log('b_fn');
// 条件: a_fn有值(有函数实现体)
if (a_fn) {
// 调用参数函数
a_fn(data);
}
}
b_fn(a_fn);
// 1.一个函数(函数名)作为另外一个函数的参数
// 2.满足一定的条件,调用参数函数
// 3.形成了函数回调,回调的函数可以获取调用函数的局部变量(将数据携带出去)
</script>
<!-- 函数回调在系统中的使用 -->
<script type="text/javascript">
// 通常情况下,我们的页面标签存不存在点击事件? => 存在
// 点击事件触发后,可不可以对外传送数据 => 可以,eg:点在页面的什么位置
// 系统已经书写好了这种函数回调,但是没有回调体,回调体(回调函数)由普通开发者提供
// 钩子:满足条件情况下被系统回调的函数(方法),称之为钩子函数(方法) <=> 回调函数
document.onclick = function (a, b , c) {
console.log("点击事件");
console.log(a, b , c);
}
</script>
</html>
2、闭包
function outer() {
var data = {}
function inner() {
return data;
}
return inner;
}
// 闭包目的:不允许提升变量作用域时,该函数的局部变量需要被其他函数使用
// 闭包本质:函数的嵌套,内层函数称之为闭包
// 闭包的解决案例:①影响局部变量的生命周期,持久化局部变量;②解决变量污染
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>闭包</title>
</head>
<body>
闭包
</body>
<script type="text/javascript">
// 闭包: 函数的嵌套定义,内层函数就是闭包
// 闭包产生的原因:
// 1.函数会产生局部作用域, 外部需要使用 -- 返回值 | 函数回调 | 闭包 | 提升作用域
// 2.在外部另一个函数中使用该局部变量 -- 函数回调 | 闭包
// 3.不能使用函数回调(函数已有固定参数,或不能拥有参数),只能将函数定义到拥有局部变量函数的内部 => 闭包
// 总结:一个函数要使用另外一个函数的局部变量
// 提升作用域
var a; // 作用域被提升
function fn() {
a = 10; // 局部变量 => 在外部定义
}
fn();
// 外部使用局部变量: 返回值 | 函数回调 | 闭包 | 提升作用域
console.log(a);
// 好处:
// 1.外部函数a_fn不需要强制拥有参数以及返回值
// 2.外部函数的局部变量也无需提升作用域,可以保证参数的安全性
// 3.内部函数b_fn也不需要强制拥有参数与返回值,便可以直接使用外部函数a_fn的局部变量data
function a_fn() {
var data = [1, 2, 3, 4, 5];
// 闭包
function b_fn() {
console.log('>>>', data);
}
b_fn();
}
a_fn();
// 闭包使用:
// 外部函数在外部调用
// 内部函数在(外部函数)内部调用
// 就是闭包可以解决哪些问题
// 1.局部变量的持久化
// 2.变量污染(页面标签循环绑定)
</script>
</html>
二、循环绑定
.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、使用闭包解决局部变量生命周期
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>局部变量生命周期</title>
</head>
<body>
局部变量生命周期
</body>
<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>
2、使用闭包解决变量污染问题
/* .css */
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
width: 80px;
height: 35px;
background-color: pink;
border-radius: 5px;
float: left;
margin-left: 3px;
}
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>闭包解决变量污染</title>
<!-- .html -->
</head>
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
</html>
// .js
// 需求:点击li,打印li在ul中的索引 => 0, 1, 2, 3, 4
// 1.lis
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); // 点击事件触发一定晚于该逻辑语句
// 所以再去触发点击,弹出i的值,永远是5
// 该类问题就称之为变量污染
3、利用块级作用域解决循环绑定
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<title>块级作用域解决循环绑定</title>
<style type="text/css">
ul {
margin: 0;
padding: 0;
list-style: none;
}
li {
width: 80px;
height: 35px;
background-color: pink;
border-radius: 5px;
float: left;
margin-left: 3px;
}
</style>
</head>
<body>
<ul>
<li></li>
<li></li>
<li></li>
<li></li>
<li></li>
</ul>
</body>
<script type="text/javascript">
// ES6语法中支持块级作用域
let lis = document.querySelectorAll('li');
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
alert(i)
}
}
</script>
</html>