• jQuery框架结构简析


      一、 切入点:首先完成each方法和map方法的模拟;

        each方法: jQuery的each方法,返回一个jQuery对象,即一个伪数组,因此each方法实现了链式编程。另外,jQuery的each方法的回调函数返回false,结束循环,内部的this指向当前遍历的元素;

        map方法: jQuery的map方法中,根据回调函数的放回结果来返回,如果回调函数返回的是数组,那么map方法返回数组,如果回调函数中没有返回值,那么默认返回一个空数组。因此,map方法破坏了链式编程,内部的this不再指向遍历元素,而是window;  

      二、框架搭建:

        将整个框架的搭建放在一个沙箱中(闭包)

          (funtion(window){})(window);   // window 有两个作用: 一是减少作用域的搜索,而是提高压缩的效率

        需要一个函数,在此用MHQ表示;  

        替换原型对象并还原构造器;

        影藏new关键字:  // MHQ并不通过new关键字,jQuery的做法是,在其原型对象上添加init构造函数,该构造函数的实例就是MHQ;

        现在的问题是MHQ.prototype.init()构造函数的实例怎么调用MHQ原型对象上的方法? jQuery的做法是: 让其原型对象上的init构造函数的原型对象指向其原型对象,也就是说:让MHQ.prototype.init.prototype = MHQ.prototype;

        那么现在如何要让闭包中的MHQ暴漏给外部访问呢? 答案是将其挂到全局window上,于是有了window.MHQ = window.M = MHQ; MHQ就是jQuery,那么M就是$,现在,window.MHQ就直接访问MHQ原型上的方法了。

        现在的问题是:如何给jQuery扩展方法呢?   jQuery的做法是直接添加静态属性和实例方法,实现混入继承。  MHQ.extend=MHQ.fn.extend=function(obj){for(var key in obj){this[k]=obj[k]}};将一个对象中的属性和方法拷贝一份供自己使用;

        另外jQuery中为了避免出现错误将所有的变量声明提前。

     1 (function(window){
     2     function MHQ(selector){
     3         return new MHQ.fn.init(selector);
     4     }
     5     MHQ.fn = MHQ.prototye = {
     6         constructor: MHQ,
     7         length:0,
     8         init: function(selector){
     9             // 对传入选择器的一系列的判断
    10         }
    11     };
    12     MHQ.fn.init.prototype = MHQ.fn;
    13     MHQ.extend = MHQ.fn.extend = function(obj){
    14         var k;
    15         for(k in obj){    
    16             this[k] = obj[k];
    17         }
    18     };
    19     // 扩展实例方法,通过MHQ.fn.init(selector)的实例来访问
    20     MHQ.fn.extend({...});    
    21     // 扩展静态方法,一般是工具类方法,如each,map
    22     MHQ.extend({...});
    23     window.MHQ = window.M = MHQ; 
    24 })(window); 

      三、首先根据切入点一的分析封装each和map方法

        这里需要明确jQuery的$符里面能够传入的类型有:jQuery对象,字符串(html格式字符串和选择器),DOM对象,函数等,因此需要判断传入的类型,因此也就有了其对应的判断方式。

      四、toArray方法和get方法的封装

        其中toArray方法没有参数,get方法不传参返回DOM元素的真数组,传入参数为正数,返回对应下标的DOM元素,为负数从this.length开始计算返回DOM元素;

      五、DOM操作的一些方法的封装

        在此需要注意的是链破坏,恢复链;

     

      1 /**
      2  * Created by mhq on 2016/10/26.
      3  */
      4 // window 的两个作用: 减少作用域的搜素,提高压缩效率
      5 (function (window) {
      6     /*在闭包内部作用域中定义变量,提高效率*/
      7     var arr = [];
      8     var push = arr.push;
      9     var slice = arr.slice;
     10 
     11     // MHQ的原型对象中的init构造函数创建对象,影藏了new关键字,返回一个伪数组
     12     function MHQ(selector) {
     13         return new MHQ.fn.init(selector);
     14     }
     15     // 替换原型对象的方式实现继承
     16     MHQ.fn = MHQ.prototype = {
     17         // 还原构造器
     18         constructor: MHQ,
     19         // 添加length属性,返回时是伪数组
     20         length: 0,
     21         init: function (selector) {
     22             // 判断选择器类型
     23             if (!selector) return this;
     24             if (typeof selector === "string") {
     25                 // HTML格式的字符串
     26                 if (selector.charAt(0) === "<") {
     27                     push.apply(this, parseHTML(selector));
     28                     return this;
     29                 } else { // 选择器
     30                     push.apply(this, document.querySelectorAll(selector));
     31                     return this;
     32                 }
     33             }
     34             if (typeof selector === "function") {
     35                 // 传入类型是函数  将来处理事件
     36             }
     37             if (selector.nodeType) {  // 是DOM对象时
     38                 this[0] = selector;
     39                 this.length = 1;
     40                 return this;
     41             }
     42             if (selector.constructor.name === MHQ) { // 是MHQ类型的对象
     43                 return selector;
     44             }
     45             if (selector.length >= 0) { // 是数组或者伪数组
     46                 push.apply(this, selector);
     47             } else {
     48                 this[0] = selector;
     49                 this.length = 1;
     50             }
     51         }
     52     };
     53     // 使init构造函数的实例能够访问MHQ原型对象中的方法
     54     MHQ.fn.init.prototype = MHQ.fn;
     55     // 混入实现继承 
     56     MHQ.extend = MHQ.fn.extend = function (obj) {
     57         var k;
     58         for (k in obj) {
     59             this[k] = obj[k];
     60         }
     61     };
     62     
     63     MHQ.fn.extend({
     64         each: function (callback) {
     65             return MHQ.each(this, callback);
     66         },
     67         map: function (callback) {
     68             return MHQ.map(this, callback);
     69         }
     70     });
     71     
     72     MHQ.extend({
     73         each: function (obj, callback) {
     74             var i,
     75                 len = obj.length,
     76                 isArray = len >= 0;
     77             if (isArray) {
     78                 for (i = 0; i < len; i++) {
     79                     if (callback.call(obj[i], i, obj[i]) === false) break;
     80                 }
     81             } else {
     82                 for (i in obj) {
     83                     if (callback.call(obj[i], i, obj[i]) === false) break;
     84                 }
     85             }
     86             return obj;
     87         },
     88         map: function (obj, callback) {
     89             var i,
     90                 len = obj.length,
     91                 isArray = len >= 0,
     92                 result,
     93                 ret = [];
     94             if (isArray) {
     95                 for (i = 0; i < len; i++) {
     96                     result = callback(obj[i], i);
     97                     if (result != null) {
     98                         ret.push(result);
     99                     }
    100                 }
    101             } else {
    102                 for (i in obj) {
    103                     result = callback(obj[i], i);
    104                     if (result != null) {
    105                         ret.push(result);
    106                     }
    107                 }
    108             }
    109             return ret;
    110         },
    111         next: function ( dom ) {
    112             var node = dom;
    113             while( node = node.nextSibling ) {
    114                 if ( node.nodeType === 1 ) {
    115                     return node;
    116                 }
    117             }
    118             return null;
    119         }
    120     });
    121 
    122     // 处理HTML字符串的方法
    123     function parseHTML(htmlStr) {
    124         var div = document.createElement("div"),
    125             i = 0,
    126             nodeArr = [];
    127         div.innerHTML = htmlStr;
    128         for (; i < div.childNodes.length; i++) {
    129             nodeArr.push(div.childNodes[i]);
    130         }
    131         return nodeArr;
    132     }
    133 
    134     // 实现toArray方法、get方法(获取DOM元素)
    135     MHQ.fn.extend({
    136         toArray: function () {
    137             return slice.call(this);
    138         },
    139         get: function (index) {
    140             if (index === undefined) {
    141                 return this.toArray();
    142             } else {
    143                 return this[index > 0 ? index : this.length + index];
    144             }
    145         }
    146     });
    147 
    148     // DOM元素操作模块
    149     MHQ.fn.extend({
    150         appendTo: function (selector) {
    151             var i,
    152                 j,
    153                 tmpObj,
    154                 ret = [],
    155                 destinationObj = MHQ(selector);
    156 
    157             for (i = 0; i < this.length; i++) {
    158                 for (j = 0; j < destinationObj.length; j++) {
    159                     tmpObj = j === destinationObj.length - 1 ? this[i] : this[i].cloneNode(true);
    160                     ret.push(tmpObj);
    161                     destinationObj[j].appendChild(tmpObj);
    162                 }
    163             }
    164             return this.pushStack(ret);
    165         },
    166         prependTo: function (selector) {
    167             // 将 this[i] 加入到 selector[j] 中, 链会破坏
    168             // MHQ( selector ).prepend( this );
    169             var tmpObj, ret = [],
    170                 i, j,
    171                 destinationObj = MHQ(selector);
    172             for (i = 0; i < this.length; i++) {
    173                 for (j = 0; j < destinationObj.length; j++) {
    174                     tmpObj = j === destinationObj.length - 1 ? this[i] : this[i].cloneNode(true);
    175                     ret.push(tmpObj);
    176                     destinationObj[j].insertBefore(tmpObj, destinationObj[j].firstChild);
    177                 }
    178             }
    179 
    180             return this.pushStack(ret);
    181         },
    182         prepend: function (selector) {
    183             MHQ(selector).appendTo(this);
    184             return this;
    185         },
    186         append: function (selector) {
    187             // 将 selector[j] 加到 this[i] 中
    188             // 不会造成链破坏
    189             MHQ(selector).appendTo(this);
    190             return this;
    191         },
    192         next: function () {
    193             /*
    194              var ret = [];
    195              this.each(function () {
    196              ret.push( this.nextElementSibling );
    197              });
    198              return this.pushStack( ret );
    199              */
    200             return this.pushStack(
    201                 this.map(function ( v ) {
    202                     return MHQ.next( v );
    203                 }));
    204         },
    205         remove: function () {
    206             this.each(function () {
    207                 this.parentNode.removeChild(this);
    208             });
    209         }
    210     });
    211 
    212     // 恢复链
    213     MHQ.fn.extend({
    214         end: function () {
    215             return this.prevObj || this;
    216         },
    217         pushStack: function (array) {
    218             var newObj = MHQ(array);
    219             newObj.prevObj = this;
    220             return newObj;
    221         }
    222     });
    223 
    224     window.MHQ = window.M = MHQ;
    225 
    226 })(window);

      暂时先分析这些基本的功能实现过程。

      

      学习是一个辛苦但又兴奋的过程,只有通过不断的努力,才能勉强不让自己在快速发展的节奏中脱节。

    拼着一切代价,奔你的前程。_巴尔扎克
  • 相关阅读:
    我的第一次面试 —— 腾讯 AI安全 一面总结
    从零开始openGL——五、光线追踪
    从零开始openGL——四、纹理贴图与n次B样条曲线
    从零开始openGL——三、模型加载及鼠标交互实现
    从零开始openGL—— 二、 基本图形绘制
    NN入门,手把手教你用Numpy手撕NN(三)
    2020计算机保研经验分享
    TCP实战二(半连接队列、全连接队列)
    TCP实战一(三握四挥、流量控制)
    tcpdump抓包工具的基本使用
  • 原文地址:https://www.cnblogs.com/hongqin/p/5999801.html
Copyright © 2020-2023  润新知