【JS特性】解析各大框架的插件系统

2023/02/10 14:18:37

jQuery 对象扩展

如何扩展 jQuery 对象

jQuery 中提供了 $.extend()$.fn.extend() 两个方法来扩展 jQuery 对象。

$.extend() 可以给 $ 对象绑定属性,绑定后可通过 $. 的形式访问:

$.extend({
  getName() {
    console.log("extend name");
  },
});

$.getName();

$.fn.extend() 可以给 jQuery 的原型对象绑定属性,绑定后所有的 jQuery 对象都可以访问:

$.fn.extend({
  getFnName() {
    console.log("fn extend name");
  },
});

$().getFnName();

解析 jQuery 的插件系统

实际上这两个方法其实是一个方法:$.extend === $.fn.extend === function () {}

这里只考虑传入单个对象作为参数的情况,关键源码如下:

jQuery.extend = jQuery.fn.extend = function () {
  var options,
    name,
    copy,
    target = arguments[0] || {},
    i = 1,
    length = arguments.length,

  // 只传一个参数时
  if (i === length) {
    target = this;
    i--;
  }

  for (; i < length; i++) {
    // 参数不为 null (赋值语句),options为传入的对象
    if ((options = arguments[i]) != null) {
      for (name in options) {
        copy = options[name]; // name为传入对象属性的 key,copy 为 value

        // 禁止修改原型对象,禁止传入自身对象: $.extend({aa: $})、$.fn.extend({aa: $.fn})
        if (name === "__proto__" || target === copy) {
          continue;
        }

        // 属性值存在时赋值
        if (copy !== undefined) {
          target[name] = copy;
        }
      }
    }
  }

  // Return the modified object
  return target;
};

可以看到最终的复制语句为 target[name] = copy,只是将 target 赋值为 this 以实现给调用方法的对象赋值。

简易实现

核心思路:将属性绑定到 this 上,谁调用方法,就给谁绑定。

function jQuery() {
  return new init();
}

function init() {}

init.prototype = jQuery.fn = jQuery.prototype = {};

jQuery.extend = jQuery.fn.extend = function (obj) {
  for (let key in obj) {
    this[key] = obj[key];
  }
};

$ = jQuery;

axios 拦截器

从源码解析 axios 拦截器是如何工作的

实现 axios 的拦截器

Express 中间件

实现类似 Express 的中间件系统