个人收藏JavaScript

JavaScript - 闭包 - 函数回调 - 即时函数

2017-03-29  本文已影响310人  西巴撸

<h4>本小节主要讲解闭包,是特别重要的一块内容.希望大家能够用心学习!</h4>

作用域链的补充内容 ----> 搜索规则

如果有忘记的人,翻一下上一篇博客

注意点:如果在内层作用域中声明了和外层作用域中同名的变量,那么这个变量是不会把外层的同名变量覆盖的

搜索原则:

闭包

闭 : 关闭,封闭的意思,对外界不开方的

包 : 包装起来

闭包技术

访问数据

<script>
    function f1(){
        var num = 10;
        return num;
    }

    //num
    var a = f1();
    var b = f1();

    console.log(a);
    console.log(b);

    //一次性获得数据
    //1 每次调用函数获得的数据并不是同一份数据
    //2 只能获取值,但是却不能修改值
</script>
<script>
    function f1(){
        var num = 10;
        return function(param){
            num = param;    //修改函数内部变量的值
            return num;
        };
    }
</script>
<script>
    function f1(){
        var num = 10;
        var name = "张学友";

        return function(){
            return [num,name];
        };
    }

    var func = f1();
    console.log(func()[0]);
    console.log(func()[1]);
</script>
<script>
    function f1(){
        var num = 10;
        var name = "xxx";
        return {
            getNum:function(){
                return num;
            },
            getName:function(){
                return name;
            }
        }
    }

    var func = f1();
    console.log(func.getName());
    console.log(func.getNum());
</script>

闭包读取数据和设置数据

<script>
    function foo(){
        var name = "卡罗";
        var age = 18;
        return {
            getName:function(nameValue){
                //判断
                if (nameValue != undefined)
                {
                    name = nameValue;
                }
                return name;
            },
            getAge:function(ageValue){
                age = ageValue;
                return age;
            }
        }
    }

    var func = foo();

    console.log(func.getName());     //
    console.log(func.getName("卡罗尔"));
    console.log(func.getName());
</script>
<script>
    function foo(){
        var name = "卡罗";
        var age = 18;
        return {
            getName:function(){
                return name;
            },
            getAge:function(){
                return age;
            },
            setName:function(nameValue){
                name = nameValue;
            },
            setAge:function(ageValue) {
                age = ageValue;
            }
        }
    }

    var func = foo();
    console.log(func.getName());
    func.setName("卡米尔");
    console.log(func.getName());

    func.setAge(20);
    console.log(func.getAge());
</script>

闭包的作用

提供了一种间接访问函数封闭空间中数据的方法

<script>
    function f1(){
        var age = 20;
        var author= "今何在";

        return {
            getAge:function(){
                return age;
            },
            setAge:function(ageValue){

                //校验处理
                if (ageValue <0)
                {
                    ageValue = 0;
                }

                //其他的处理(异常检测)
                age = ageValue;
            }
        }
    }

    var func = f1();
    func.setAge(22);
    console.log(func.getAge());

    //设置年龄  -3 (因为人的年龄不能是负值 所以得进行安全校验)
    func.setAge(-3);
    console.log(func.getAge());
</script>

setTimeout和闭包的执行

setTimeout(); 只调用一次函数(延迟函数) 一次是隔两秒(至少)

每隔一定的时候就调用一次

setTimeout的问题

<script>
    for (var i = 0; i < 100; i++) {

        setTimeout(function () {
            console.log(i);
        },0);

        console.log("----");
    }
</script>

解决setTimeout的问题

<script>
    for (var i = 0; i < 10; i++) {

        setTimeout((function (j) {

            return function () {
                console.log(j);
            }
        })(i),10);

        console.log("+++++++++");
    }
</script>

div事件和闭包

<div>我是第1个div标签</div>
<div>我是第2个div标签</div>
<div>我是第3个div标签</div>
<div>我是第4个div标签</div>
<div>我是第5个div标签</div>
<div>我是第6个div标签</div>
<script>
var divs  = document.getElementsByTagName("div");
for (var i = 0; i < divs.length; i++) {
        divs[i].onclick = function(){
            alert("我是第" + i + "标签");
        }
    }
    // 每次点击得到的都是第六个标签
</script>
<script>
    var divs  = document.getElementsByTagName("div");
    for (var i = 0; i < divs.length; i++) {
       (function(a){
           divs[a].onclick = function(){
               alert("我是第" + a + "标签");
           }
       })(i)
   }
</script>

函数的特性

函数的约定和name值

<script>

    //function funName(参数1,参数2){函数体}   //函数声明

    //函数表达式(匿名)
    var add = function(a,b){
        console.log(a + b);
    }

    //函数表达式(命名)
    var sum = function name(a,b){
        console.log(a + b);
    }

    //sum.length // 形参的个数
    console.log(add.name);   //add 跟浏览器的实现有关系(在火狐中name的值为空)
    console.log(sum.name);   //name

    //03构造函数创建对象
    new Function(参数1,参数2,参数3)
</script>

函数的回调(作为参数传递)

函数是第一型对象(因此可以使用对象的地方都可以使用函数)

回调函数(回调),当我们把某个函数作为参数传递给另一个函数的时候,这个函数就称为回调函数。

回调函数的基本模式

<script>
    function func(callBack) {

        //处理其他的操作
        callBack();     //调用回调函数
    }

    function demo() {
        console.log("这是一个回调函数");
    }

    func(demo); //注意调用函数的时候,参数是回调函数的引用(不要加括号);
</script>

回调函数(关于this丢失的问题)

<script>
    //如果回调函数是某个对象的方法,而该对象方法中使用了this指针
    //那么该方法作为回调函数来使用的时候,需要注意this丢失的问题

    //01 提供一个对象,该对象中永远有showName方法
    var obj = {
        name:"xxx名字",
        age:30,
        showName:function () {
            console.log(this.name);
        },
        showAge:function () {
            console.log(this.age);
        }
    }


    //02 提供一个函数,该函数接受一个参数(函数引用)
    function demo(callBack) {
        callBack();
    }

    demo(obj.showName); //注意:不要带上括号 打印结果为空(window.name)
    demo(obj.showAge);  //undefined
</script>

回调函数(解决this丢失的问题)

<script>
    //01 提供一个对象,该对象中永远showName方法
    var obj = {
        name:"默认的名字",
        age:30,
        showName:function () {
            console.log(this.name);
        },
        showAge:function () {
            console.log(this.age);
        }
    };

    //02 提供一个函数,该函数接受一个参数(函数引用)
    function demo(callBack,callBack_obj) {
        if (typeof callBack == 'function')
        {
            callBack.call(callBack_obj);
            console.log("++++");
        }
    }

    demo(obj.showName,obj); //注意:不要带上括号
    demo(obj.showAge,obj);  //undefined

</script>

回调函数(兼容字符串方式)

<script>
    //01 提供一个对象,该对象中永远showName方法
    var obj = {
        name:"默认的名字",
        age:30,
        showName:function () {
            console.log(this.name);
        },
        showAge:function () {
            console.log(this.age);
        }
    };

    //02 提供一个函数,该函数接受一个参数(函数引用)
    function demo(callBack,callBack_obj) {

        //处理第一个参数传递对象方法字符串的形式
        if(typeof callBack == 'string')
        {
            callBack = callBack_obj[callBack];
        }

        if (typeof callBack == 'function')
        {
            callBack.call(callBack_obj);
        }


    }

    //demo(obj.showName,obj);
    //demo(obj.showAge,obj);

    //传递字符串和对象来进行调用
    demo("showName",obj);
</script>

函数作为返回值( 计算器)

<script>

    //使用闭包实现一个计数器(在该示例中setup函数的返回值为一个函数)
    //通过调用返回值(一个函数),可以操作setup函数中的变量

    var setup = function () {
        var count = 0;
        return function () {
            return count ++;
        }
    }

    var next = setup();
    console.log(next());    //0
    console.log(next());    //1
    console.log(next());    //2
</script>

自定义函数( 惰性函数 )

惰性函数

应用场景

特点

缺点:

<script>
    var demo = function foo() {
        console.log("foo!");
        foo = function () {
            console.log("new foo!");
        }
    }

    //函数的调用
    //foo();  //foo!
    //foo();  //new foo!

    //总结:该函数的实现特点在于能够更新自身的实现。
    demo(); //foo!
    demo(); //foo!
</script>

惰性定义函数存在的问题

<script>
    //01 声明函数foo
    function foo() {
        console.log("foo!");
        foo = function () {
            console.log("foo! foo!");
        }
    }

    //02 为foo函数对象添加属性
    foo.description = "foo函数的描述信息";

    //03 把foo函数赋值给其他的变量
    var func = foo;

    //04 把foo函数赋值给对象中的方法
    var obj = {
        showFoo:foo
    }

    //05 验证并演示输出
    func(); //foo!
    func(); //foo!
    console.log(func.description);  //foo函数的描述信息
    //总结:01 如果把函数赋值给其他的变量,那么在以其他变量的方式调用时不会更新自身,还是执行旧的函数体

    obj.showFoo();  //foo!
    obj.showFoo();  //foo!
    console.log(obj.showFoo.description);   //foo函数的描述信息
    //总结:02 如果把函数赋值给对象的方法,那么在以对象方法形式调用时不会更新自身,还是会执行旧的函数体。

    foo();  //已经更新过foo函数 foo! foo!
    foo();  //已经更新过foo函数 foo! foo!
    console.log(foo.description);   //undefined
</script>

即时函数

在函数定义之后立即执行该函数。

即时函数模式的组成:

即时函数的作用

即时函数的优点

<script>
    //第一种写法
    (function () {
       console.log("即时函数的第一种写法");
    }());

    //第二种写法
    (function () {
        console.log("即时函数的第二种写法");
    })();
</script>
<script>
    //01 接受参数
    (function (str) {
        console.log(str);           //hello
    })("hello");

    //02 提供返回值并赋值给新的变量
    var foo = (function () {
        return 2 + 1;
    })();

    console.log(foo);           //3
</script>

即时函数和闭包

即时对象初始化

结构特征

基本结构

({}).init();

模式优点

<script>
    ({
        name:"xxx",
        age:23,
        getDescript:function () {
            console.log("名字:" + this.name + "年龄:" + this.age);
        },

        //注意:在对象中访问对象的属性和方法都需要使用this.前缀
        init:function () {
            this.getDescript();
            //其他的初始化处理
        }
    }).init();
上一篇下一篇

猜你喜欢

热点阅读