Skip to content

一步步分析JQ,真香!(已统一放入blog里,如有需要,请单独享用)

Notifications You must be signed in to change notification settings

mtonhuang/analysis_JQ

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

10 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

首先,我们先去官网把JQ的js相关文件download到本地,看着源码,先多多少少理解一下jq的原理。

接着创建一个属于自己的js文件(取名为jquerMey-1.0.1js)。

这里先说一下解析源码的几个步骤:

  1. 学会分析组成及架构 => (JQ通过选择器(字符串)来检索所有匹配的DOM,并且进行批量操作,同时能够帮我们解决浏览器的兼容问题。)

  2. 学会看英文注释(不懂多用腾讯翻译君[手动滑稽])

  3. 先减后删

  4. 阅读思考作者的语义

  5. 尝试补全 好的,开搞吧!

首先创立一个html文件,如图:

<!DOCTYPE html>
 <html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>jQuery源码解析</title>
  </head>
  <body>
  <div class="box">这是一个div</div>
  <span class="box">这是一个span</span>
  <script src="jquery-3.3.1.js"></script>
  <!--<script src="sizzle.js"></script>-->
  <!--<script src="jquerMey-1.0.1.js"></script>-->
  <script type="text/javascript">
    var $eles = $('.box');
    var $eles = jQuery('.box');
    console.log($eles)
    $eles.addClass('myFirst')
  </script>
</body>
</html>

可以看到,这边jQuery.fn.init 输出的是一个数组,还有一系列方法。我们一步步来。

这边先把JQ源码多余的东西都先删一下,可以看到,定义一个匿名函数,创建 闭包

// 定义一个匿名函数,马上调用它,包起来调用的时候可以创建闭包
    (function(global,factory) {
        //内存中动态开辟了一块空间来执行这个里面的代码,对外是封闭的,可以访问外面的变量
    }(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
         /*这里的三元判断,除了BOM浏览器的运行环境还能运行在什么环境中? =>node环境 (node运行在V8引擎中,主要用来做中间件) 
         中间件很多,架构与部署方面的中间件:webpack,grunt,gulp;功能方面的中间件:node.js(页面静态化) */
    }));

好,接着分析

// 定义一个匿名函数,马上调用它,包起来调用的时候可以创建闭包
    (function (global, factory) {
        //内存中动态开辟了一块空间来执行这个里面的代码,对外是封闭的,可以访问外面的变量
        /*那么除了BOM浏览器的运行环境还能运行在什么环境中? =>
     node环境 (node运行在V8引擎中,主要用来做中间件) 中间件很多,
     架构与部署方面的中间件:webpack,grunt,gulp;功能方面的中间件:node.js(页面静态化) */
        if (typeof module === "object" && typeof module.exports === "object") {
              // For CommonJS and CommonJS-like environments where a proper `window`
            module.exports = global.document ?
                factory(global, true) :
                function (w) {
                    if (!w.document) {
                        throw new Error("jQuery requires a window with a document");
                    }
                    return factory(w);
                };
        }
        else {
            factory(global);
        }
    }(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
    }));

写到这里,那么这里注释说的CommonJS是什么呢?这就涉及到了上面说的node了。

CommonJS是nodejs也就是服务器端广泛使用的模块化机制。 该规范的主要内容是,模块必须通过module.exports 导出对外的变量或接口,通过 require() 来导入其他模块的输出到当前模块作用域中。

可以看到,这里并没有给factory()传入第二个参数,默认为false,则会执行下面if的代码(即为BOM环境)。在if语句中,可以看到jQuery一定是核心代码,那么jQuery到底是什么呢?继续看。

这里的jQuery本质就是一个函数,jQuery有一个fn对象,并且fn有一个init函数。这里的makeArrray本质是返回一个数组。

往下看,可以看到这里jQuery的fn对象其实就是jQuery的原型对象;接着我们找到init方法。

jQuery.fn = jQuery.prototype = {
        init : function (selector, context) {
            return jQuery.makeArray( selector, context );
        }
    };
    jQuery.makeArray = function(selector, context){
        var $eles = new Sizzle(selector, context);
        return $eles;
    }

分析完jQuery.fn,我们看看makeArray。Sizzle.js文件里面有很多算法方面的代码,我们先跳过,继续分析代码。此时,我们用Chrome打开html代码,可以看到,输出如图:(此时还没有写addClass函数所以报错了)

jQuery.fn = jQuery.prototype = {
        init : function (selector, context) {
            return jQuery.makeArray( selector, context );
        },
        each: function (func) {
            
        },
        addClass : function (className) {
            
        },
        removeClass: function (className) {

        }
    };
    jQuery.makeArray = function(selector, context){
        var $eles = new Sizzle(selector, context);
        $eles.prevObject = arguments.callee;
        $eles.__proto__ = jQuery.fn
        return $eles;
    }

继续补全,这样jQuery的 整体架构 就ok了,之后就是往里面添加东西。

(比如往里面添加addClass,removeClass,each方法)

jQuery.fn = jQuery.prototype = {
        init : function (selector, context) {
            return jQuery.makeArray( selector, context );
        },
        each: function (func) {
            for (var i=0;i<this.length;i++) {
                func.call(this,i,this[i]);
            }
            return this;
        },
        addClass : function (className) {
            return this.each(function (index, element) {
               element.className += " " + className
            })
        },
        removeClass: function (className) {
            return this.each(function (index, element) {
                element.className = ""
            })
        }
    };
 

我们可以看到此时控制台里面已经有了我们添加的方法,让我们来实验一下。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>jQuery源码解析</title>
</head>
<style>
    .myEleFirst {
        display: block;
        width: 100px;
        height: 100px;
        margin: 10px auto;
        background: red;
    }
    button {
        display: block;
        width: 20px;
        height: 20px;
        margin: auto;
   }
  </style>
  <body>
   <div class="myEle">这是一个div</div>
   <span class="myEle">这是一个span</span>
   <button onclick="removeClass()"></button>
   <!--<script src="jquery-3.3.1.js"></script>-->
  <script type="text/javascript" src="sizzle.min.js"></script>
  <script type="text/javascript" src="jquerMey-1.0.1.js"></script>
  <script type="text/javascript">
    var $eles = $(".myEle");
    var $eles = jQuery(".myEle");
    console.log($eles);
    $eles.addClass('myEleFirst');
    function removeClass() {
        $eles.removeClass("myEleFirst")
    }
  </script>
  </body>
</html>

结果如图:

附上全部代码:

/*!
 * jqueMey JavaScript Library v1.0.1
 *
 * Includes Sizzle.js
 * https://sizzlejs.com/
 *
 * Copyright JS Foundation and other contributors
 * Released under the MIT license
 * Email: huangmiantong@126.com || v_mtonhuang@tencent.com
 *
 * Date: 2018-12-11T22:04Z
 */

// 定义一个匿名函数,马上调用它,包起来调用的时候可以创建闭包
(function (global, factory) {
    //在BOM浏览器的运行环境
    /*那么除了BOM浏览器的运行环境还能运行在什么环境中? =>
     node环境 (node运行在V8引擎中,主要用来做中间件) 中间件很多,
     架构与部署方面的中间件:webpack,grunt,gulp;功能方面的中间件:node.js(页面静态化) */
    //内存中动态开辟了一块空间来执行这个里面的代码
    if (typeof module === "object" && typeof module.exports === "object") {
        module.exports = global.document ?
            factory(global, true) :
            function (w) {
                if (!w.document) {
                    throw new Error("jQuery requires a window with a document");
                }
                return factory(w);
            };
    } else {
        factory(global);
    }
}(typeof window !== "undefined" ? window : this, function (window, noGlobal) {
    var
        version = "1.0.1",

        // Define a local copy of jQuery
        jQuery = function( selector, context ) {

            // The jQuery object is actually just the init constructor 'enhanced'
            // Need init if jQuery is called (just allow error to be thrown if not included)
            return new jQuery.fn.init( selector, context );
        };
    jQuery.fn = jQuery.prototype = {
        init : function (selector, context) {
            return jQuery.makeArray( selector, context );
        },
        each: function (func) {
            for (var i=0;i<this.length;i++) {
                func.call(this,i,this[i]);
            }
            return this;
        },
        addClass : function (className) {
            return this.each(function (index, element) {
               element.className += " " + className
            })
        },
        removeClass: function (className) {
            return this.each(function (index, element) {
                element.className = ""
            })
        }
    };
    jQuery.makeArray = function(selector, context){
        var $eles = new Sizzle(selector, context);
        $eles.prevObject = arguments.callee;
        $eles.__proto__ = jQuery.fn
        return $eles;
    }
    // Expose jQuery and $ identifiers, even in AMD
    // (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
    // and CommonJS for browser emulators (#13566)
    if (!noGlobal) {
        //BOM一定有window对象
        // jQuery一定是核心对象
        window.jQuery = window.$ = jQuery;
    }
    return jQuery;
}));
 

未完待续...

About

一步步分析JQ,真香!(已统一放入blog里,如有需要,请单独享用)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published