我爱编程前端

JQuery源码简单分析

2017-07-31  本文已影响0人  whitsats

JQuery源码分析

我们通过对jQuery1.4.2版本的分析,了解jQuery原理

最外层

(function(window,undefined){

    })(window)
  1. 将代码放到匿名函数中,用闭包的特性,防止过多的变量污染到全局
  2. 将window传递到自身的AO上,不用跳到全局寻找,速度更快
  3. 函数形参使用undefined,避免ie6/7情况下关键字undefined可复制的现象,保证函数的运行

选择器

初始化代码

var jQuery = function( selector, context ) {
        return new jQuery.fn.init( selector, context );
        //调用fn属性的init方法
    }
    //定义$和Jquery 使用noConflict方法让出$的控制权
    //定义正则表达式用于解析selector
    //定义方法,基于Object和Array的原型
    //init方法
    //将$和Jquery暴露在全局中

Jquery作为一个方法,传入选择器和文本

jQuery.fn = jQuery.prototype = {
    init: function( selector, context ) {
        if ( typeof selector === "string" ) {
            //通过定义好的正则和方法对传入的selector进行判断,确定传入值是html或者id,如果传入的为html,则创建dom对象,如果为类或者伪类选择器,或者为表达式,则选择对象,返回包装后的dom元素
        }
        //定义Jq方法,属性
    }
}
jQuery.fn.init.prototype = jQuery.fn;

jQuery只是一个普通函数,未定义prototype的情况下,原生的prototype应为Object;

定义jQuery中的fn属性,并且将jQuery的prototype指向该对象,为了确保Jquery在实例化的同时直接通过原型使用其中的方法.

但是我们在全局中使用$()时,只是对jQuery.fn.init进行了实例化,并未对jQuery进行实例化,所以,我们设置jQuery.fn.init.prototype = jQuery.fn,其实就是定义jQuery.fn.init.prototype = jQuery.prototype,表达的意思就是jQuery.fn.init的实例化对象就等价于jQuery的实例化对象,他们公用的方法和属性都存在于jQuery.fn中.

jquery.png
It gives the init() function the same prototype as the jQuery object. So when you call init() as a constructor in the "return new jQuery.fn.init( selector, context );" statement, it uses that prototype for the object it constructs. This lets init() substitute for the jQuery constructor itself

保障我们在使用Jquary.fn.init实例化的对象时,可以直接调用JQuery.fn中的属性.

独立选择器

Jquery的选择器被称之为sizzle选择器,我们仿照源码写一个选择器

(function(window,undefined){
    window.$ = window.JQuery;
    var JQuery = function(selector){
        return new JQuery.fn.init(selector)
    }
    jQuery.fn = {
        init:function(selector){
            var rs = null;
            
            this.length = null;

            if(selector.substr(0,1) == '#') { // ID选择器
                rs = document.getElementById(selector.slice(1));
            } else if(selector.substr(0,1) == '.') { // 类选择器
                rs = document.getElementsByClassName(selector.slice(1));
            } else { // 标签选择器
                rs = document.getElementsByTagName(selector);
            }

            if(rs !== null && rs.length ===undefined) {
                this[0] = rs;
                this.length = 1;
            } else if(rs !== null && rs.length !==undefined){
                for(var i=0; i<rs.length; i++) {
                    this[i] = rs[i];
                }
                this.length = rs.length;
            }

            return this;
        }
    }
    })(window)

CSS方法

我们如果去除刚刚所写的jQuery.fn = jQuery.prototypejQuery.fn = jQuery.fn.init.prototype,在/代码块上直接添加css方法,方法不能正常使用

(function(window,undefined){
    window.$ = window.JQuery;
    var jQuery = function(selector){
        return new JQuery.fn.init(selector)
    }
    jQuery.fn = {
        css:function(){
            alert(3)
        }
        init:function(selector){
            //...
        }
    }
    })(window)

这是因为我们返回值是JQuery.fn.init的实例化对象,该对象只能访问自身或者原型上的属性和方法,所以我们只需要将JQuery.fn.init的原型指向jQuery.fn,即可在全局访问css方法

(function(window,undefined){
    window.$ = window.JQuery;
    var JQuery = function(selector){
        return new JQuery.fn.init(selector)
    }
    jQuery.fn = {
        css : function(attr , value) {
            for(var i=0; i<this.length; i++) {
                this[i].style[attr] = value;
            }
        },
        init:function(selector){
            //...
        }
    }
    jQuery.fn.init.prototype = jQuery.fn;
    })(window)

方法的扩展

(function(window,undefined){
    window.$ = window.JQuery;
    var JQuery = function(selector){
        return new JQuery.fn.init(selector)
    }
    JQuery.fn = {
        css:function(attr , value) {
            for(var i=0; i<this.length; i++) {
                this[i].style[attr] = value;
            }
        },
        attr:function(attr , value) {
            for(var i=0; i<this.length; i++) {
                this[i][attr] = value;
            }
        },
        init:function(selector){
            //...
        }
    }
    JQuery.fn.init.prototype = JQuery.fn;
    })(window)

我们的库完成并发布后,用户如何扩展?

我们需要给用户提供一个接口,用于扩展库的功能 -> 使用复制继承

(function(window,undefined){
    window.$ = window.JQuery;
    var JQuery = function(selector){
        return new JQuery.fn.init(selector)
    }
    JQuery.fn = {
        extend:function(obj) {
            for(var k in obj) {
                this[k] = obj[k];
            }
        },
        init:function(selector){
            //...
        }
    }
    JQuery.fn.init.prototype = JQuery.fn;
    })(window)

此后,我们就可以在jQuery外部书写方法,复制继承给fn对象,通过init初始化访问而不改变原内核.

(function(window,undefined){
    window.$ = window.JQuery;
    var JQuery = function(selector){
        return new JQuery.fn.init(selector)
    }
    JQuery.fn = {
        extend:function(obj) {
            for(var k in obj) {
                this[k] = obj[k];
            }
        },
        init:function(selector){
            //...
        }
    }
    JQuery.fn.init.prototype = JQuery.fn;
    JQuery.fn.extend({
        html : function(val) {
            for(var i=0; i<this.length; i++) {
                this[i].innerHTML = val;
            }
        }
    });
    })(window)

同理,函数也可以看作为对象,所以我们可以将属性挂载在JQuery本身上

(function(window,undefined){
    window.$ = window.JQuery;
    var JQuery = function(selector){
        return new JQuery.fn.init(selector)
    }
    JQuery.fn = {
        init:function(selector){
            //...
        }
    }
    JQuery.fn.init.prototype = JQuery.fn;
        JQuery.extend = JQuery.fn.extend = function(obj){
        for(var k in obj) {
            this[k] = obj[k];
        }
    };
    JQuery.fn.extend({
        html : function(val) {
            for(var i=0; i<this.length; i++) {
                this[i].innerHTML = val;
            }
        }
    });
    JQuery.extend({
        get:function(url,succ)
            var xhr = new XMLHttpRequest();
            xhr.onreadystatechange = function(){
                if(this.readyState == 4){
                    succ(this.responseText)
                }
            }
            xhr.open('get',url,true);
            xhr.send(null)
        })
    })(window)

从事实上来说

jQuery.extend(object)     为扩展jQuery类本身.为类添加新的方法。 

jQuery.fn.extend(object)  给jQuery对象添加方法。 
上一篇 下一篇

猜你喜欢

热点阅读