zoukankan      html  css  js  c++  java
  • 《jQuery源码解析》读书笔记(第二章:构造jQuery对象)

    第2章 构造jquery对象 8

    • jQuery 对象是一个类数组对象,含有

      • 连续的整形属性

      • length 属性

      • 大量的 jQuery 方法

    • 2.1 构造函数jquery() 8

      jQuery 很有意思的一点是,它的方法定义很强大,会根据不同的参数情况执行不同的功能。

      构造函数 jQuery() 有 7 种用法。

      • 2.1.1 jquery( selector [, context] ) 9

        • 用法

          • 如果传入一个字符串参数, jQuery 会检查这个字符串是选择器还是 HTML 代码
          • 如果是选择器,则遍历文档
            • 如果有匹配的元素,返回匹配的封装了匹配的 DOM 元素的 jQuery 对象
            • 如果没有匹配的元素,则返回一个空的 jQuery 对象
      • 2.1.2 jquery( html [, ownerdocument] )、jquery( html, props ) 9

        • 用法
          • 如果传入的参数看起来像一段 HTML 代码,那么jQuery会尝试创建新的DOM元素,并创建一个封装了此DOM元素的jQuery对象
          • 第二个参数 ownerDocument 用于指定创建新DOM对象的文档对象,如果不传入,则默认为当前文档对象
          • 如果HTML代码是单独一个标签,那么第二个参数还可以是props,是一个包含了属性、事件的普通对象,设置新创建元素的属性、事件
      • 2.1.3 jquery( element )、jquery( elementarray ) 10

        • 用法

          传入一个DOM对象或DOM数组,然后封装这些DOMjQuery对象

      • 2.1.4 jquery( object ) 10

        • 用法

          • 传入一个普通JavaScript对象,把该对象封装到jQuery对象并返回
          • 可以方便的实现自定义事件的绑定和触发
      • 2.1.5 jquery( callback ) 11

        • 用法

          DOM ready事件的回调函数

      • 2.1.6 jquery( jquery object ) 11

        • 用法

          传入一个jQuery对象,则返回该对象的一个副本,这个副本与原jQuery对象引用相同的DOM元素

      • 2.1.7 jquery() 11

        • 用法

          • 不传入任何一个参数,则返回一个空的 jQuery 对象
          • 可以用来复用 jQuery 对象,例如,创建一个空的jQuery对象,然后在需要的时候手动修改其中的元素,再调用jQuery方法,从而避免重复创建jQuery对象
    • 2.2 总体结构 11

      (function(window, undefined) {
          // 构造 jQuery 对象
          var jQuery = (function() {
              var jQuery = function(selector, context) {
                  return new jQuery.fn.init(selector, context, rootjQuery);
              };
      
              // 一堆局部变量声明
              // ...
              
              jQuery.fn = jQuery.prototype = {
                  constructor: jQuery,
                  init: function(selector, context, rootjQuery) {
      
                  }
      
                  // 一堆原型属性和方法
              };
      
              jQuery.fn.init.prototype = jQuery.fn;
      
              jQuery.extend = jQuery.fn.extend = function() {};
      
              jQuery.extend({
                  // 一堆静态属性和方法
              });
      
              return jQuery;
          })();
      
          // 工具方法 Utilities
          // 回调函数列表 Callbacks Object
          // 异步队列 Defferred Object
          // 浏览器功能测试 Support
          // 数据缓存 Data
          // 队列 Queue
          // 属性操作 Attributes
          // 事件系统 Events
          // 选择器 Sizzle
          // DOM遍历 Traversing
          // 样式操作 CSS(计算样式、内联样式)
          // 异步请求 Ajax
          // 动画 Effects
          // 坐标 Offset、尺寸 Dimensions
      
          window.jQuery = window.$ = jQuery;
      })(window);
      

      以上内容,有几个要点:

      • jQuery 的定义部分,为什么要用自调用匿名函数包裹?

        减少与其他模块的耦合,体现高内聚低耦合的思想

      • jQueryjQuery.fn.initprototype都被覆盖了

      • jQueryjQuery.fn.init 这两个方法的 prototype 都指向了 jQuery.prototype

        好处是jQueryjQuery.prototype.init的实例都可以访问构造函数 jQuery() 的原型属性和方法。

        用图表示即:

        new jQuery()                ---> jQuery.prototype
                                                                    ---->   同一个对象
        new jQuery.prototype.init() ---> jQuery.prototype.init.prototype
        
      • 为什么要增加一个函数jQuery.fn.init

        1、对返回对象的要求:该对象需要能访问jQuery原型上的方法和属性。

        2、一般情况下返回的是jQuery的实例,但如果返回的代码是return new jQuery(),会形成死循环

        3、因此构建一个新函数,该函数的实例也能访问jQuery原型上的方法和属性

      • 为什么要在构造函数 jQuery() 内部用运算符 new 创建并返回另一个构造函数的实例?

        创建一个实例的方式是 new 后面跟一个构造函数,如果构造函数有返回值,运算符 new 所创建的对象会被丢弃,返回值将作为 new 表达式的值

        jQuery利用了这一特性,省去了构造函数jQuery()之前的运算符new

        为了书写方便,为构造函数定义了别名$

    • 2.3 jquery.fn.init( selector, context, rootjquery ) 13

      构造函数 jquery.fn.init() 负责解析参数 selectorcontext 的类型,并执行相应的逻辑,返回jquery.fn.init()实例。它有12个有效分支

      • .2.3.1 12个分支 13

      • 2.3.2 源码分析 14

      • 2.3.3 小结 21

    • 2.4 jquery.buildfragment( args, nodes, scripts ) 22

      • 2.4.1 实现原理 22

      • 2.4.2 源码分析 22

      • 2.4.3 小结 26

    • 2.5 jquery.clean( elems, context, fragment, scripts )27

      • 2.5.1 实现原理 27

      • 2.5.2 源码分析 27

      • 2.5.3 小结 39

    • 2.6 jquery.extend()、jquery.fn.extend() 40

      • 2.6.1 如何使用 40

        • 二者是一样的功能:jQuery.extend = jQuery.fn.extend = function()

          也就是说,jQuery对象和jQuery的实例对象都有extend方法了

        • 语法

          jQuery.extend([deep],target,object1[,objectN])

          jQuery.fn.extend([deep],target,object1[,objectN])

        • 参数

          • deep

            是可选的布尔值,表示是否进行深度合并(即递归合并),默认是不递归的,即后面参数的属性的会覆盖第一个参数的同名属性。如果是true,表示进行深度合并,合并过程是递归的。

          • target

            目标对象

          • objectN

            源对象,所有源对象的属性都会合并到目标对象

          • 如果只有一个参数

            那么参数target将被忽略,jQueryjQuery.fn被当做目标对象,用这种方式可以在jQueryjQuery.fn上添加新的属性和方法

      • 2.6.2 源码分析 40

    • 2.7 原型属性和方法 43

      以下属性和方法均在下方代码块中定义

      jQuery.fn = jQuery.prototype = {
          原型属性和方法
      }
      

      也就是说,jQuery的实例有这些属性和方法

      • 2.7.1 .selector、.jquery、.length、.size() 44

        • 源码

          selector: '',
          
          // 版本号
          jquery: '1.7.1',
          
          // jQuery 对象中元素的个数,初始化为 0
          length: 0,
          
          // 同 length,不建议使用
          size: function() {
              return this.length;
          },
          
        • selector

          • 介绍

            当前jQuery对象的选择器,主要用来调试,与实际选择器不一定匹配

          • 源码

            `jquery`: 当前`jQuery`的版本号
            `length`:jQuery 对象中元素的个数,初始化为 0
            `size`:同 length,不建议使用,因为有函数调用开销
            
      • 2.7.2 .toarray()、.get( [index] ) 45

        • toArray

          slice = Array.prototype.slice
          
          toArray: function() {
              return slice.call(this, 0);
          }
          

          小技巧:借鸡下蛋

          利用Array.prototype.slice方法将jQuery对象转为数组,形成方法toArrayslice方法里的this,可以是数组,也可以是类数组。

        • get

          源码:return num == null ? this.toArray() ? (num < 0 ? this[this.length + num] : this[num])

          这样就可以支持: 1、参数为空;2、下标为负数。

      • 2.7.3 .each( function(index, element) )、jquery.each( collection, callback (indexinarray, valueofelement) ) 46

        • .each

          • 功能介绍

            1、遍历当前jQuery对象,并在每个对象上执行回调函数

            2、回调函数参数是索引(从0开始)和当前对象

            3、最重要的一点是,回调函数中的this总是指向当前元素

            4、在回调函数中返回false可以终止遍历

          • 实现技巧

            在源码中,它通过调用jQuery.each方法来实现,又一个借鸡生蛋的应用。

        • jQuery.each

          • 源码在627~666行,就不贴在这里了
          • 源码实现的总体思路
            • 功能上,可以遍历(类)数组和对象(包括函数)
            • 可以自定义回调函数的参数,如果不自定义,则默认给回调函数传index, element的参数
          • 小技巧
            • 判断是否是对象:isObj == object.length === undefined || jQuery.isFunction(object)

            • 遍历对象,用for in

            • 遍历数组,用for循环

            • 执行、判断写在同一句

              if(callback.call(object[i], i, object[i++]) === false){ break; }

            • break可以跳出for infor循环

      • 2.7.4 .map( callback(index, domelement) )、jquery.map( arrayorobject, callback(value, indexorkey) ) 47

      • 2.7.5 .pushstack( elements, name, arguments ) 49

      • 2.7.6 .end() 51

        • 功能描述

          核心代码:return this.prevObject || this.constructor(null)

          如果是:$(ul.first).find('.foo').css(..).end().find('.bar')

      • 2.7.7 .eq( index )、.first()、.last()、.slice( start [, end] ) 51

        • .eq

          eq: function(i) {
              i = +i;
              return i === -1 ?
                  this.slice(i) :
                  this.slice(i, i + 1);
          }
          

          小技巧:如果i是字符串,把前面加上+可以把该参数转换为数值

      • 2.7.8 .push( value, ... )、.sort( [orderfunc] )、.splice( start,deletecount, value, ... ) 52

        • .push

          var foo = $(document);
          
          foo.push(document.body); // 2
          
        • .sort

          var foo = $([33, 4, 1111, 222]);
          
          foo.sort(); // [1111, 222, 33, 4]
          
          foo.sort(function(a, b) {
              return a - b;
          }); // [4, 33, 222, 1111]
          
      • 2.7.9 小结 53

    • 2.8 静态属性和方法 54

      • 2.8.1 jquery.noconflict( [removeall] ) 55

        看源码即可,绕来绕去的

      • 2.8.2 类型检测:jquery.isfunction( obj )jquery.isarray( obj )jquery.iswindow( obj )jquery.isnumeric( value )jquery.type( obj )jquery.isplainobject( object )jquery.isemptyobject( object ) 56

        • 判断类型

        核心代码是用了 toString.call(obj)判断,该表达式的值是:

        [object Array][object Boolean][object Date][object Function][object Number][object Object][object RegExp][object String]

        还有一个小技巧,循环数组:

        ('Boolean Date Function Number Object RegExp String').split(' ')
        
        • isWindow

          判断方法是:obj == obj.window,以前的版本里是:setInterval in obj

        • jquery.isplainobject( object )

          • 功能

            判断对象是否由 {}new Object()创建

          • 返回false的情况

            • object 可以转为 false

            • Object.prototype.toString.call(object)返回的不是[object Object]

            • objectDOM元素

              object.nodeType 非空

            • objectwindow 对象

            • 不是由Object()函数创建,而是由自定义函数创建的,返回false

              • 含有属性constructor

                是继承属性

                是自身属性

                如果不含属性constructor,则一定是{}创建的对象

              • 没有属性isPropertyOf

                isPropertyOfObject原型对象的特有属性

              • 执行时抛出异常。IE 8/9中,在某些浏览器对象上执行以上检测时会抛出异常,也应该返回false

          • 返回true的情况

            Object.prototype.hasOwnProperty(property)检测对象是否含有该非继承属性

            如果该对象没有属性,或所有属性都是非继承属性,则返回true

        • jquery.isemptyobject( object )

          for in遍历自身属性和继承属性

        • parseFloat(x)可以解析字符串,并返回字符串的第一个数字;如果没有数字,则返回NaN;如果参数是对象,则自动调用该对象的方法toString(),得到该对象的字符串表示,然后再解析

      • 2.8.3 解析jsonxmljquery.parsejson( data )jquery.parsexml( data ) 60

        • jquery.parsejson( data )

          • 解析思路

            先尝试用JSON.parse解析,如果没有该方法,则用(new Function('return' + data))()解析

            其余的是正则表达式匹配字符串之类的东西,在此略过

          • JSON.parse

            解析json字符串为json对象

            判断方法:window.JSON && window.JSON.parse

          • JSON.stringify

            解析json对象为json字符串

            用法1:

            JSON.stringify({a: 1, b: 2}); // '{"a": 1, "b": 2}'
            

            用法2:

            JSON.stringify({a: 1, b: 2}, function(key, value) {
                if(key == '') return value;
                if(key == 'a') return value * 10;
                if(key == 'b') return undefined;
                return value;
            })
            
            // '{"a": 10}'
            

            用法3:

            JSON.stringify({a: 1, b: 2}, ['b']); // '{"b": 2}'
            

            用法4:

            JSON.stringify({a: 1, b: 2}, null, 4); // '{
                "a": 1
                "b": 2
            }'
            
      • 2.8.4 jquery.globaleval( code ) 65

      • 2.8.5 jquery.camelcase( string ) 65

        针对-ms单独做了处理,所有处理函数还是很简洁的

        return string.replace(/^-ms-/, 'ms-').replace(/-[a-z]|[0-9]/, function(){...});
        
      • 2.8.6 jquery.nodename( elem, name ) 66

        dom元素的节点名称:dom.nodeName

      • 2.8.7 jquery.trim( str ) 67

        书中的思路很清晰,值得一提的是,这个方法里同样用了String.prototype.trim()方法来借鸡生蛋

        另外,在IE9中,正则/s/不能匹配不间断空格xA0,但其也被认为是空格。测试是否不识别,用:/S/.test('xA0'),如果是true,则不能识别

      • 2.8.8 数组操作方法:jquery.makearray( obj )、jquery.inarray( value, array [, fromindex] )、jquery.merge( first, second )、jquery.grep( array, function(elementofarray, indexinarray) [, invert] ) 68

        • jquery.makearray( obj )

          学到了一点:push方法里的this可以指定为类数组

        • jquery.inarray( value, array [, fromindex] )

          fromIndex 是查找的起点

          如果浏览器支持数组方法indexOf,则直接调用,否则就自己写方法

          数组的下标有可能是不连续的,所以需要用i in array来判断是否存在下标i

          值得学习的就是判断了

          if($.inArray(element, array) > -1) {}
          

          太繁琐,改进为

          if(!!~$.inArray(element, array)) {}
          

          ~按位取反,相当于改变符号并且减一,只有当-1时,~(-1) == 0

          !!用来形成布尔值

        • jquery.merge( first, second )

          这个方法的源码写的挺不错的,值得一看。

          其中,把second认为两种对象处理:

          1、数组/类数组(判断依据:有无整数/可转为整数的属性length, typeof second.length === 'number'

          2、含有连续整形(或可转换为连续整形)的对象,如{0: 'a', 1: 'b'},从下标0开始遍历。

          最后修正first.length,因为first不一定是真正的属性,需要手动维护length属性。

      • 2.8.9 jquery.guid、jquery.proxy( function, context ) 72

        • jquery.proxy( function, context )

          这个函数使得某个函数在任何环境下执行时,上下文都是context,很实用。

          而且,它的实现原理是:1、闭包封存上下文context;2、返回一个新函数,新函数的作用域链上,有闭包内的上下文context

          其他的,看源码即可。

      • 2.8.10 jquery.access( elems, key, value, exec, fn( elem, key, value ), pass ) 74

      • 2.8.11 jquery.error( message )jquery.noop()jquery.now() 75

      • 2.8.12 浏览器嗅探:jquery.uamatch( ua )jquery.browser 76

      • 2.8.13 小结 77

    • 2.9 总结 77

      到这一步,值得将jQuery的整体结构再回顾一遍了。代码概述在11页的图上。

      (1)构造函数jQuery()有7种用法,根据参数的不同而不同。

      (2)jQuery.fn.init()方法有12种用法,根据参数的不同而不同。

      (2)原型属性和方法,直接放在jQuery.fn = jQuery.prototype对象上

      (3)静态属性和方法,通过jQuery.extend({...})放在jQuery对象上

  • 相关阅读:
    python之路_爬虫之selenium模块
    python之路_爬虫之requests模块补充
    扩展中国剩余定理讲解
    扩展中国剩余定理讲解
    bzoj3225 [Sdoi2008]立方体覆盖——扫描线
    差分约束讲解
    CF917C Pollywog —— 状压DP + 矩乘优化
    斜率优化讲解
    AC自动机讲解
    BZOJ2870—最长道路tree
  • 原文地址:https://www.cnblogs.com/yiyang/p/4959373.html
Copyright © 2011-2022 走看看