咱們平時使用jQuery大概是這樣:css
let $p = $('p'); $p.css('fontSize', '40px');
咱們生成jQuery實例對象後,就能夠使用原型上的css(), html()等方法,這就體現了原型繼承:由構造函數生成的實例對象,能夠繼承構造函數的原型對象上的屬性和方法。html
咱們能夠試着手寫一個迷你的jQuery,思路大概是這樣:node
1-經過匿名自執行函數來存放咱們的代碼,將window對象做爲參數傳入,防止全局做用域的污染。jquery
2-利用工廠函數,在調用jQuery或者$的時候,返回構造函數的實例對象git
3-構造函數定義爲jQuery.fn.init,初始化時處理dom元素,將dom元素綁定在實例對象上github
4-將構造函數的prototype屬性指向jQuery.fn,此時構造函數的實例即可以繼承jQuery.fn裏的屬性和方法dom
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作中轉呢?this
jQuery.fn = {...}; init.prototype = jQuery.fn;
這就體現了原型的擴展性,jQuery.fn
| $.fn
是用來擴展插件用的,將插件擴展統一到$.fn.xxx
這一個接口,也是符合對修改封閉,對擴展開放的原則。
下面咱們來寫一個簡單的jQuery插件。
$.fn.getNodeName = function () { return this[0].nodeName; } // 測試 alert($box.getNodeName()); // DIV
小結:
本篇文章總結了如下幾個問題