你对this的理解正确吗?有趣又神奇的this对象
2014 年 11 月 14 日
在每个面向对象编程语言中都会涉及到一个指向当前对象的值,this( 当然,python不是的)。但是this本身在很多时候都是有”歧义”的,因为不同的理解容易造成意想不到的bug产生。
比如在jquery中的ajax请求,经常会看到下面的代码:
$('#button').click(function(){ var that = this; $.ajax({ url:'/xxxx/xxxx', 'data':{}, 'success':function(res){ if(res.code == 0) { $(that).hide(); } } }) })
之所以需要在请求之前将this对象赋值给that,是因为在成功回调函数中的”this”并不是之前的”this”了。除了通过一个临时变量that保存之外,还可以使用bind的方式制定this。
相同的,在php中也存在回调函数,匿名类对象,闭包等。这些场景都会导致this的指向内容歧义化。
class TestFoo { public $foo = 'TestFoo'; public function getCallback(){ $currentFoo = $this->foo; return function() use ($currentFoo) { echo 'current '.$currentFoo.',callback '.$this->foo."\n"; }; } } $testFoo = new TestFoo(); $closure = $testFoo->getCallback(); call_user_func_array($closure, []); $context = new \StdClass; $context->foo = "Hello World"; $boundClosure = $closure->bindTo($context); $boundClosure();
上面代码分别是输出
current TestFoo,callback TestFoo current TestFoo,callback Hello World
在php5.4之前的版本,上面的代码其实是会有问题的。必须要写成that的形式
class TestFoo { public $foo = 'TestFoo'; public function getCallback(){ $currentFoo = $this->foo; $that = $this; return function() use ($currentFoo,$that) { echo 'current '.$currentFoo.',callback '.$that->foo."\n"; }; } }
对于匿名类,则会有更加复杂的
class TestFoo { public $foo = 'TestFoo'; protected $logger; public $name = "out"; public function getCallback(){ $currentFoo = $this->foo; $this->testInnerClass(new class { private $name = "innerlogger"; public function log($msg) { echo $this->name.' log '.$msg."\n"; } }); $this->logger->log('test'); return function() use ($currentFoo) { echo 'current '.$currentFoo.',callback '.$this->foo."\n"; }; } public function testInnerClass($log){ $this->logger = $log; } } $testFoo = new TestFoo(); $closure = $testFoo->getCallback(); call_user_func_array($closure, []);
上面代码输出内容是:
innerlogger log test current TestFoo,callback TestFoo
通过上面的分析,相信大家对 this
会有新的认识。在编码过程中,要注意 this
对象的实际指向,避免产生不必要的bug。这种问题,如果产生bug,是很难排查的。