看透JavaScript:原理、方法与实践
上QQ阅读APP看书,第一时间看更新

7.4 内部函数中的this

我们先来看一个例子。

    var v = 1;
    function Program(){
        var v = 2;
        this.v = 3;
    }
    Program.prototype.logV = function () {
        function innerLog(){
            console.log(this.v);
        }
        innerLog();
    }
    var pro = new Program();
    pro.logV();

大家觉得上述代码会打印出什么呢?可能有的读者觉得很简单,既然是pro对象调用的,当然会打印出pro对象中v的值3。但是,实际上1才是正确答案。在这个例子中,需要注意实际的打印操作并不是在logV方法中执行的,而是在logV中调用它的内部方法innerLog来完成的,因此这里的this应该指向innerLog方法前的对象,而不是logV方法前面的对象,而innerLog方法是直接调用的,前面并没有对象,这种情况下的this就会指向全局对象window,而window的v属性就是全局变量v,所以结果会打印出1。

这时,如果我们想在内部函数中打印出调用外部函数的对象的属性(例如,在innerLog方法中打印出pro对象中的v属性),那么有三种方法可以实现:第一种,在外部方法中将this保存到一个变量然后在内部函数中调用;第二种,在外部方法中将内部方法关联到对象上并使用对象调用内部方法;第三种,将内部方法改为接收参数的方法,并在外部方法中将属性通过变量传入内部方法。例如,上述代码中的logV方法可以这么处理。

方法1:

    Program.prototype.logV = function () {
        var instance = this;
        function innerLog(){
            console.log(instance.v);
        }
        innerLog();
    }

方法2:

    Program.prototype.logV = function () {
        function innerLog(){
            console.log(this.v);
        }
        this.innerLog = innerLog;
        this.innerLog();
    }

方法3:

    Program.prototype.logV = function () {
        function innerLog(v){
            console.log(v);
        }
        innerLog(this.v);
    }

这三种方法都会打印出pro对象的属性v(3)。这里跟我们的原则“谁直接调用方法this就指向谁”并不冲突,只要注意实际处理业务的函数到底是谁调用的就可以了。