jQuery設(shè)計(jì)原理-無(wú)new構(gòu)建實(shí)例

jQuery無(wú)new構(gòu)建實(shí)例

無(wú)new化構(gòu)建

在jQuery中 $符號(hào)就是jQuery的別稱

$()就是創(chuàng)建了jQuery的實(shí)例對(duì)象

實(shí)現(xiàn)


(function(root){

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

    // 在jQuery的原型上定義init方法
    jQuery.prototype = {
        init: function() {

        },
        css: function() {
            // 在jQuery原型上擴(kuò)展的屬性也會(huì)被共享到init的原型上
        }
    }

    // 把jQuery的原型共享給init的原型
    jQuery.prototype.init.prototype = jQuery.prototype;

    // 設(shè)置全局變量$和jQuery
    root.$ = root.jQuery = jQuery;

})(this); // 把宿主對(duì)象window傳進(jìn)

共享原型設(shè)計(jì)

描述

如上, 在實(shí)現(xiàn)jQuery實(shí)例化的時(shí)候,我們直接調(diào)用$();

console.log($());

因?yàn)?()指向的是jQuery函數(shù),所以相當(dāng)于調(diào)用了jQuery函數(shù);

 // 設(shè)置全局變量$和jQuery;
 // $和window.jQuery指向的都是jQuery函數(shù)
    root.$ = root.jQuery = jQuery;

jQuery作為構(gòu)造函數(shù)直接被調(diào)用效果和普通函數(shù)唄調(diào)用一樣,

所以無(wú)法生成有效實(shí)例;

解決方案:

只能把jQuery函數(shù)的返回值設(shè)成構(gòu)造函數(shù)的實(shí)例;

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

但是這樣做是不行的,很明顯會(huì)造成死循環(huán)

所以jQuery采用的共享原型的設(shè)計(jì)模式, 即;

  • 在jQuery函數(shù)的prototype上定義了init方法

    // 在jQuery的原型上定義init方法
      jQuery.prototype = {
          init: function() {
    
          }
      }
    
  • 把jQuery的原型共享給init

     // 把jQuery的原型共享給init的原型
      jQuery.prototype.init.prototype = jQuery.prototype;
    
  • 通過$()調(diào)用jQuery函數(shù)時(shí)返回一個(gè)init的實(shí)例

      function jQuery() {
          return new jQuery.prototype.init();
      };
    
  • 給jQuery的prototype擴(kuò)展屬性的時(shí)候,由于原型共享,

    所以init的原型上也會(huì)具有該擴(kuò)展屬性

      jQuery.prototype = {
          init: function() {
    
          },
          css: function() {
              // 在jQuery原型上擴(kuò)展的屬性也會(huì)被共享到init的原型上
          }
      }
      
      console.log($());
    
123.png

以上就是jQuery無(wú)new實(shí)例化的實(shí)現(xiàn)

原型擴(kuò)展設(shè)計(jì)見下圖:

1122.png

extend函數(shù)源碼解析

extend函數(shù)用法:

  //  給任意對(duì)象擴(kuò)展
  var obj1 = { a:1, b:2 };
  var obj2 = { c: 3 }; 

  var res = $.extend(obj1, obj2);

  console.log(res); // ===> { a:1, b:2, c: 3 }
  console.log(obj1); // ===> { a:1, b:2, c: 3 }
  
  
  
  // 給$(jQuery)進(jìn)行擴(kuò)展
  $.extend({
      myMethod: function() {
          console.log('myMethod1');
      }
  })
  $.myMethod(); //  myMethod1;

  // 給$(jQuery)的實(shí)例進(jìn)行擴(kuò)展
  $.fn.extend({
      myMethod: function() {
          console.log('myMethod2');
      }
  })
  $().myMethod(); //  myMethod2;

extend函數(shù)用于給對(duì)象進(jìn)行擴(kuò)展,給jQuery提供了插件機(jī)制

  • 可以給任意對(duì)象擴(kuò)展
  • 也可以給jQuery自身擴(kuò)展

注:

  //  $.fn指向的就是$.prototype
  jQuery.fn = jQuery.prototype = {
     // ......
  }
  1. extend再jQuery中之所以既能通過$.extend調(diào)用,

又能通過$().extend調(diào)用是因?yàn)樵谠创a內(nèi)部中實(shí)現(xiàn)了
jQuery.fn.extend = jQuery.extend = function() { // ...... }

extend實(shí)現(xiàn)與分析


    // extend
    jQuery.fn.extend = jQuery.extend = function() {
        
        var target = arguments[0] || {};        //  target賦值為第一個(gè)參數(shù),也就是要擴(kuò)展的對(duì)象
        var length = arguments.length;          //  獲取參數(shù)的個(gè)數(shù)
        var i = 1;  
        var deep = false;                        
        var options, name, copy, src, copyIsArray, clone;

        if(typeof target === 'boolean') {       //   當(dāng)傳入第一個(gè)參數(shù)是boolean時(shí)
            deep = target;                      //   把參數(shù)deep的值設(shè)置為target,即傳入的第一個(gè)參數(shù)
            target = arguments[1];              //   把target(需擴(kuò)展的對(duì)象設(shè)置為第二個(gè)參數(shù))
            i = 2;                              //   i = 2,以便之后從第三個(gè)參數(shù)開始遍歷
        };                                  
        
        if(typeof target !== 'object') {        //  驗(yàn)證傳入的參數(shù)為obj
            target = {};
        };

        if(length === i) {                      //  如果只有一個(gè)參數(shù),則extend方法為jQuery內(nèi)部的擴(kuò)展
            target = this;                      //  把target的引用設(shè)置為this,指向$或者$()
            i--;               
        };                                  

        // 淺拷貝
        for( ;i < length; i++) {                //  boolean參數(shù)和所需要擴(kuò)展的對(duì)象的屬性無(wú)需遍歷
            if((options = arguments[i]) !==null) {
                for(name in options) {
                    copy = options[name];
                    src = target[name];
                    // 如果需要深拷貝,并且options的屬性對(duì)應(yīng)的是對(duì)象或數(shù)組時(shí)
                    if(deep && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
                        if(copyIsArray) {        
                            copyIsArray = false;    //copyIsArray不重置會(huì)影響下一次循環(huán)的判斷;
                            clone = src && jQuery.isArray(src) ? src : [];
                        } else {
                            clone = src && jQuery.isPlainObject(src) ? src : {};
                        }
                        target[name] = jQuery.extend(deep, clone, copy);
                    } else if(copy !== undefined) {
                        target[name] = copy;
                    };
                };
            };
        };

        return target;
    }
    
    jQuery.extend({
        isPlainObject: function(obj) {  //  判斷傳入?yún)?shù)的數(shù)據(jù)類型是否是obj
            return toString.call(obj) === '[object Object]'
        },
        isArray: function(arr) {        //  判斷傳入?yún)?shù)的數(shù)據(jù)類型是否是數(shù)組
            return toString.call(arr) === '[object Array]'
        }
    });

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容