独家剖析Javascript原型继续 - 之函数原型和AOP

引子

独家剖析Javascript原型继续已比较周全的剖析了自定义函数范例,JS内置基本类(undefined, null, bool, number, string, symbol)和JS内置对象范例(Error, Date, Function)的design-timeprototype, 以及run-time的__proto__原型链。鉴于函数是JS的一等国民,另辟新篇引见函数的原型及其运用。

JS函数范例的组织

通常情况下定义一个函数:

function add1(a, b) {
    return a + b;
}

console.log(add1(1,2)) //3

经由过程new Function也能组织:

var add2 = new Function('a', 'b', 'return a + b');
console.log(add2(1,2)) //3

两种体式格局到达的目标是一致的。而add1和add2的run-time __proto__都是Function.prototype, 能够看做add1和add2都是透过new Function组织出来的,而function关键子就是挪用new Function组织的方便门路。

add1.__proto__ = Function.prototype //true
add2.__proto__ = Function.prototype //true

函数自身也是对象,它遵照独家剖析Javascript原型继续所形貌的自定义函数范例对象的原型轨则。

//add1 创自于Function范例,是Function的实例
add1.__proto__ //[Function]
add instanceof Function //true

// add1 也继续了object范例的原型
add1.__proto__.__proto__ //{}
add1 instanceof Object //true

// 所以add1 run-time __proto__原型链的顶端同样是null
add1.__proto__.__proto__.__proto__ // null

AOP编程完成

至此我们相识到,透过funtion关键字定义的函数,本质是Fuction范例的实例,和经由过程new Function体式格局组织自身是一样的。所以我们经由过程修正Function的design-time的prototype,来完成面向切面编程(AOP)

值得一提的是:我们(顺序员)平常情况下只引荐修正design-time的prototype,而不去变动run-time的__proto__, 不然修正run-time的__proto__会形成顺序难以保护和浏览,增添不确定的运转毛病。Object.setPrototypeOf能够变动对象实例run-time的__proto__

面向切面编程(AOP,Aspect-Oritented Programming), 简而言之,可理解为函数挪用时,在该函数实行前或/和实行后做一些通用的事情,比方做log,纪录实行时间等。这须要一个代办函数,把原始函数打扮成具有做log等功用的新函数。现实中挪用该代办函数

function foo() {
     console.log('foo runs');
}

foo(); // foo runs

如今我们想在foo函数实行前后离别打印log,而不修正foo函数自身。

Function.prototype.before = function() {
    var _self = this;
    return function() {
        console.log('before foo calls');
        return _self.apply(this, arguments);
    }
}

Function.prototype.after = function() {
    var _self = this;
    return function() {
        var ret = _self.apply(this, arguments);
        console.log('after foo calls');
        return ret;
    }
}

//这里foo就具有了实行前后打印log的功用
foo = foo.before().after();
foo();
// before foo calls
// foo runs
// after foo calls

把打印log的功用提出来,做成更通用的逻辑。

Function.prototype.before = function(beforeFn) {
    var _self = this;
    return function() {
        beforeFn.apply(this, arguments);
        return _self.apply(this, arguments);
    }
}

Function.prototype.after = function(afterFn) {
    var _self = this;
    return function() {
        var ret = _self.apply(this, arguments);
        afterFn.apply(this, arguments);
        return ret;
    }
}

//包装成具有log功用的新的foo函数
foo = foo.before(function() {
    console.log('foo enters')
}).after(function(){
    console.log('foo exits')
});
foo();
// foo enters
// foo runs
// foo exits

由此,可把函数挪用和通用的log能功用挂接(hook)起来了。

    原文作者:杰克船长
    原文地址: https://segmentfault.com/a/1190000010202061
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞