回调函数、闭包、循环绑定、面向对象、定时器

一、函数高级

1、函数回调

// 回调函数
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>

2、闭包

function outer() {
var data = {}
function inner() {
return data;
}
return inner;
} // 使用闭包的原因:不能使用函数回调(调用函数已有固定参数,或不能拥有参数),只能将函数定义到拥有局部变量函数的内部
// 闭包目的:不允许提升变量作用域时,该函数的局部变量需要被其他函数使用
// 闭包本质:函数的嵌套,内层函数称之为闭包
// 闭包的解决案例:①影响局部变量的生命周期,持久化局部变量;②解决循环绑定导致的变量污染
2.1、闭包解决变量的生命周期问题

局部变量的生命周期在函数运行结束时就结束,将局部变量传到外部函数,实现了延长局部变量声明周期的效果

<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>
2.2、闭包解决变量污染问题

变量污染:前几次变量的定义,被最后一次定义覆盖。

// 在循环绑定中,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);
}
}

利用闭包解决:

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);

3.总结:

  • 函数会产生局部作用域, 外部需要使用 -- 返回值 | 函数回调 | 闭包 | 提升作用域(不建议)
  • 在外部另一个函数中使用该局部变量 -- 函数回调 | 闭包

二、循环绑定

.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.闭包解决,如:一、2.2 利用闭包解决循环绑定所带来的变量污染
// 3.对象属性解决
2.1、通过获取局部作用域解决变量污染
// 在ES5中没有块级作用域,在ES6中有块级作用域,所以只要将 var 改为 let 即可解决变量污染
let lis = document.querySelectorAll('li');
for (let i = 0; i < lis.length; i++) {
lis[i].onclick = function () {
alert(i)
}
}
2.2、通过对象属性解决变量污染
<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>

三、面向对象JS

1、属性与方法

// 创建对象
var obj = {}; | var obj = new Object(); // 前者一般是创建一个对象是用,后者在需要创建多个对象是用
// 属性
obj.属性名 = "";
// 方法
obj.func = function () {}
// 删除属性与方法
delete obj.prop
delete obj.func

2、类字典结构使用

JS中没有字典(键值对存储数据的方式),但可以通过对象实现字典方式存储数据,并使用数据

  • 结构
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()
  • 增删改查key与value
// 增
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"]);
类字典总结:
  • key全为字符串形式,但存在两种书写方式
  • key在JS标识符语法支持情况下,可以省略引号,但key为js标识符不支持的语法情况下,必须添加引号
  • value可以为任意类型
  • 访问值可以通过字典名(对象名).key语法与["key"]语法来访问value
  • 可以随意添加key与value完成增删改查

3、构造函数(ES5)

function People(name, age) {
this.name = name;
this.age = age;
this.eat = function () {
return '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) {
// 继承属性,在继承函数中由被继承(父级)函数调用,传入继承函数的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();

5、类及继承(ES6)

// 父类
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无法完成的动画

  • setInterval:持续型定时器,setInterval(函数, 时间间隔(毫秒数), 函数所需参数(可以省略));
  • setTimeout:一次型定时器,setTimeout(函数, 时间间隔(毫秒数), 函数所需参数(可以省略));
// 一次性定时器
/* 异步执行
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.允许清除不存在的定时器编号

前端(十三)—— JavaScript高级:回调函数、闭包、循环绑定、面向对象、定时器的更多相关文章

  1. JavaScript利用闭包循环绑定事件

    我们经常在做前端面试题的时候,会遇到循环绑定事件后,输出打印结果,很多人总是搞不清楚,今天借此机会跟大家梳理一下闭包相关作用. 1.首先我们举一个简单的例子. html部分: <a href=& ...

  2. nodejs-REPL/回调函数/事件循环

    REPL 回调函数 事件循环 REPL----------------------------------------------------- Node.js REPL(Read Eval Prin ...

  3. JavaScript Callback 回调函数

    JavaScript callback回调函数 你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货.在这 ...

  4. JavaScript高级程序设计--函数小记

    执行环境和作用域链   每个函数都有自己的执行环境.当执行流进入一个函数时,函数 的环境就会被推入一个环境栈中.而在函数执行之后,栈将其环境弹出,把控制权返回给之前的执行环境.   当代码在一个环境中 ...

  5. 告诉你什么是javascript的回调函数

    函数也是对象 想弄明白回调函数,首先的清楚地明白函数的规则.在javascript中,函数是比较奇怪的,但它确确实实是对象.确切地说,函数是用Function()构造函数创建的Function对象.F ...

  6. javascript的回调函数

    函数也是对象 想弄明白回调函数,首先的清楚地明白函数的规则.在javascript中,函数是比较奇怪的,但它确确实实是对象.确切地说,函数是用Function()构造函数创建的Function对象.F ...

  7. Javascript之回调函数(callback)

    1.回调函数定义: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方 ...

  8. JavaScript中回调函数的使用

    在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A.我们就说函数A叫做回调函数.如果没有名称(函数表达式),就叫做匿名回调函数. ...

  9. JavaScript高级之函数的四种调用形式

    主要内容 分析函数的四种调用形式 弄清楚函数中this的意义 明确构造函对象的过程 学会使用上下文调用函数 了解函数的调用过程有助于深入学习与分析JavaScript代码. 本文是JavaScript ...

  10. JavaScript碎片—函数闭包(模拟面向对象)

    经过这几天的博客浏览,让我见识大涨,其中有一篇让我感触犹深,JavaScript语言本身是没有面向对象的,但是那些大神们却深深的模拟出来了面向对象,让我震撼不已.本篇博客就是在此基础上加上自己的认知, ...

随机推荐

  1. 用 Flask 来写个轻博客 (17) — MV(C)_应用蓝图来重构项目

    目录 目录 前文列表 重构目录结构 重构代码 使用蓝图后的路由过程 总结 前文列表 用 Flask 来写个轻博客 (1) - 创建项目 用 Flask 来写个轻博客 (2) - Hello World ...

  2. PHP面试 MySQL的高可扩展和高可用

    MySQL的高可扩展和高可用 面试题一 MySQL分表和分区的工作原理,分表和分区的使用场景和优缺点. 分区表的原理 对用户而言,分区表时一个独立的逻辑表,但是底层MySQL将其分成了多个物理子表,这 ...

  3. EmWin 如何显示汉字 不用在文件中使用编码

    1. Font Converter for emWin 生成C文件字库 1.1 新建文件 1.2 选择字体 1.3 为了减小C文件体积,这里只加入自己需要的汉字,先把所有字体取消选择. 1.4 新建一 ...

  4. EOJ 1127. 多边形面积(计算几何)

    题目链接:1127. 多边形面积(计算几何) 题意 按逆时针顺序给出 \(n\) 个点的坐标,求这些点围成的多边形的面积. 思路 选择多边形上的一个点,然后每次枚举之后的两个点,计算叉积,注意要保留符 ...

  5. 12.Jmeter 快速入门教程 -- 监控被测资源

    写在前面的话, 作者认为jmeter的监控被测服务器资源只是基本可用, 还好习惯了linux的各种命令和工具,所以也基本不用担心什么了.但是有了图形化的监控, 也方便给领导出报告. 怎么说也是不错的. ...

  6. Java.io包

    Java.io.BufferedInputStream 类添加功能到另一个输入流,缓冲输入以及支持mark和reset methods.Following是关于缓冲输入流的要点: 当创建缓冲输入,创建 ...

  7. 使用php的curl函数post返回值为301永久迁移的问题。(301 Moved Permanently)

    本文链接:https://blog.csdn.net/Angus_01/article/details/82467652添加一行curl_setopt: curl_setopt($ch,CURLOPT ...

  8. 区别:javascript:void(0);javascript:;

    2015-07~2015-08 区别:javascript:void(0);javascript:; href="#",包含了一个位置信息.默认的锚是#top,也就是网页的上端. ...

  9. spring中配置Properties对象的方法

    工作中有必要将Properties对象进行注解进入:比如 class Person{ @Autowired private Properties properties; } 如果有这种需求的话,那么需 ...

  10. promise、async、await、settimeout异步原理与执行顺序

    一道经典的前端笔试题,你能一眼写出他们的执行结果吗? async function async1() { console.log("async1 start"); await as ...