深入理解javascript系列(十五):高阶函数

1,442 阅读3分钟

我们都学过javascript的面向对象,在我学习的过程中,一度有个问题困扰着我,那就是在构造函数中,如果使用了this,那么这个this指向的是谁?如果在定义的原型方法中使用了this,那么这个this又指向谁了?是构造函数、原型、还是实例?到底是谁在决定?

function Person(name, age) {
    this.name = name;
    this.age = age;
}
Person.prototype.getName = function() {
    return this.name;
}
var p1 = new Person('pan', 18);
p1.getName();

构造函数其实就是普通的函数,而this是在函数运行时才确定的。那么是什么导致构造函数变得如此特别了?

与new 关键字有关

如果我们自定义一个New方法,来模拟关键字new的能力,那么会有如下实现(在此之前请先回忆一下new 一个函数 会发生什么.,如果您没有想起来,那就记住new一个函数,生成一个实例对象)。

//将构造函数以参数形式传入
function New(func) {
    //声明一个中间对象,该对象为最终返回的实例

    var res = {};
    if(func.prototype !== null) {
        //将实例的原型指向构造函数的原型
        res.__proto__ = func.prototype;
    }

    //ret为构造函数执行的结果,这里通过apply,
    //将构造函数内部的this指向修改为指向res,即为实例对象

    var ret = func.apply(res, Array.prototype.slice.call(arguments,1))

    //当在构造函数中明确指定了返回对象时,那么new的执行结果就是该返回对象
    if((typeof ret === 'object' || typeof ret === 'function') && ret !== null) {
        return ret;
    }

    //如果没有明确指定返回对象,则默认返回res,这个res就是实例对象
    return res;
}

为了方便大家理解,例子中做了一些注解。通过New 方法的实现可以看出,执行时,利用apply设定了传入的构造函数的this指向,因此当使用New方法创建实例时,构造函数中的this就指向了被创建的实例。

如果把当前函数看成基础函数,那么高阶函数,就是让当前函数获得额外能力的函数。如果把构造函数看成基础函数,那么New方法,就是构造函数的高阶函数。构造函数本就和普通函数一样,没有什么区别。但是因为New的存在,它获得了额外的能力。New方法每次执行都会创建一个新的中间对象,并将中间对象的原型指向构造函数的原型,将构造函数的this指向该中间对象。这样统一逻辑的封装,就是高阶函数的运用。

当然,如果简单粗暴一点来理解,则凡是接收一个函数作为参数的函数,就是高阶函数。但是如果这样理解,那么我们还是用不好高阶函数。因为正如阳波大神所说,高阶函数其实是一个高度封装的过程,理解它需要点想象力。那么在接下来的系列中,就借助几个例子,来理解高阶函数的封装。