jquery的链式操作,和underscope的链式操作

2020-03-04  本文已影响0人  Mr绍君

先说说jquery的链式操作。

jquey的链式操作比较简单,我们只要把jquery对象返回就可以实现链式调用。

写个最简单的版本。

(function(window) {
  jQuery = function(selector) {
    return new jQuery.fn.init(selector);
  }

  jQuery.fn = jQuery.prototype = {
    // 先假装传进来的就是id
    init: function(selector) {
      this.el = document.querySelectorAll(selector)
      return this
    },
    css: function(name, styles) {
      if(styles) {
        this.el.forEach(element => {
          element.style[name] = styles
        });
      }
      return this
    }
  }
  
  // 共享原型对象
  jQuery.fn.init.prototype = jQuery.fn

  window.$ = window.jQuery = jQuery
})(this)

我们可以调用一下。

$("#test").css('color', 'red').css('background', '#ccc')

重点说一下underscope的链式调用,这个设计感觉还是挺别致的。

我们先来看一下版本1

(function(window) {
    var _ = function() {

    }
    _.unique = function(arr, cb) {
      var ret = []
      var target = null
      arr.map(item => {
        target = cb ? cb(item) : item
        if(ret.indexOf(target) === -1) {
          ret.push(target)
        }
      })
      return ret
    }
  
    _.sort = function(arr, cb) {
      return arr.sort(function(x,y) {
        return y-x
      })
    }
  
    window._ = _
  })(this)

我们定义一个函数,然后在函数上添加属性。这样我们就可以通过.unique()这样的方式来进行调用。

但是这样并不能实现链式调用。

我们再来看看第二个版本

(function(window) {
  var _ = function(obj) {
    if (obj instanceof _) return obj;
    if (!(this instanceof _)) return new _(obj);
    this._wrapped = obj;
  }

  var push = Array.prototype.push

  _.unique = function(arr, cb) {
    var ret = []
    var target = null
    arr.map(item => {
      target = cb ? cb(item) : item
      if(ret.indexOf(target) === -1) {
        ret.push(target)
      }
    })
    return ret
  }

  _.sort = function(arr, cb) {
    return arr.sort(function(x,y) {
      return y-x
    })
  }

  // 遍历underscope上的所有方法
  _.functions = function(obj) {
    let names = []
    for (const key in obj) {
      if (toString.call(obj[key]) === '[object Function]') {
        names.push(key)
      }
    }
    return names
  }

  _.each = function(arr, cb) {
    var i=0
    if(_.isArray(arr)) {
      for(;i<arr.length; i++) {
        cb.call(arr, arr[i])
      }
    } else {
      for (const key in arr) {
        cb.call(arr, arr[key])
      }
    }
  }

  _.isArray = function(obj) {
    return toString.call(obj) === '[object Array]';
  }

  _.chain = function(obj) {
    var instance = _(obj);
    instance._chain = true;
    return instance;
  }

  _.prototype.value = function() {
    return this._wrapped
  }

  var chainResult = function(instance, obj) {
    return instance._chain ? _(obj).chain() : obj;
  };

  _.mixin = function(obj) {
    _.each(_.functions(obj), function(name) {
      var func = _[name] = obj[name];
      _.prototype[name] = function() {
        var args = [this._wrapped];
        push.apply(args, arguments);
        return chainResult(this, func.apply(_, args));
      };
    });
  };

  // Add all of the Underscore functions to the wrapper object.
  _.mixin(_);

  window._ = _
})(this)

和第一个版本的差异我们定义了一个mixin函数,并且执行了这个函数。

这个函数的作用是遍历对象上的所有属性方法,并把它绑定到原型对象上。这样我们的就变成了一个类对象。

类对象可以进行链式调用,那么数据怎么传递呢?

除了mixin我们还定义了一个chain函数,想要支持链式调用,先调用一下chain函数。

如果参数是_对象,我们就返回,如果不是,我们就把参数传进构造函数,重新进行设置。

这样每次执行方法,都会去prototype原型对象上找对应的函数,并把结果参数重新设置,保证了数据的传递。

console.log(_([1,1,3,3,2,5,4,5]).chain().unique().sort().value())

// [5, 4, 3, 2, 1]
上一篇下一篇

猜你喜欢

热点阅读