精华内容
下载资源
问答
  • JavaScript 闭包 原理

    2018-11-13 13:59:07
    闭包 引用代码片段 //var i=1;//污染全局 function fun(){ var i=1; //函数内变量 ao释放 console.log(i++); } fun();//1 fun();//1 //i=0; 全局污染之后变量 会被影响 fun();//1 fun();//1 运行结果是 1 ...

    闭包 引用代码片段

    //var i=1;//污染全局  
    function fun(){
    	  var i=1;  //函数内变量  ao释放
    	  console.log(i++);
    	}
    fun();//1
    fun();//1
    //i=0;  全局污染之后变量 会被影响
    fun();//1
    fun();//1

    运行结果是  1 1 1 1

    模仿一个场景  我们想要使用  变量 i 中的值  让其自动累加

    让而 又不想让 var  i  放入全局   污染全局变量   

    解决方案   

     闭包     解决 

    1.  用外层函数包裹内层函数对象
    2.  外层函数将内层函数对象返回到外部
    3.  使用者调用外层函数, 获得返回的内层函数
    // 用外层函数包裹 变量和内层函数
    function outer(){ 
    	var i=1;  //外层函数内将内层函数对象返回
     return function (){
    	 console.log(i++);
    	}
    }
    fun();//1
    fun();//2
      i=0;  //全局变量修改不了 闭包中的变量
    fun();//3
    fun();//4

    运行结果为1 2 3 4 

     

    下面给大家演示一下 闭包案例

    <!doctype html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>Document</title>
    </head>
    <body>
    <button>click me</button>
    <button>click me</button>
    <button>click me</button>
    <button>click me</button>
    <button>click me</button>
    <button>click me</button>
    <button>click me</button>
    <button>click me</button>
    <script>
    var btns= document.getElementsByTagName("button");
    //获取到当前 按钮的 选择器 
    for(var i=0;i<btns.length;i++){//遍历当前按钮
    	btns[i].onclick=(function(){
    	//为按钮绑定点击事件  将函数封装 ({fun() })();
    		var myi=i;
    	//闭包获取当前的i  不被全局或者因函数内ao释放而释放
    		return function(){  alert("我是当前第"+myi+"个按钮"); }
    	})();
    }
    </script>
    </body>
    </html>

     

     

    展开全文
  • js中闭包原理谈和原型及例子

    千次阅读 2015-12-07 17:47:11
    闭包是一个比较抽象的概念,但是他也是js能力提升无法绕过的一环,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的理解以及js内部解释器的运作方式的描述,都是可以看出你js实际水平的.即使你没...

      闭包是一个比较抽象的概念,但是他也是js能力提升中无法绕过的一环,几乎每次面试必问的问题,因为在回答的时候.你的答案的深度,对术语的理解以及js内部解释器的运作方式的描述,都是可以看出你js实际水平的.即使你没答对,也能让考官对你的水平有个评估.那么我先来说说我对js中的闭包的理解.

      闭包是很多语言都具备的特性,在js中,闭包主要涉及js几个其他的特性:作用域链,垃圾(内存)回收机制,函数嵌套,等等.

    在理解闭包以前.最好能先理解一下作用域链的含义,简单来说,作用域链就是函数在定义的时候创建的,用于寻找使用到的变量的值的一个索引,而他内部的规则是,把函数自身的本地变量放在最前面,把自身的父级函数中的变量放在其次,把再高一级函数中的变量放在更后面,以此类推直至全局对象为止.当函数中需要查询一个变量的值的时候,js解释器会去作用域链去查找,从最前面的本地变量中先找,如果没有找到对应的变量,则到下一级的链上找,一旦找到了变量,则不再继续.如果找到最后也没找到需要的变量,则解释器返回undefined.

      了解了作用域链,我们再来看看js的内存回收机制,一般来说,一个函数在执行开始的时候,会给其中定义的变量划分内存空间保存,以备后面的语句所用,等到函数执行完毕返回了,这些变量就被认为是无用的了.对应的内存空间也就被回收了.下次再执行此函数的时候,所有的变量又回到最初的状态,重新赋值使用.但是如果这个函数内部又嵌套了另一个函数,而这个函数是有可能在外部被调用到的.并且这个内部函数又使用了外部函数的某些变量的话.这种内存回收机制就会出现问题.如果在外部函数返回后,又直接调用了内部函数,那么内部函数就无法读取到他所需要的外部函数中变量的值了.所以js解释器在遇到函数定义的时候,会自动把函数和他可能使用的变量(包括本地变量和父级和祖先级函数的变量(自由变量))一起保存起来.也就是构建一个闭包,这些变量将不会被内存回收器所回收,只有当内部的函数不可能被调用以后(例如被删除了,或者没有了指针),才会销毁这个闭包,而没有任何一个闭包引用的变量才会被下一次内存回收启动时所回收.

    也就是说,有了闭包,嵌套的函数结构才可以运作,这也是符合我们的预期的.然后,闭包还有一些特性,却往往让程序员觉得很难理解.看看下面一段代码.

    var result=[];
    function foo(){
    var i= 0;
    for (;i<3;i=i+1){ 
    result[i]=function(){ 
    alert(i) 
    } 
    }
    }; 
    foo();
    result[0](); // 3
    result[1](); // 3
    result[2](); // 3
    

    这段代码中,程序员希望foo函数中的变量i被内部循环的函数使用,并且能分别获得他们的索引,而实际上,只能获得该变量最后保留的值,也就是说.闭包中所记录的自由变量,只是对这个变量的一个引用,而非变量的值,当这个变量被改变了,闭包里获取到的变量值,也会被改变.

    解决的方法之一,是让内部函数在循环创建的时候立即执行,并且捕捉当前的索引值,然后记录在自己的一个本地变量里.然后利用返回函数的方法,重写内部函数,让下一次调用的时候,返回本地变量的值,改进后的代码:

    var result=[];
    function foo(){
        var i= 0;
        for (;i<3;i=i+1){
            result[i]=(function(j){
                return function(){
                    alert(j);
                };
            })(i);
        }
    };
    foo();
    result[0](); // 0
    result[1](); // 1
    result[2](); // 2
    

    在这里我再解释一下.这里用到了另外2个技术,立即调用的匿名函数和返回函数.也是初学者比较难以理解的部分.


    我们所熟知的主流语言,像C,java等,在函数内部只要执行了return,函数就会返回结果,然后内存中删除该函数所在的区域.生命周期也就停止了.一般的js函数也是这样.
    但是有闭包特性的js函数有点特殊.
    就例子来说:
    function a(){
          var i=0;
          function b(){
            alert(++i);
          }
          return b; //返回b函数本身内容,不能写成return b()这样直接执行了
        }
        var c = a();
        c();
    

    这是个标准的闭包,这段代码有两个特点:
      1、函数b嵌套在函数a内部;
      2、函数a返回函数b。
    var c = a();
    c();
    这两句执行很重要
    这样在执行完var c=a()后,变量c实际上是指向了函数b,再执行c()后就会弹出一个窗口显示i的值(第一次为1)。所有的生命周期按理论来说就算全部结束. 第一次c()后,a中的i依然保留.自然a在内存的栈区依然保留.a是return过了,但是,a及内部值却依然存在,这就是闭包.

    这段代码就创建了一个闭包,为什么?因为函数a外的变量c引用了函数a内的函数b,就是说:

    当函数a的内部函数b被函数a外的一个变量引用的时候,就创建了一个闭包。

    总结下,

    1,闭包外层是个函数.
    2,闭包内部都有函数.
    3,闭包会return内部函数.
    4,闭包返回的函数内部不能有return.(因为这样就真的结束了)
    5,执行闭包后,闭包内部变量会存在,而闭包内部函数的内部变量不会存在.

    再来案例

    案例一:function aa(){
    	var b=10;
    	return function cc(){                        
    		b++;
    		alert(b);
    		}
    	}
    aa()();
    
    这个函数调用时,aa()(),有两个括号,第一个是调用aa函数,第二个是执行cc函数。
    function test(){
          return function(){alert("不做死就不会死!")}
    }
    test()();
    

    第一个括号 执行test函数 返回子函数,第二个括号执行test返回的函数

    为什么后面还要加一个括号,以前我直接test()这样调用,但是没有弹出结果,也没有报错。

    后来在网友的提示下:再加一个括号,就可以了,注意直接test() 它返回的是子函数的内容,并没有调用子函数,不信你可以输出一下:

    alert(test()) ,结果: ,再加上括号,就调用了

    如果觉得很难理解,你可以把它想象返回的不是一个函数,而是一个字符串,

    比如:function test(){

          return alert("a+b");

        

    test();  结果:

    还有子函数里为什么要写return,?这是因为要在父函数外部调用。看下面这段代码;

     

    如果不想用两个括号调用,有两种方式。一是定义一个变量接收子函数返回的值,再执行变量所在的函数,二是子函数直接在里面就调用。

    还是拿案例一来说:

    可以改成第一种方式。

     function aa(){
    	var b=10;
    	return function cc(){                        
    		b++;
    		alert(b);
    		}
    	}
    var dd=aa();
    dd();  
    
    二: function aa(){
    	var b=10;
    	(function cc(){                        
    		b++;
    		alert(b);
    		})();
    	}
    alert(aa());
    结果:11,undefined  
    

    为什么第二个会弹出undefined,因为:如果一个函数没有返回值,则会留下一个undefined

    注意如果内部函数在里面执行,那么前面就不要写return, 如:return (functioncc(){ b++; alert(b); })();  此时return在里面没有意义,因为没有返回值 ,就不要写return,就像java 不会写returnvoid一样。函数运行就是个闭包,如果里面的子函数不在里面执行,就要加上return ,然后在父函数外面调用返回的子函数。

    下面这个问题,点击第个li,得到其索引。

    问题:里面子函数并没有执行,为什么也能弹出结果?

    代码如下:

    window.οnlοad=function(){
    	var li=document.getElementsByTagName("li");
    	for(var i=0;i<li.length;i++){
    	     li[i].οnclick=(function(n){
    			 return  function(){
                    alert(n);	 	 
    			 } 
    		  })(i);
    		}
    	}
     <ul>
       <li>1</li>
       <li>2</li>
       <li>3</li>
       <li>4</li>
       <li>5</li>
     </ul>
    

    像上面那些写法都是要么在里面加上括号,直接调用,要么在父函数外面执行。而这里却没有?

    解释:上面的内部的函数被绑定到事件上了
    父函数运行,然后把里面的函数返回了,然后返回给绑定的事件上

    这时代码就变成这样:

     li[i].οnclick=	function(){
                    alert(n);	 	 
    			 } 
    

    这是我们常用的写法,很明显,这样就运行了子函数,就会弹出结果。这个闭包还有第二种写法:

    window.οnlοad=function(){
    	var li=document.getElementsByTagName("li");
    	for(var i=0;i<li.length;i++){
    	     (function(n){
    			 li[i].οnclick=function(){
    				 alert(n);
    			}
    			 
    			 })(i);
    		}
    	}
    

    因为要用到循环里的变量,所以用一个闭包把下面的代码包起来,并传给一个形参n,调用时传实参i,这个i就是for循环里的i。

    有一种格式颇受争议:

    (function(a,b))(a,b);
    如果你使用过jquery,并且观察过他的代码,你就会很奇怪他的写法,网上有人也把这种格式叫做闭包

    闭包有许多有趣的用途,Javascript的两个特征使它这么有趣:1. function是一个对象,它跟数组,Object一样,地位平等。2. Javascript变量作用域范围。《Javascript权威指南》对这两点有深入的讲解。

    闭包有一个著名的用途就是实现面向对象的访问控制。也就是c++, c#, java等面向对象的private, public访问控制。先看一段示例代码 

    <script type="text/javascript">
    function ClassA(){
    	var a = 4;
    	this.get_a = function(){
    		return a;
    	};
    	this.set_a = function(value){
    		a = value;
    	};
    }
    
    var v = new ClassA();
    document.write(v.get_a()+"<br />"); //显示4
    v.set_a(1);
    document.write(v.get_a()+"<br />"); //显示1
    alert(v.a); //显示undefined
    </script>
    
    上面的代码很简单,只是把数据成员a的访问器(setter/ getter),放在了构造函数中。a使用var声明,外面不能直接访问a。get_a和set_a都用this来使得这两个函数与类对象关联,并且外面可见。

    上面的方法很有技巧,但我从没有这样做过,微软的AJAX.NET也没有利用闭包来实现访问控制。原因是它要占用更多的内存,下面说说它为什么要占用更多的内存。

    首先,我们使用原型(prototype)来定义一个类 

    	<script type="text/javascript">
    function ClassA(){
    }
    ClassA.prototype = {
    	fun1: function(){
    		document.write("prototype fun1 <br /><br />");
    	}
    }
    
    var a = new ClassA();
    var b = new ClassA();
    a.fun1(); //prototype fun1
    b.fun1(); //prototype fun1
    ClassA.prototype.fun1 = function(){
    	document.write("modify function<br /><br />");
    }
    a.fun1(); //modify function
    b.fun1(); //modify function
    a.fun1 = function(){
    	document.write("modify a's method<br /><br />");
    }
    a.fun1();
    b.fun1();
    </script>
    

    从上面的运行结果可以看出,使用prototype定义的类,实例化出来的对象都共享同一个方法,一旦原型改变了,会影响全部对象。而一个对象修改了自身的方法,系统会执行copy on write,把对象指向新的方法而不会影响其他对象。

    再看看以下这一段:

    <script type="text/javascript">
    function ClassA(){
    	this.fun1 = function(){
    		document.write("object function <br />");
    	};
    <span style="white-space:pre">	</span>}
    var a = new ClassA();
    var b = new ClassA();
    a.fun1();
    b.fun1();
    ClassA.prototype.fun1 = function(){
    	document.write("modify object function <br />");
    }
    a.fun1();
    b.fun1();
    a.fun1 = function(){
    	document.write("modify a's function <br />");
    }
    a.fun1();
    b.fun1();
    </script>
    

    从运行结果可以看到,闭包的结果是每个对象都拥有独立的方法,即使对象之间的方法的实现一模一样。这样会造成多余的内存浪费。 

    展开全文
  • 这说明了,JavaScript中闭包是包含了上下文的函数,也就是说,这个函数的作用基础,是它所处的环境,这是不能超越的,跟线性代数是不是有一点似曾相识的感觉呢? 换个角度看,闭包的作用是为了实现OO。JavaScript...
  • JS闭包原理

    2021-03-30 17:46:16
    JS闭包原理

    JS闭包原理

    什么是必包

    有权访问另一个函数作用域中的变量的函数;一般情况就是在一个函数中包含另一个函数。

    好像必包挺简单的,但是注意必包是有超能力的
    慢慢品味“有权访问另一个函数作用域中的变量”,那要是没有必包是不是就不能访问函数作用域中的变量了呢,终于意识到了吧。函数作用域是独立的、封闭的,外部的执行环境是访问不了的,但是闭包具有这个能力和权限。

    function person () {
    	var fruit = "鱼"
    	function say () {
    		console.log("我想吃" + fruit)
    	}
    	say()
    }
    var personSay = person();
    console.log(personSay()) // 我想吃鱼
    console.log(personSay()) // 我想吃鱼
    console.log(personSay()) // 我想吃鱼
    

    性能考量

    如果不是特殊情况要求使用必包,否则必包必须少用,因为使用必包会造成额外的资源和性能损耗。

    例如:创建新的对象或者类时,方法通常关联与对象的原型,而不是定义到对象的构造器中。原因是这将导致每次构造器被调用时,方法都会被重新赋值一次(也就是说,对于每个对象的创建,方法都会被重新赋值)

    考虑以下例子

    function MyObject(name, message) {
      this.name = name.toString();
      this.message = message.toString();
      this.getName = function() {
        return this.name;
      };
    
      this.getMessage = function() {
        return this.message;
      };
    }
    

    在上面的代码中,我们并没有利用到闭包的好处,因此可以避免使用闭包。修改成如下:

    function MyObject(name, message) {
      this.name = name.toString();
      this.message = message.toString();
    }
    MyObject.prototype = {
      getName: function() {
        return this.name;
      },
      getMessage: function() {
        return this.message;
      }
    };
    

    但我们不建议重新定义原型(应避免,因为有可能会把原型上的其它属性/方法给删了)。可改成如下例子:

    function MyObject(name, message) {
      this.name = name.toString();
      this.message = message.toString();
    }
    MyObject.prototype.getName = function() {
      return this.name;
    };
    MyObject.prototype.getMessage = function() {
      return this.message;
    };
    
    展开全文
  • Js中闭包原理

    2020-09-14 15:36:28
    Js中闭包原理 要了解清楚js中的闭包制机,那么得先了解全局执行环境、块级执行环境、函数执行环境、变量对象、环境栈、作用域链、摧毁执行环境。 全局执行环境 全局执行环境指的是最外层的执行环境。在web...

    Js中的闭包原理

    要了解清楚js中的闭包制机,那么得先了解全局执行环境、块级执行环境、函数执行环境、变量对象、环境栈、作用域链、摧毁执行环境。

     

    全局执行环境

    全局执行环境指的是最外层的执行环境。在web中全局执行环境被认为window对象,所以你在全局环境中创建的变量与函数都是对象的属性和方法。

     

    函数执行环境

    函数执行环境指的是函数体。

     

    块级执行环境

    块级执行环境指的是块级定义区域。

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    'use strict';

    // 全局执行环境

    // .....

    {

        // 块级执行环境

        // 代码 ....

    }

     

    function func() {

       // 函数执行环境

       //...

    }

     

     

    变量对象

    每一个执行环境最有一个与之关联的变量对象,变量对象中存储当前环境中定义的变量与函数。在使用变量或函数时,都是在个变量对象上去寻找成员的。这个对象是无法访问的,但是你可以在作用域链[scope]中查看到所定义的成员(如果没有使用的话可能无法看到,这和优化有关)。

     

    环境栈

    每个函数或块都有自己的执行环境。当执行流进入一个函数时,函数的环境就会被推入“环境栈”中。函数执行完后,栈将其弹出并销毁变量对象,然后把控制权返回在给之前的执行环境。如果内执行环境的变量对象,被外部执行环境引用,那么内部环境变量对象就无法被销毁(如:闭包)。

     

     

    作用域链

    作用域链是一个列表,存储着与执行环境相关的变量对象,通过【scope】属性可查看变量对象列表。

     

    关系图

     

     

    实例讲解

    // 例子1:常见的函数嵌套

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    'use strict';

    function a() {

        let x = 2;

        return function() {

            return x;

        }

    }

    let func = a(); // 返回a函数体内的 匿名函数

    console.log(func()); // 在全局执行环境中,访问a函数内部变量。 如果是非闭包函数,那么执行完后

     

    我们来看一下,a函数体内匿名函数的作用域链。

     

    [Scopes] : 是当前匿名函数的作用域链。

    索引为 0 的:是a函数的执行环境的变量对象, x 表示 变量对象中的。

    索引为 1 的:全局执行环境变量对象。

     

    // 例子2:访问块内部变量

    1:返回块级内容函数 实现在全局执行环境中访问块级内容变量。

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    'use strict';

    let func = null;

    {

        let x = "你好";

        func = function () {

            return x;

        }

    }

    // 返回块级内容函数 实现在全局执行环境中访问块级内容变量。

    console.log(func());

     

    作用域链图:

     

     

    展开全文
  • JS闭包原理

    2019-09-26 12:57:40
    什么是js闭包原理,有什么作用? 一、定义:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式,因而这些变量也是该表达式的一部分。 作用:1、可以减少全局变量的对象,防止全局变量过去庞大,导致难以...
  • JavaScript闭包原理与详解

    千次阅读 多人点赞 2016-10-26 18:24:12
    JavaScript的闭包是一个特色,但也是很多新手难以理解的地方,阅读过不少大作,对闭包讲解不一,个人以为,在《JavaScript高级程序设计》一书,解释的最为详尽,结合此书,表述一下我对JavaScript闭包的理解,希望...
  • js闭包原理理解

    千次阅读 2015-11-27 22:59:07
    什么是js(javaScript)的闭包原理,有什么作用? 一、定义 官方解释:闭包是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。 很显然,丫的。。。。...
  • 简述JavaScript中闭包原理

    千次阅读 2018-06-05 09:17:54
    简述JavaScript中闭包原理哟 2018年6月5日 晴 微风 温度 26-36°C JavaScript中的闭包是指一种 相对的空间概念 我们拿我们所处空间来举例: 我们当下所坐在房间里,这个房间就形成了一个封闭的...
  • JavaScript中闭包原理

    2020-05-30 17:15:21
    闭包原理 函数内部的变量函数外部是无法获取的,如果我们要访问函数内部的某个变量或是变量值的话,可以用一个return方法来实现 比如下面这个例子: function hk(){ var a = 10; console.log(a); } hk(); ...
  • 主要介绍了JS闭包原理与应用,结合实例形式较为详细的分析了javascript闭包的原理、应用及相关操作注意事项,需要的朋友可以参考下
  • 下面小编就为大家带来一篇利用js闭包原理做对象封装及调用方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • JavaScript的闭包是一个特色,但也是很多新手难以理解的地方,阅读过不少大作,对闭包讲解不一,个人以为,在《JavaScript高级程序设计》一书,解释的最为详尽,结合此书,表述一下我对JavaScript闭包的理解,希望...
  • 主要介绍了JavaScript闭包原理与用法,结合实例形式详细分析了JavaScript闭包相关概念、原理、用法及操作注意事项,需要的朋友可以参考下
  • JS闭包原理

    2018-11-23 22:17:45
    我们今天的主角:闭包,很多小伙伴都写过关于它的文章,相信大家也读过不少,那些文章到底有没有把JS中这个近似神话的东西讲清楚,说实话,真的有,但为数不多。初衷:让所有看到这篇文章的小伙伴都彻彻底底的理解...
  • 主要介绍了JavaScript闭包原理与用法,结合实例形式分析了javascript闭包的概念、功能、常见问题及相关操作技巧,需要的朋友可以参考下
  • JavaScript闭包原理

    2021-01-10 08:58:47
    闭包原理就是:子函数携带其上级作用域链(父函数的AO)返回到父函数的上级作用域并储存 例子: <script> function father(){ var num = 0; var add1 = function(){ console.log(++num); } ...
  • js-闭包原理

    2015-08-24 18:06:42
     js变量作用域:全局变量和局部变量  函数内部可以读取全局变量  函数外部无法读取函数内部的局部变量  函数内部用var关键字定义的变量为局部变量,否则为全局变量 如何在函数外部读取局部变量? ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,865
精华内容 10,346
关键字:

js中的闭包原理