前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >jQuery源码浅析

jQuery源码浅析

作者头像
用户3094376
发布2018-09-12 11:04:35
8890
发布2018-09-12 11:04:35
举报
文章被收录于专栏:gaoqin31gaoqin31

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

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

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

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

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

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

废话少说,上滥代码

代码语言:javascript
复制
<!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>
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-07-21 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档