你对this的理解正确吗?有趣又神奇的this对象

在每个面向对象编程语言中都会涉及到一个指向当前对象的值,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,是很难排查的。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章