• JavaScript基础笔记(五) 函数表达式


    函数表达式

    一、闭包

    概念:闭包是指有权访问另一个函数作用域中变量的函数。

            function createCompareFun(propertyName) {
                return function (obj1, obj2) {
                    var a = obj1[propertyName];
                    var b = obj2[propertyName];
    
                    if (a < b) {
                        return -1;
                    }
                    if (a > b) {
                        return 1;
                    } else {
                        return 0;
                    }
                }
            }
    
            //创建匿名函数
            var compare = createCompareFun("age");
            //调用该函数
            var result = compare({age:3},{age:8});
            console.log(result); //-1

    如果一个闭包能访问的函数被执行完毕,作用域链(本质上是一个指向变量对象的指针列表)被销毁后,

    其活动对象也不会被销毁,因为它们被闭包引用,知道闭包函数被销毁后,它们才被销毁。

    由于闭包会携带包含它函数的作用域,所以会占用更多内存,建议能不使用闭包就不要使用闭包。

    作用域链的这种配置机制引出了另外一个重要问题:闭包只能取得包含函数中任何一个变量的最后一个值。

            function createFun() {
                var result = new Array();
                for (var i = 0; i < 10; i++) {
                    result[i] = function () {
                        return i;
                    }
                }
                return result;
            };
    
            function getResult(fun, array) {
                for (var j = 0; j < fun.length; j++) {
                    array[j] = fun[j]();
                }
                return array;
            }
    
            var fun = createFun();
            var array = new Array();
            var a = getResult(fun,array);
            console.log(a);  //[ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10 ]

    注意该问题的本质:注意函数实际执行时i变量的值,定义时的值不能说明问题。

    解决办法:

            function createFun() {
                var result = new Array();
                for (var i = 0; i < 10; i++) {
                    result[i] = function (num) {
                        return function () {
                            return num;
                        };
                    }(i);
                }
                return result;
            };
    
    
            /*var b = function rightNow(a) {
                return a;
            }(5);
            console.log(b);*/

    闭包中this的问题:

            var name = "Window";
            var obj = {
                name: "Object",
                getFun: function () {
                    return function () {
                        return this.name;
                    };
                }
            };
            console.log(obj.getFun()()); //Window
            
            //解决:
            var obj2 = {
                name: "Obj2",
                getFun: function () {
                    console.log("Fun's name: "+this.name);
                    var v = this.name;
                    return function () {
                        return v;
                    }
                }
            }
            console.log(obj2.getFun()());
            var name = "Window";
            var obj = {
                name: "Object",
                getFun: function () {
                    return this.name;
                }
            };
    
            var a = obj.getFun;
            console.log(a()); //Window
            console.log(obj.getFun()); //Object

    内存泄漏问题:

            window.onload = function () {
                function outer() {
                    var element = document.getElementById("testId");
                    element.onclick = function () {
                        //闭包的作用域链中保存了一个html元素
                        //只要匿名函数存在,element的引用数最少是1,因此它所占用的内存永远不会被回收。
                        console.log(element.id);
                    };
                }
                outer();
    
                //解决
                function outer2() {
                    var element = document.getElementById("testId");
                    var id = element.id;
                    element.onclick = function () {
                        console.log(id);
                    };
                    //闭包会引用包含函数的整个活动对象,闭包即使不直接引用element,
                    //包含函数的活动对象任然会保存一个引用,所以这步必须有
                    element = null;
                }
            }

    二、模仿块级作用域

    ECMAScript很操蛋地没有块级作用域:

            function Afun() {
                for (var i = 0; i < 10; i++){
                    console.log(i);
                }
                //在外面重新声明i,并没有什么卵用
                var i;
                console.log("Outer i is "+i);
            }
            Afun(); //Outer i is 10
            function Afun() {
                for (var i = 0; i < 10; i++){
                    console.log(i);
                }
                //
                var i = 100;
                console.log("Outer i is "+i);
            }
            Afun(); //Outer i is 100

    可以用匿名函数来模仿块级作用域:

            function Afun() {
                //由于函数声明后不能直接跟员括号来执行它
                //所以我们用()包裹函数声明把它转换一个指向函数的引用
                (function () {
                    for (var i = 0; i < 10; i++){
                        console.log(i);
                    }
                })();
                console.log(i); //导致Error:i is not defined.
            }

    这种技术经常被用来限制在全局作用域中添加过多的变量和函数。

    三、私有变量

    私有变量:函数的参数、局部变量和在函数内部定义的函数。

    共有方法 ==  特权方法

            //在构造函数定义特权方法
            function MyObject() {
                //私有变量
                var v = 10;
                //私有函数
                function f() {
                    return false;
                }
    
                //特权方法
                this.pm = function () {
                    ++v;
                    return v;
                }
            }
    
            var o = new MyObject();
            //除了pm()没有任何途径能访问到真正的o.v
            console.log(o.v);  //undefined
            o.v = 166;
            //假的
            console.log(o.v);  //166
            console.log(o.pm());  //11

    一)静态私有变量

    也可以通过在私有作用域中定义私有变量和函数,创建特权方法。

            (function () {
                var v = 10;
                function f() {
                    return false;
                }
    
                //注意这里没有var,是全局的
                //为了保证全局,也没有使用声明函数
                MyObject = function () {
                };
    
                MyObject.prototype.pm = function () {
                    v++;
                    return f();
                };
            })();
    
            console.log(MyObject);
            console.log(new MyObject().pm()); //false
    Simple is important!
  • 相关阅读:
    [转]mysql视图学习总结
    [转]mysql索引详解
    mysql索引的操作
    [转]mysql的约束
    mysql表的操作
    【转】mysql的数据类型
    java泛型
    java 8新特性
    Dubbo有意思的特性介绍
    dubbo + zookeeper
  • 原文地址:https://www.cnblogs.com/Shadowplay/p/8399759.html
Copyright © 2020-2023  润新知