• 闭包


    闭包的定义:在函数中创建子函数,并且子函数中调用了函数中的变量。称之为闭包

    闭包和普通函数的区别是:
    • 多了一层外部函数的作用域链
    • 普通函数的作用域链为:函数本身的变量 -> 全局变量;而闭包作用域链为:函数本身的变量 -> 父函数的变量-> 全局变量
    • 应尽量少用闭包,因为会增加内存的占用

    标准的闭包实现:

     1 (function () {
     2     function createComparisonFunction(propertyName) {
     3         return function (obj1, obj2) {
     4             var value1 = obj1[propertyName]
     5             var value2 = obj2[propertyName]
     6 
     7             var result = 0
     8             if (value1 > value2) {
     9                 result = 1
    10             }
    11             else if (value1 < value2) {
    12                 result = -1
    13             }
    14 
    15             return result
    16         }
    17     }
    18 
    19     var compare = createComparisonFunction('name')
    20     var obj1 = { name: 'a' }
    21     var obj2 = { neme: 'b' }
    22     console.log(compare(obj1, obj2)) // -1
    23 })();
    闭包与变量
      因为闭包会共享父级作用域链的变量,所以下面demo中的闭包,打印出的index结果都是10
     1 (function () {
     2     function createFunction() {
     3         var arr = []
     4 
     5         for (var index = 0; index < 10; index++) {
     6             arr[index] = function () {
     7                 return index
     8             }
     9         }
    10 
    11         return arr
    12     }
    13 
    14 
    15     var arr = createFunction()
    16 
    17     for (var index = 0; index < arr.length; index++) {
    18         var element = arr[index];
    19         console.log(element()) // 全部都是10
    20     }
    21 })();

    为了解决上面的变量共享问题,我们可以给数组赋值时,增加一个立即执行的闭包。

    思路:因为参数是按值传递的,所以多写一个闭包,并且马上执行,就可以将每个参数都隔离开,达到预期的效果

     1 (function () {
     2     function anotherCreateFunction() {
     3         var arr = []
     4 
     5         for (var index = 0; index < 10; index++) {
     6             arr[index] = (function (num) {
     7                 return function () {
     8                     return num
     9                 }
    10             })(index)
    11         }
    12 
    13         return arr
    14     }
    15 
    16     var arr = anotherCreateFunction()
    17 
    18     for (var index = 0; index < arr.length; index++) {
    19         var element = arr[index];
    20         console.log(element()) // 1~10
    21     }
    22 })();
     
    闭包中的this
      
      默认闭包中的this会指向window
     1 (function () {
     2     var name = 'Cheery'
     3     var thisObject = {
     4         name: 'Colyn',
     5         getNameFunc: function () {
     6             return function () {
     7                 return this.name
     8             }
     9         }
    10     };
    11 
    12     console.log(thisObject.getNameFunc()()) // Cheery
    13 })();
     如果想要在闭包中访问父级函数的作用域,可以通过提前将this的值保存起来,以达到预期效果
     1 (function () {
     2     var name = 'Cheery'
     3     var thisObject = {
     4         name: 'Colyn',
     5         getNameFunc: function () {
     6             var that = this
     7             return function () {
     8                 return that.name
     9             }
    10         }
    11     };
    12 
    13     console.log(thisObject.getNameFunc()()) // Colyn
    14 })();
    闭包的内存泄漏问题
    • IE9之前的javascript和COM对象的回收机制不同
    • 如果闭包的作用域链中保存着一个HTML 元素,那么就意味着该元素将无法被销毁
    下面这个方法,只要匿名函数存在,element的引用数至少是1,因此它所占用的内存就永远不会被回收
    1 (function () {
    2     function assignHandler() {
    3         var element = document.getElementById('someElement')
    4         element.click = function () {
    5             alert(element.id)
    6         }
    7     }
    8 })();
    解决办法
    • 将闭包中要用到的变量提取到父级作用域链中
    • 销毁element
     1 (function () {
     2     function anotherAssignHandler() {
     3         var element = document.getElementById('someElement')
     4         // 重点1
     5         var id = element.id
     6         element.click = function () {
     7             alert(id)
     8         }
     9 
    10         // 重点2
    11         element = null
    12     }
    13 })();
    模仿块级作用域
     
    以下函数的index会存在于整个函数
    1 (function () {
    2     function blockFunction() {
    3         for (var index = 0; index < 10; index++) {
    4 
    5         }
    6 
    7         console.log(index) //10
    8     }
    9 })();

    想要解决变量污染的问题,可以创建一个立即执行的闭包来解决

     1 (function () {
     2     function anotherBlockFunction() {
     3         (function () {
     4             for (var blockIndex = 0; blockIndex < 10; blockIndex++) {
     5 
     6             }
     7         })()
     8 
     9         console.log(blockIndex) //Uncaught ReferenceError: blockIndex is not defined
    10     }
    11 })();
     
    特权方法:指的是有权访问私有变量的共有方法
     
    方式一:每个实例独享变量
     
     1 (function () {
     2     function PrivilegeFunction(name) {
     3         var privateName = name || 'Cheery'
     4 
     5         this.publicSetName = function (name) {
     6             privateName = name
     7         }
     8 
     9 
    10         this.publicGetName = function () {
    11             return privateName
    12         }
    13     }
    14 
    15     var p1 = new PrivilegeFunction
    16     var p2 = new PrivilegeFunction
    17 
    18     console.log(p1.publicGetName()) // Cheery
    19     console.log(p2.publicGetName()) // Cheery
    20 
    21     p1.publicSetName('Colyn')
    22 
    23     console.log(p1.publicGetName()) // Colyn
    24     console.log(p2.publicGetName()) // Cheery
    25 })();
    方式二:实例间共享变量
     1 (function () {
     2     var staticPrivateName
     3 
     4     function StaticPrivilegeFunction(name) {
     5         staticPrivateName = name || 'Cheery'
     6     }
     7 
     8     StaticPrivilegeFunction.prototype.publicSetName = function (name) {
     9         staticPrivateName = name
    10     }
    11 
    12     StaticPrivilegeFunction.prototype.publicGetName = function () {
    13         return staticPrivateName
    14     }
    15 
    16     var p1 = new StaticPrivilegeFunction
    17     var p2 = new StaticPrivilegeFunction
    18 
    19     console.log(p1.publicGetName()) // Cheery
    20     console.log(p2.publicGetName()) // Cheery
    21 
    22     p1.publicSetName('Colyn')
    23 
    24     console.log(p1.publicGetName()) // Colyn
    25     console.log(p2.publicGetName()) // Colyn
    26 })();
  • 相关阅读:
    Asp.Net Winform 条形码系列之Code39 Code39 Of .Net BarCode Serial Blog
    .NET 中文星期几的简单实现方式
    C#使用SQLite数据库(asp.net/winform)
    .Net日期时间格式化输出大全 DateTime.ToString(?)
    C#使用HTTP头检测网络资源是否有效
    [转]C#(VB.NET)操作Windows自带的防火墙 之 添加/删除允许通过防火墙的例外程序
    华为C2800进入工程模式
    android webview 加载网页显示对话框
    SVN 与 VS2003
    VisualSVN1.7.7 序列号
  • 原文地址:https://www.cnblogs.com/ch11ry/p/7501233.html
Copyright © 2020-2023  润新知