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

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

一、函数高级

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.允许清除不存在的定时器编号

原文地址:https://www.cnblogs.com/linagcheng/p/9799897.html

时间: 2024-11-12 14:57:05

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

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

在javascript中回调函数非常重要,它们几乎无处不在.像其他更加传统的编程语言都有回调函数概念,但是非常奇怪的是,完完整整谈论回调函数的在线教程比较少,倒是有一堆关于call()和apply()函数的,或者有一些简短的关于callback的使用示例. 函数也是对象 想弄明白回调函数,首先的清楚地明白函数的规则.在javascript中,函数是比较奇怪的,但它确确实实是对象.确切地说,函数是用Function()构造函数创建的Function对象.Function对象包含一个字符串,字符串包

web前端之JavaScript高级程序设计六:事件

web前端之JavaScript高级程序设计六:事件 JavaScript 与 HTML 之间的交互是通过事件实现的.事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间.可以使用侦听器(或处理程序)来预订事件,以便事件发生时执行相应的代码.这种在传统软件工程中被称为观察员模式的模型,支持页面的行为(JavaScript 代码)与页面的外观(HTML 和 CSS 代码)之间的松散耦合. 事件流: 事件流描述的是从页面中接收事件的顺序.但有意思的是, IE 和 Netscape 开发团队居然提出了

JavaScript利用闭包循环绑定事件

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

JavaScript自定义回调函数

背景分析 首先看一段js的代码,主要实现添加的时候首先通过异步请求判断是否存在,如果不存在的话,在进行添加操作: function add(url,data) { var isExited = isExited(data); if(!isExited){ addRequest(url, data); } } 当我添加一个数据的时候,我首先通过判断是否在数据库中存在(当然,如果前后台彻底分离的话,不应该前端进行业务逻辑的判断,前端只应该,用来展示数据),首先,isExited()的请求是ajax请

Javascript AJAX回调函数传递参数

在Javascript 中,特别是在AJAX中,回调函数常常是一个函数名,没有地方放入参数,如下面的AJAX代码,在成功后将调用回调函数callback,但callback是有参数的,如何把参数传进来呢? var callback = function(p1){ //do something } var ajaxSetting = { url: url, timeout:me.timeout, type: method, contentType: "application/json",

JavaScript中回调函数的使用

在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A.我们就说函数A叫做回调函数.如果没有名称(函数表达式),就叫做匿名回调函数. 在实际应用中,可以这么应用,一个方法进行获取数据源,另一个方法(回调函数)可以通过数据源在页面上进行展示,可以根据具体的需求进行展示就行,如果多个地方用到这个数据源,可以写不同的回调函数,将此函数传入这个方法中即可. 来,咱们通过实例可以一目了然 获取公司信息的小例子 1.获取公司信息数据源的方法(

javascript 的回调函数

既然函数可以像其他数据那样赋值给某个个变量,可以被定义.删除.拷贝,那为什么就不能被当成参数传递给其他函数呢? 下面的示例中,我们定义了一个以两个函数为参数的函数.该函数会分别执行这两个参数函数,并返回它们的返回值之和. function invoke_and_add(a,b){ return a() + b(); } 现在让我们来简单定义一下这两个参与加法运算的函数,它们只是单纯地返回一个硬编码值: function one(){ return 1; } function two(){ ret

Javascript之回调函数(callback)

1.回调函数定义: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用为调用它所指向的函数时,我们就说这是回调函数.回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应. 在JavaScript中,回调函数具体的定义为:函数A作为参数(函数引用)传递到另一个函数B中,并且这个函数B执行函数A.我们就说函数A叫做回调函数.如果没有名称(函数表达式),就叫做匿名回调函数.因此callb

javascript 自定义回调函数

javascript 回调函数 如果你直接在函数a里调用的话,那么这个回调函数就被限制死了.但是使用函数做参数就有下面的好处:当你a(b)的时候函数b就成了回调函数,而你还可以a(c)这个时候,函数c就成了回调函数.如果你写成了functiona(){...;b();}就失去了变量的灵活性. function a(index,callback){ callback(index); } function b(index){ alert(index); } a(10000,b);

理解JavaScript中回调函数的使用

首先要理解function 对象,在JavaScript中function和array object,number一样作为一个对象,因此function也可以像普通对象一样可以作为一个参数传递个另一个函数; function parentF(callback){//callback可以任意定义名称,它只是个参数,此时并不能确定callback的类型(是number,object,function都不确定) var a=1; var b=2;  console.log("parent")