jQuery源码浅析

如果说php是世界上最好的语言,那么javascript无疑可以称为世界上最飘逸的语言,最近看了下jQuery的源码,实现了一个简陋的jQuery。我觉得要看懂jQuery整体结构,需要搞懂js作用域链,闭包,js prototype继承,关于闭包网络上的定义实在太多了,这里参照了js权威指南里的定义,感觉从js的角度好理解一点。

闭包:js函数对象不仅包含函数的代码逻辑,还引用了当前的作用域链,

函数对象可以通过作用域链相互关联起来,函数体内部的变量都可以保存在函数作用域内

这种特性在计算机科学文献中称为闭包,所有的js函数都是闭包。

javascript运行在它被定义的作用域里,而不是执行的作用域里

关于js作用域参见 : http://www.laruence.com/2009/05/28/863.html

废话少说,上滥代码

<!DOCTYPE html>
<html>
<head>
    <title>jQuery源码浅析</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
</head>
<script>
/**
 *
 * 参照jQuery 3.2.1源码
 * 省略了一些规范,如AMD, Commonjs
 * 整个jQuery包含在匿名函数中,函数就是闭包
 */

(function(window, factory){

    factory(window);

})(window, function(window){
    /**
     * 为什么要传window对象?
     * 1.在jQuery里可以把window对象当局部变量使用
     * 2.压缩的时候window变量名可以压缩至1个字节
     */

    var getProto = Object.getPrototypeOf;
    var class2type = {};
    var toString = class2type.toString;
    var hasOwn = class2type.hasOwnProperty;
    var fnToString = hasOwn.toString;
    var ObjectFunctionString = fnToString.call( Object );

    /**
     * 工厂方法,返回jQuery.fn.init的实例,即jQuery对象
     * selector待查找的字符串,源码里还有context参数,此处省略
     * 我们所说的jQuery其实准确的说是jQuery工厂方法,调用jQuery工厂方法返回的才是真正的jQuery对象
     */
    var jQuery = function(selector){
            return new jQuery.fn.init(selector);
        },
        version = "3.2.1";

    //jQuery原型对象赋值给jQuery.fn,定义在jQuery.prototype里的方法可以被所有的jQuery对象使用
    jQuery.fn = jQuery.prototype = {

        jquery: version,

        constructor: jQuery,

        //...省掉了一些方法
    };

    //jQuery.fn的属性init函数,jQuery的选择器使用了Ssize,这里简单的使用一个id选择器
    jQuery.fn.init = function(selector){
        /* (在Javascript中,This关键字永远都指向函数(方法)的所有者) this指向的是jQuery.fn
        *  这里简单的将DOM对象赋值给this[0],其他属性省略, 我们使用jQuery的时候使用下标0即可将jQuery对象转化为普通的DOM对象
        */
        this[0] = window.document.getElementById(selector);
        return this;
    };

    /**
    * 这一句很关键
    * 将jQuery.fn赋值给jQuery.fn.init的原型,这样jQuery.fn.init的实例(通常我们所说的jQuery对象就是它)可以使用jQuery.fn的方法
    * 结合之前可以得出 jQuery.fn.init.prototype = jQuery.fn = jQuery.prototype
    * jQuery.fn,jQuery.prototype扩展的方法属性 jQuery对象可以使用
    */
    jQuery.fn.init.prototype = jQuery.fn;

    //实现了jQuery的html方法
    jQuery.fn.html = function(value){
        if(typeof value === "string"){
            this[0].innerHTML = value;
            return this;
        }else{
            return this[0].innerHTML;
        }
    };

    /**
     *
     * jQuery扩展方法,除了可以扩展jQuery外,还可以扩展你指定的对象
     * jQuery.extend 扩展jQuery,可以理解为扩展类方法
     * jQuery.fn.extend 扩展jQuery.fn,即jQuery实例可以使用,可以理解为扩展实例方法
     *
     * 具体用法
     * 1.jQuery.extend(obj) 扩展jQeury
     * 2.jQuery.extend(true, obj) 深度扩展jQuery
     * 3.jQuery.extend(obj1, obj2) 扩展obj1
     * 4.jQuery.extend(true obj1, obj2) 深度扩展obj1
     */
    jQuery.extend = jQuery.fn.extend = function() {
        var options, name, src, copy, copyIsArray, clone,
            target = arguments[ 0 ] || {},
            i = 1,
            length = arguments.length,
            deep = false;

        //第一个参数为boolean且为true的时候为深度扩展
        if ( typeof target === "boolean" ) {
            deep = target;
            // Skip the boolean and the target
            target = arguments[ i ] || {};
            i++;
        }

        //被扩展的对象不是对象或者函数
        if ( typeof target !== "object" && !jQuery.isFunction( target ) ) {
            target = {};
        }

        //参数只有1个对象的情况下,扩展jQuery,多个对象则扩展第一个对象
        if ( i === length ) {
            target = this;
            i--;
        }

        for ( ; i < length; i++ ) {
            //只处理非空值
            if ( ( options = arguments[ i ] ) != null ) {

                // Extend the base object
                for ( name in options ) {
                    src = target[ name ];
                    copy = options[ name ];

                    // Prevent never-ending loop
                    if ( target === copy ) {
                        continue;
                    }

                    //仅在属性为纯粹对象或者 数组的时候深度拷贝才有效
                    if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
                        ( copyIsArray = Array.isArray( copy ) ) ) ) {

                        if ( copyIsArray ) {
                            copyIsArray = false;
                            clone = src && Array.isArray( src ) ? src : [];

                        } else {
                            clone = src && jQuery.isPlainObject( src ) ? src : {};
                        }

                        //递归扩展
                        target[ name ] = jQuery.extend( deep, clone, copy );

                    // Don‘t bring in undefined values
                    } else if ( copy !== undefined ) {
                        target[ name ] = copy;
                    }
                }
            }
        }

        // Return the modified object
        return target;
    };

    jQuery.extend( {

        isFunction: function( obj ) {
            return jQuery.type( obj ) === "function";
        },

        isPlainObject: function( obj ) {
            var proto, Ctor;

            // Detect obvious negatives
            // Use toString instead of jQuery.type to catch host objects
            if ( !obj || toString.call( obj ) !== "[object Object]" ) {
                return false;
            }

            proto = getProto( obj );

            // Objects with no prototype (e.g., `Object.create( null )`) are plain
            if ( !proto ) {
                return true;
            }

            // Objects with prototype are plain iff they were constructed by a global Object function
            Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
            return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
        },

        type: function( obj ) {
            if ( obj == null ) {
                return obj + "";
            }

            // Support: Android <=2.3 only (functionish RegExp)
            return typeof obj === "object" || typeof obj === "function" ?
            class2type[ toString.call( obj ) ] || "object" :
            typeof obj;
        },
    });

    //简易ready方法实现, 只支持DOMContentLoaded
    jQuery.extend( {
        readyList : [],
        ready: function(fn){
            if(fn && typeof fn === ‘function‘){
                //向数组末尾添加函数
                jQuery.readyList.push(fn);
            }else{
                //顺序执行ready绑定的方法
                for(var i in jQuery.readyList){
                    fn = jQuery.readyList[i];
                    //fn来自于全局作用域,属于window对象
                    fn.call(window, jQuery);
                }
            }
        }
    });

    //只支持DOMContentLoaded
    document.addEventListener( "DOMContentLoaded", completed );
    window.addEventListener( "load", completed );
    function completed() {
        document.removeEventListener( "DOMContentLoaded", completed );
        window.removeEventListener( "load", completed );
        jQuery.ready();
    }
    //只暴露了两个变量到全局作用域
    window.$ = window.jQuery =  jQuery;
});

$.ready(function(){
    console.log(‘----设置id为test的元素文档内容,并获取文档内容----‘ + $(‘test‘).html(‘jQuery‘).html());
});

$.ready(function(){
    console.log(1);
});

$.ready(function(){
    console.log(2);
});

$.ready(function(){
    console.log(3);
});

var obj1 = {
    ball : {
        nba : ‘nba‘
    },
};

var obj2 = {
    ball : {
        cba : ‘cba‘
    }
};

var obj3 = {
    ball : {
        nba : ‘nba‘
    }
};

//扩展obj1
$.extend(obj1, obj2);
/**
 * {ball : {‘cba‘ : ‘cba‘}}
 */

//深度扩展obj3
$.extend(true, obj3, obj2);
/**
 * {ball : {‘nba‘ : ‘nba‘}, {‘cba‘ : ‘cba‘}}
 */
</script>
<body>
    <div id="test">my jQuery</div>
</body>
</html>
时间: 2024-10-27 12:03:27

jQuery源码浅析的相关文章

【深入浅出jQuery】源码浅析2--奇技淫巧

最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐进增强)优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹. 另外,阅读源码让我接触到了大量底层的知识.对原生JS .框架设计.代码优化有了全新的认识,接下来将会写一系列关于 jQuery 解析的文章. 我在 github 上关于 jQuery 源码的全文注解,感兴趣的可以围观一下

【深入浅出jQuery】源码浅析--整体架构(转)

最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐进增强)优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹. 另外,阅读源码让我接触到了大量底层的知识.对原生JS .框架设计.代码优化有了全新的认识,接下来将会写一系列关于 jQuery 解析的文章. 我在 github 上关于 jQuery 源码的全文注解,感兴趣的可以围观一下

【深入浅出jQuery】源码浅析--整体架构

最近一直在研读 jQuery 源码,初看源码一头雾水毫无头绪,真正静下心来细看写的真是精妙,让你感叹代码之美. 其结构明晰,高内聚.低耦合,兼具优秀的性能与便利的扩展性,在浏览器的兼容性(功能缺陷.渐进增强)优雅的处理能力以及 Ajax 等方面周到而强大的定制功能无不令人惊叹. 另外,阅读源码让我接触到了大量底层的知识.对原生JS .框架设计.代码优化有了全新的认识,接下来将会写一系列关于 jQuery 解析的文章. 我在 github 上关于 jQuery 源码的全文注解,感兴趣的可以围观一下

jQuery 源码学习 - 01 - 简洁的 $(&#39;...&#39;)

首先贴上学习参考资料:[深入浅出jQuery]源码浅析--整体架构,备用地址:chokcoco/jQuery-. jQuery 库,js 开发的一个里程碑,它的出现,让网页开发者们告别荒蛮的上古时代,初步解放生产力,正式进入黄铜时代. 虽然如今 Angular/React/Vue 三驾马车驰骋畋猎,jQuery的时代渐行渐远,但是它的思想它的设计都有着里程碑式的作用.当然,我是拿它来补基础的,逃... 1.自执行函数 (function(params) { // ... })(Variable)

jquery源码学习笔记(一)jQuery的无new构建

本人是一名.net程序员..... 你一个.net coder 看什么jQuery 源码啊? 原因吗,很简单.技多不压身吗(麻蛋,前端工作好高...羡慕). 我一直都很喜欢JavaScript,废话不多说了,直接切入正题. 最近看了好几篇jQuery 源码的文章,对于jQuery的无new构建  很是不解. 查了很多资料,总算是搞明白了. jQuery的无new构建 jQuery框架的核心就是从HTML文档中匹配元素并对其执行操作. 回想一下使用 jQuery 的时候,实例化一个 jQuery

五.jQuery源码解析之jQuery.extend(),jQuery.fn.extend()

给jQuery做过扩展或者制作过jQuery插件的人这两个方法东西可能不陌生.jQuery.extend([deep],target,object1,,object2...[objectN]) jQuery.fn.extend([deep],target,object1,,object2...[objectN])这两个属性都是用于合并两个或多个对象的属性到target对象.deep是布尔值,表示是否进行深度合并,默认是false,不执行深度合并.通过这种方式可以在jQuery或jQuery.fn

Volley框架源码浅析(一)

尊重原创http://blog.csdn.net/yuanzeyao/article/details/25837897 从今天开始,我打算为大家呈现关于Volley框架的源码分析的文章,Volley框架是Google在2013年发布的,主要用于实现频繁而且粒度比较细小的Http请求,在此之前Android中进行Http请求通常是使用HttpUrlConnection和HttpClient进行,但是使用起来非常麻烦,而且效率比较地下,我想谷歌正式基于此种原因发布了Volley框架,其实出了Voll

PM2源码浅析

PM2工作原理 最近在玩一个游戏,<地平线:黎明时分>,最终Boss是一名叫黑底斯的人,所谓为人,也许不对,黑底斯是一段强大的毁灭进程,破坏了盖娅主进程,从而引发的整个大陆机械兽劣化故事. 为什么要讲这么一段呢,是希望大家可以更好地理解pm2的原理,要理解pm2就要理解god和santan的关系,god和santan的关系就相当于盖娅和黑底斯在pm2中的01世界中,每一行代码每一个字节都安静的工作god就是Daemon进程 守护进程,重启进程,守护node程序世界的安宁,santan就是进程的

jquery源码学习

jQuery 源码学习是对js的能力提升很有帮助的一个方法,废话不说,我们来开始学习啦 我们学习的源码是jquery-2.0.3已经不支持IE6,7,8了,因为可以少学很多hack和兼容的方法. jquery-2.0.3的代码结构如下 首先最外层为一个闭包, 代码执行的最后一句为window.$ = window.jquery = jquery 让闭包中的变量暴露倒全局中. 传参传入window是为了便于压缩 传入undefined是为了undifined被修改,他是window的属性,可以被修