JavaScript 原型的實際應用之實現一個 jQuery

dora_zc發表於2019-05-22

我們平時使用jQuery大概是這樣:

let $p = $('p');
$p.css('fontSize', '40px');

我們生成jQuery例項物件後,就可以使用原型上的css(), html()等方法,這就體現了原型繼承:由建構函式生成的例項物件,可以繼承建構函式的原型物件上的屬性和方法。

我們可以試著手寫一個迷你的jQuery,思路大概是這樣:

1-通過匿名自執行函式來存放我們的程式碼,將window物件作為引數傳入,防止全域性作用域的汙染。

2-利用工廠函式,在呼叫jQuery或者$的時候,返回建構函式的例項物件

3-建構函式定義為jQuery.fn.init,初始化時處理dom元素,將dom元素繫結在例項物件上

4-將建構函式的prototype屬性指向jQuery.fn,此時建構函式的例項便可以繼承jQuery.fn裡的屬性和方法

5-jQuery.fn是一個物件,裡面存放了所有的jQuery方法,讓外部來呼叫

程式碼實現:
完整程式碼請檢視 my-jquery

// my-jquery.js

(function(window) {
  var jQuery = function (selector) {
    // 通過new關鍵字,找到建構函式
    return new jQuery.fn.init(selector);
  };

  // 初始化 jQuery.fn
  jQuery.fn = jQuery.prototype =  {
    constructor: jQuery,
    css: function(key, value) {
      let that = this;
      for (var i = 0; i < that.length; i++) {
        that[i].style[key] = value;
      }
    },
    html: function (value) {
      return this[0].innerHTML;
    },
  };

  // 定義建構函式
  var init = jQuery.fn.init = function(selector) {
    var slice = Array.prototype.slice;
    var dom = slice.call(document.querySelectorAll(selector));
    var i,
      len = dom ? dom.length : 0;
    for (i = 0; i < len; i++) {
      this[i] = dom[i];
    }
    this.length = len;
    this.selector = selector || '';
  };

  // 定義原型
  init.prototype = jQuery.fn;

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

這裡有個問題:這裡為什麼不直接把init.prototype賦值為一個物件,而是要通過jQuery.fn做中轉呢?

jQuery.fn = {...};

init.prototype = jQuery.fn;

這就體現了原型的擴充套件性,jQuery.fn | $.fn 是用來擴充套件外掛用的,將外掛擴充套件統一到$.fn.xxx 這一個介面,也是符合對修改封閉,對擴充套件開放的原則。

下面我們來寫一個簡單的jQuery外掛。

$.fn.getNodeName = function () {
    return this[0].nodeName;
}

// 測試
alert($box.getNodeName()); // DIV

小結:

本篇文章總結了以下幾個問題

  • jQuery是如何使用原型的?
  • 如何實現一個小型的jQuery?
  • jQuery的外掛擴充套件機制

相關文章