zoukankan      html  css  js  c++  java
  • 了解闭包

    江湖上都说要了解闭包,得先了解作用域链,所以,先从作用域链开始吧。

    作用域链

    1. 作用域链是一个对象列表或链表,这组对象定义了这段代码“作用域”中的变量;
    2. 每当调用一个函数,这个函数会创建一个新的对象来储存它的变量(变量绑定对象),并且将这个对象添加到作用域链上;当函数返回时,就从作用域链中将这个对象删除;
    3. 当javascript需要查找一个变量时,它会沿着作用域链一级一级地搜索变量。搜索过程始终从作用域链的前端开始,然后逐级地向后回溯,直至作用域链的最顶层(全局对象)为止。
    4. 对于嵌套函数,每个嵌套的函数都各自对应一个作用域链,并且这个作用域链都指向一个变量绑定对象

    我们来看一个栗子

    var word = " the window"
    function sayWord(){
    	var word = "sayWord"
    	 function sayHello(){
    		var word = "sayHello"
    		alert(word)
    	}
    	return sayHello
    }
    sayWord()();
    

    上例的作用域链就是:
    sayHello[word="sayHello"]——sayWord[word="sayWord"]——window[word="the window"];
    当执行sayHello函数时,会沿着这个作用域链一级一级往上找word这个变量,直到找到为止。

    闭包

    javacript高级程序设计上说“有不少开发人员总是搞不清匿名函数和闭包这两个概念”。很遗憾,本人就是。

    [@javacript高级程序设计](javascript:void(0))

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

    @xiaotie

    闭包是从用户角度考虑的一种设计概念,它基于对上下文的分析,把龌龊的事情、复杂的事情和外部环境交互的事情都自己做了,留给用户一个很自然的接口。

    [@javacript权威指南](javascript:void(0))

    函数对象通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内


    上栗子

    var word = " the window"
    function sayWord(){
    	var word = "sayWord"
    	 function sayHello(){
    		alert(word)
    	}
    	return sayHello
    }
    sayWord()();
    

    sayHello函数在sayWord函数内部,它能访问sayWord函数内部的变量。sayHello函数就是闭包,

    利用闭包实现私有属性

    function createCounter() {
      var counter = 0;
      function increment() {
        counter = counter + 1;
        console.log("Number of events: " + counter);
      }
      return increment;
    }
    
    var counter1 = createCounter();
    var counter2 = createCounter();
    
    counter1(); // Number of events: 1
    counter1(); // Number of events: 2
    
    counter2(); // Number of events: 1
     
    counter1(); // Number of events: 3
    
    

    每次调用函数都会创建变量绑定对象添加到作用域链中,所以每次调用外部函数的时候,作用域链都是不同的。而对于嵌套函数,每次调用外部函数时,内部函数又会重新定义一遍。

    闭包存在的问题

    this对象的指向问题

    var name = "The Window";
    var object = {
    	name : "My Object",
    	getNameFunc : function(){
    		var name = "The v";
    		return function(){
    			return this.name;
    		};
    	}
    };
    alert(object.getNameFunc()()); //"The Window"(在非严格模式下)
    

    每个函数在被调用时都会自动取得两个特殊变量:thisarguments。内部函数在搜索这两个变量时,只会搜索到其活动对象为止,因此永远不可能直接访问外部函数中的这两个变量。

    这里

    object.getNameFunc()()==(function(){return this.name;})()

    所以其活动对象为window;

    解决办法

    var name = "The Window";
    var object = {
    	name : "My Object",
    	getNameFunc : function(){
    		var that = this;
    		return function(){
    			return that.name;
    		};
    	}
    };
    alert(object.getNameFunc()()); //"My Object"
    

    内存泄露问题

    function sayWord(){
    	var word = "hello"
    	add = function(){
    		word = word + " world"
    	}
    	function sayHello(){
    		alert(word)
    	}
    	return sayHello;
    	word = null;
    }
    var say = sayWord();
    say();  //hello
    add();
    say();	//hello world
    
    • 首先调用say();结果输出hello
    • 然后调用add,add是个全局变量,所以可以在外部调用,因为它又是闭包,所以可以访问到变量word,所以world=“hello world”;
    • 最后再调用say();发现结果输出hello world;
      这说明函数sayWord中的局部变量word一直保存在内存中,并没有在sayWord调用后被自动清除。产生这个问题主要是由于匿名函数保存了一个对word的引用,所以它所占用的内存就永远不会被回收。

    注意:因为闭包的这个特性,所以外部函数的变量是其内部所有闭包的共享值,因此,不能在闭包中随意的改变外部函数的变量值,牵一发而动全身。

    如果觉得本文不错的话,帮忙点击下面的推荐哦
    >>>>点击阅读原文

  • 相关阅读:
    SQL Server用户和角色
    小草手把手教你 LabVIEW 串口仪器控制——VISA 串口配置
    数据库的概念
    域对象
    session
    cookie
    表单
    HttpServletResponse
    JavaWeb核心之Servlet
    Tomcat服务器
  • 原文地址:https://www.cnblogs.com/yzg1/p/5067432.html
Copyright © 2011-2022 走看看