码农的世界前端开发IT技术篇

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

2019-08-15  本文已影响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采用的共享原型的设计模式, 即;

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提供了插件机制

注:

  //  $.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]'
        }
    });

上一篇 下一篇

猜你喜欢

热点阅读