美文网首页码农的世界前端开发IT技术篇
jQuery设计原理-无new构建实例

jQuery设计原理-无new构建实例

作者: 抛荒了四序 | 来源:发表于2019-08-15 18:08 被阅读77次

    jQuery无new构建实例

    无new化构建

    在jQuery中 $符号就是jQuery的别称

    $()就是创建了jQuery的实例对象

    实现

    
    (function(root){
    
        function jQuery() {
            return new jQuery.prototype.init();
        };
    
        // 在jQuery的原型上定义init方法
        jQuery.prototype = {
            init: function() {
    
            },
            css: function() {
                // 在jQuery原型上扩展的属性也会被共享到init的原型上
            }
        }
    
        // 把jQuery的原型共享给init的原型
        jQuery.prototype.init.prototype = jQuery.prototype;
    
        // 设置全局变量$和jQuery
        root.$ = root.jQuery = jQuery;
    
    })(this); // 把宿主对象window传进
    

    共享原型设计

    描述

    如上, 在实现jQuery实例化的时候,我们直接调用$();

    console.log($());
    

    因为$()指向的是jQuery函数,所以相当于调用了jQuery函数;

     // 设置全局变量$和jQuery;
     // $和window.jQuery指向的都是jQuery函数
        root.$ = root.jQuery = jQuery;
    

    jQuery作为构造函数直接被调用效果和普通函数呗调用一样,

    所以无法生成有效实例;

    解决方案:

    只能把jQuery函数的返回值设成构造函数的实例;

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

    但是这样做是不行的,很明显会造成死循环

    所以jQuery采用的共享原型的设计模式, 即;

    • 在jQuery函数的prototype上定义了init方法

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

       // 把jQuery的原型共享给init的原型
        jQuery.prototype.init.prototype = jQuery.prototype;
      
    • 通过$()调用jQuery函数时返回一个init的实例

        function jQuery() {
            return new jQuery.prototype.init();
        };
      
    • 给jQuery的prototype扩展属性的时候,由于原型共享,

      所以init的原型上也会具有该扩展属性

        jQuery.prototype = {
            init: function() {
      
            },
            css: function() {
                // 在jQuery原型上扩展的属性也会被共享到init的原型上
            }
        }
        
        console.log($());
      
    123.png

    以上就是jQuery无new实例化的实现

    原型扩展设计见下图:

    1122.png

    extend函数源码解析

    extend函数用法:

      //  给任意对象扩展
      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)进行扩展
      $.extend({
          myMethod: function() {
              console.log('myMethod1');
          }
      })
      $.myMethod(); //  myMethod1;
    
      // 给$(jQuery)的实例进行扩展
      $.fn.extend({
          myMethod: function() {
              console.log('myMethod2');
          }
      })
      $().myMethod(); //  myMethod2;
    

    extend函数用于给对象进行扩展,给jQuery提供了插件机制

    • 可以给任意对象扩展
    • 也可以给jQuery自身扩展

    注:

      //  $.fn指向的就是$.prototype
      jQuery.fn = jQuery.prototype = {
         // ......
      }
    
    1. extend再jQuery中之所以既能通过$.extend调用,

    又能通过$().extend调用是因为在源码内部中实现了
    jQuery.fn.extend = jQuery.extend = function() { // ...... }

    extend实现与分析

    
        // extend
        jQuery.fn.extend = jQuery.extend = function() {
            
            var target = arguments[0] || {};        //  target赋值为第一个参数,也就是要扩展的对象
            var length = arguments.length;          //  获取参数的个数
            var i = 1;  
            var deep = false;                        
            var options, name, copy, src, copyIsArray, clone;
    
            if(typeof target === 'boolean') {       //   当传入第一个参数是boolean时
                deep = target;                      //   把参数deep的值设置为target,即传入的第一个参数
                target = arguments[1];              //   把target(需扩展的对象设置为第二个参数)
                i = 2;                              //   i = 2,以便之后从第三个参数开始遍历
            };                                  
            
            if(typeof target !== 'object') {        //  验证传入的参数为obj
                target = {};
            };
    
            if(length === i) {                      //  如果只有一个参数,则extend方法为jQuery内部的扩展
                target = this;                      //  把target的引用设置为this,指向$或者$()
                i--;               
            };                                  
    
            // 浅拷贝
            for( ;i < length; i++) {                //  boolean参数和所需要扩展的对象的属性无需遍历
                if((options = arguments[i]) !==null) {
                    for(name in options) {
                        copy = options[name];
                        src = target[name];
                        // 如果需要深拷贝,并且options的属性对应的是对象或数组时
                        if(deep && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
                            if(copyIsArray) {        
                                copyIsArray = false;    //copyIsArray不重置会影响下一次循环的判断;
                                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) {  //  判断传入参数的数据类型是否是obj
                return toString.call(obj) === '[object Object]'
            },
            isArray: function(arr) {        //  判断传入参数的数据类型是否是数组
                return toString.call(arr) === '[object Array]'
            }
        });
    
    

    相关文章

      网友评论

        本文标题:jQuery设计原理-无new构建实例

        本文链接:https://www.haomeiwen.com/subject/mnhtsctx.html