javascript wrapper函数

在设计javascript的继承体系时,有一个重要需求,方法链。通俗地说,说是在方法中调用父类的同名方法。类似java的this.super().method()。如何把父类的同名方法包装到子类中呢?这就要用到wrapper函数。之所以叫wrapper,而不是wrap,因为它比wrap更加wrapper。比如像Ext那种深度继承的结构中,如果父类没有找祖父,祖父没有找曾祖父,沿着原型链层层上溯,以获取它所需要的功能。此外,wrapper函数在jQuery也有应用,好像分为三种wrapAll,wrapinner,wrap,专门用来对付IE的table或其他DOM。可能还有其他用处,不管了,先看如何实现它。

一个普通的函数

 
    var greeting = function(world){
      return "hello " + world +"!";
    };
    alert(greeting("world"));
var greeting = function(world){ return "hello " + world +"!"; }; alert(greeting("world"));

运行代码

我们把它塞进更深一层的作用域,非bind函数。

 
    var wrap= function(fn){
      return function(){
        return fn.apply(null,arguments);
      };
    };
var wrap= function(fn){ return function(){ return fn.apply(null,arguments); }; }; var greeting = function(world){ return "hello " + world +"!"; }; alert(greeting("world")); alert(wrap(greeting)("world"))

运行代码

但这只是延迟了它的执行时间而已。上面函数中的null,也可以换成window。

 
    var wrap= function(fn){
      return function(){
        return fn.apply(window,arguments);
      };
    };
var wrap= function(fn){ return function(){ return fn.apply(window,arguments); }; }; var greeting = function(world){ return "hello " + world +"!"; }; alert(greeting("world")); alert(wrap(greeting)("world"))

运行代码

因为总要人去调用函数的,null没有此能力,就由window上。现在我们就是要在这个位置上做文章,把换成this。如果没有进一步的改进,这里的this还是window的替身。下面就开始复杂了,先分解一下写法,降低阅读难度,就像jQuery那样把它掰成三部分:

 
    var wrapper= function(fn){//这里改一下名。
      var temp =  function(){
        return fn.apply(this,arguments);
      };
      return temp;
    };
 
    //fn为原函数
    //temp为改装了的函数
    //wrapper为包装工厂,只运作一次
    //wrap为改装了的函数的属性,它的参数和wrapper一样为函数,但能运行无数次,
    //把原改装了的函数内置为新增函数的内部函数。
    var wrapper= function(fn){
      var temp =  function(){
        return fn.apply(this,arguments);
      };
      temp.wrap = function(callback){
        var prev = fn;
        fn = function(){
          return callback.apply(prev,arguments);
        };
      };
      return temp;
    };

这样就可以如下神奇效果:

var wrapper= function(fn){ var temp = function(){ return fn.apply(this,arguments); }; temp.wrap = function(callback){ var prev = fn; fn = function(){ return callback.apply(prev,arguments); }; }; return temp; }; var html = function(str){ //原函数数 return "

"+str+"

"; } alert(html("段落")); var p = wrapper(html);//第一次包装 alert(p("段落")) p.wrap(function(str){//第二次包装 return "
"+this(str)+"
"; }); alert(p("段落")); p.wrap(function(str){//第三次包装 return ""+this(str)+""; }); alert(p("段落"));

运行代码

可以看出,this总是为原来的同名函数(p),也就是说,我们可以称之为父方法,这样也super关键字或者相关的代替品也不用了,轻松调用原来覆盖了父类的方法。因此jQuery同学单是用它来处理DOM真是大材小用。Prototype同学就做得不错了,不过代码写得比较艰涩:

 
  wrap: function(wrapper) {
    var __method = this;
    return function() {
      return wrapper.apply(this, [__method.bind(this)].concat($A(arguments)));
    }
  },

它的方法链设计:

 
    for (var i = 0, length = properties.length; i < length; i++) {
      var property = properties[i], value = source[property];
      if (ancestor && Object.isFunction(value) &&
          value.argumentNames().first() == "$super") {
        var method = value;
        value = (function(m) {
          return function() { return ancestor[m].apply(this, arguments) };
        })(property).wrap(method);

        value.valueOf = method.valueOf.bind(method);
        value.toString = method.toString.bind(method);
      }
      this.prototype[property] = value;
    }

相关文档:http://www.prototypejs.org/learn/class-inheritance

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值