PHP中闭包的一些常见问题

时间:2025-10-23 09:23:01 php语言 我要投稿

PHP中闭包的一些常见问题

  PHP具有非常强大的功能,所有的CGI的功能PHP都能实现,而且支持几乎所有流行的数据库以及操作系统。最重要的是PHP可以用C、C++进行程序的扩展!以下是小编为大家搜索整理的PHP中闭包的一些常见问题,希望能给大家带来帮助!更多精彩内容请持续关注我们应届毕业生考试网!

  首先说明下...闭包是js高级特性之一...但并非js独有...perl, python, php(5.3以上版本) 都是支持闭包的..

  官方解释: 所谓“闭包”,指的是一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分

  john resig解释: 闭包就是内部函数可以访问外部函数中所定义的变量,即使该函数已经执行结束。

  如果你还是不能明白上面那句话...那么我就换句话来说:

  在js中...执行一个函数A...当函数A执行完后...理论上来讲...改函数A内所有被定义的 临时变量都将被 当成可回收的垃圾等待垃圾回收....然而在这个过程..有一种临时变量是无法被垃圾回收的...当A函数中有一个内部函数a时.a函数内引用了A中定义的临时变量...并且a函数在A函数执行完后..仍然可以被外部访问到时...被a函数所引用的临时变量就无法被当成垃圾等待垃圾回收.. 而a函数可以被外部访问的同时..就生成了一个闭包...

  举个例子吧..也是比较经典的例子

  /pic/p>

  function A(){

  /pic/p>

  var x = 1;

  /pic/p>

  /pic/p>

  return function a(){

  console.log( x );

  };

  }

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  var a = A();

  /pic/p>

  a(); /pic/p>

  闭包并非定义函数时就生成的...而是在执行过程中 当a函数被当成一个返回值被返回时 才会生成一个闭包..

  闭包容易误解的地方:

  1。 闭包总是在匿名函数中生成的

  闭包并非都是在匿名函数中生成的..比如上一段代码中...被返回的函数有命名-a

  2。 闭包在定义时产生的...

  闭包并非是在定义时产生的...而是在内部函数可被外部访问到时才会产生...

  3。 闭包很强大..用的越多就越牛A(==!)

  不否认闭包很强大.....但是并非用的越多就是越好的...使用闭包..会造成调试困难..所以要习惯做标识..另外...使用闭包会涉及到 增长函数作用域的 造成内部函数访问全局变量变慢的问题...

  PHP中的闭包

  php-5.3 以上版本其中一个更新就是使php支持了简单的闭包

  /**

  * 一个curry的加法函数

  * @param unknown_type $start 起始值

  * @return unknown 返回一个匿名函数

  */

  function add( $start = 0 ){

  $sum = $start;

  /pic/p>

  return function () use ( &$sum ){

  /pic/p>

  $args = func_get_args();

  for( $i = 0; $i < count($args); $i++ ){

  $sum += (int)$args[$i];

  }

  return $sum;

  };

  }

  /pic/p>

  $add = add( 1 );

  /pic/p>

  $add( 1, 2, 3 );

  /pic/p>

  echo $add( 3 ); /pic/p>

  ?> 这段代码的作用是 每调用一次add函数都会生成一个相应的$sum 每个函数执行后不冲突 可避免使用static变量 而且sum不会随函数执行结束而消失 从而实现函数柯里化

  闭包的使用

  1. 函数柯里化

  闭包在js中经常会被用过函数柯里化

  比如上面php的那段代码中 改成js则是:

  /pic/p>

  function add( start ){

  var sum = start || 0;

  /pic/p>

  return function(){

  for( var i = 0, j = arguments.length; i < j; i++ ){

  sum += Number( arguments[i] );

  }

  return sum;

  }

  }

  var a = add( 1 );

  a( 1, 2, 3 );

  console.log( a( 3 ) );

  玩个有意思的函数 这个是别人曾经给我出的一道题目 当时我也没想出来...(压根把tostring这方法给忘了.)

  题目需求要求可以这样调用(当时的需求只要求传一个参数)

  /pic/p>

  var a = add( 1 );

  /pic/p>

  a( 1, 2, 3 )( 1, 2, 3 )( 1, 2, 3 );

  /pic/p>

  console.log( a ); /pic/p>

  /pic/p>

  console.log( a( 1, 2, 3 )( 1, 2, 3 ) ); /pic/p>

  实现如下

  /pic/p>

  function add( start ){

  var sum = start || 0;

  /pic/p>

  /pic/p>

  return function(){

  /pic/p>

  for( var i = 0, j = arguments.length; i < j; i++ ){

  sum += Number( arguments[i] );

  }

  /pic/p>

  var func = arguments.callee;

  /pic/p>

  func.toString = function(){

  return sum;

  };

  /pic/p>

  return func;

  }

  }

  2。模拟对象中的私有属性和方法

  写之前先解释下 js非一门OO语言 它是一门基于对象的语言

  如 var i = 0; 则i是一个数值型对象 转成对象写法则是 var i = new Number(1); 前一种叫过直接量表示法 同JSON(js对象字面量,表示js中对象的直接量表示方法) 直接量表示的速度要比 new 快

  (1)模拟私有属性和私有方法

  /pic/p>

  function Smarty(){

  /pic/p>

  /pic/p>

  this.leftLimiter = '{';

  /pic/p>

  this.rightLimiter = '}';

  /pic/p>

  /pic/p>

  var cacheData = {};

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  this.assign = function( name, value ){

  /pic/p>

  cacheData[name] = value;

  }

  /pic/p>

  /pic/p>

  function fetch( tpl ){

  /pic/p>

  return tpl;

  }

  /pic/p>

  this.display = function( tpl ){

  /pic/p>

  console.log( fetch( tpl ) );

  }

  }

  /pic/p>

  var template = new Smarty();

  /pic/p>

  template.leftLimiter = '<{';

  /pic/p>

  template.rightLimiter = '}>';

  /pic/p>

  template.assign( 'name', 'jsyczhanghao' );

  /pic/p>

  template.assign( 'age', 23 );

  /pic/p>

  template.display( document.getElementById( 'test' ).innerHTML );

  (2)模拟私有静态方法(单例模式-Zend framework 模拟前端控制器 phper你懂的..)

  /pic/p>

  /pic/p>

  /pic/pic/p>

  /pic/p>

  var Zend_Controller = function(){

  /pic/p>

  this.setControllerDirectory = function(){};

  /pic/p>

  this.dispatch = function(){

  console.log( 1 );

  };

  };

  /pic/p>

  /pic/p>

  var intance;

  /pic/p>

  var Zend_Controller_Front = function(){};

  /pic/p>

  /pic/p>

  Zend_Controller_Front.getInstance = function(){

  /pic/p>

  /pic/p>

  return instance || ( instance = new Zend_Controller() );

  };

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  window.Zend_Controller_Front = Zend_Controller_Front;

  })( this );

  var zend_instance = Zend_Controller_Front.getInstance();

  zend_instance.setControllerDirectory( '/root' );

  zend_instance.dispatch();

  3。事件回调函数中的使用

  /pic/p>

  /pic/p>

  /pic/p>

  function updateElement( elem, url ){

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  /pic/p>

  $.get( url, function( data ){

  /pic/p>

  elem.innerHTML = data;

  });

  } 以上是闭包绝大部分会出现的场景

  #############################################################################################################

  来看个问题吧:针对 #js的异步机制和大数据量的处理方案# 中的一段代码段

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

  /pic/p>

  document.getElementById( 'test' + i ).onclick = function(){

  /pic/p>

  console.log( i );

  };

  }

  这段代码执行后 点击test0-test9并非象预期那样.. 依次打印出0-9 而是每一个元素点击后都打印了10

  造成的原因就是 绑定click事件时 回调函数并未执行 当回调函数执行时 i已经变成了10 所以打印的结果都会变成10

  解决方法:

  思路: 如果能找到一种方式可以将每一次的i都缓存起来 并且一直到click事件触发的时候 它都一直不会消失 不就完了么

  我们都知道 一个函数作用域内执行完后..作用域中的所有临时变量都会消失 但是有一种不让临时变量消失的方式就是使用闭包。。而上面讲闭包的使用场景时 其中有一条就是事件回调函数 当一个事件回调函数位于一个作用域内的时候...作用域执行外后 由于回调函数并未马上执行..而是等到相应事件触发时才执行...当回调函数依赖该作用域内的临时变量时...导致该作用域内部使用的临时变量无法马上被当垃圾回收(意味着该临时变量不会消失)

  目前我们拥有一个事件回调函数 要做的就是需要让这个事件回调函数位于一个函数作用域内

  代码:

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

  /pic/p>

  function(){

  document.getElementById( 'test' + i ).onclick = function(){

  /pic/p>

  console.log( i );

  };

  };

  }

  这样 事件绑定就位于一个匿名函数中了...但是这样肯定不行...因为函数都没有执行...函数内的代码肯定不会起作用....也就是说..这段代码能够正常执行 不报错..但是不会为每一个元素绑定一个事件..因为它的外部函数没有执行

  继续修改:

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

  /pic/p>

  (function(){

  document.getElementById( 'test' + i ).onclick = function(){

  /pic/p>

  console.log( i );

  };

  })();

  }

  恩 这次看起来差不多了....绑定事件的行为位于一个匿名函数中..并且匿名函数定义后立即执行....

  但是目前 绑定事件内的变量i并不是 匿名函数中所产生的临时变量 i是一个全局变量 i不会因为匿名函数的执行而一直保持 你所希望的值

  所以我们需要在匿名函数内定义一个临时变量 该临时变量的值和当前相应的i值相等即可 将i直接赋值给该临时变量就可以了..

  最终修改代码:

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

  /pic/p>

  (function(){

  var j = i;

  document.getElementById( 'test' + j ).onclick = function(){

  /pic/p>

  console.log( j );

  };

  })();

  }其实不一定要直接赋值 当一个参数传进去也行代码如下(执行结果一样..过程也没什么区别..只是写法不同)for( var i = 0; i < 10; i++ ){

  /pic/p>

  (function( j ){

  document.getElementById( 'test' + j ).onclick = function(){

  /pic/p>

  console.log( j );

  };

  })( i );

  }

  其实还有一种不使用闭包的方式...在事件的回调函数中直接引用 dom对象的一个属性即可 因为dom对象是一直存在的 而指向当前的dom对象使用this即可for( var i = 0; i < 10; i++ ){

  /pic/p>

  var elem = document.getElementById( 'test' + i );

  elem.index = i;

  elem.onclick = function(){

  /pic/p>

  console.log( this.index );

  };

  }

【PHP中闭包的一些常见问题】相关文章:

javascript中js闭包的深入理解09-29

PHP中的Trait11-20

细数PHP程序的一些缺陷08-19

PHP中php://input和$-POST的区别11-07

PHP中list的方法11-17

PHP中的魔术方法03-05

PHP中Json应用03-01

PHP中的Reload操作12-19

PHP中$-SERVER的详解09-09

  • 相关推荐