jQuery源码学习

来源:互联网 发布:小企业做账软件 编辑:程序博客网 时间:2024/06/07 03:16

分离构造器

分离构造器几个关键点:



  1. jQuery = function( selector, context ) {
    return new jQuery.fn.init( selector, context );
    },
  2. init.prototype = jQuery.fn;

    上面实现了构造器的分离,通过jQuery对象选择到的对象的构造器是jQuery原型上的init方法,this指向的也是这个原型方法返回来的对象this,而不是jQuery构造器中的this,使得返回的这个this不能访问到jQuery原型上的方法。

    但是通过第二条,可以把他们链接起来,使得返回的this可以访问jQuery原型上的方法。

function aQuery(select){        this.select=select;        return new aQuery.prototype.init(select);    }    aQuery.prototype={        init:function(select){            this.select=select;            return this;        },        optionSelect:function(){            document.getElementById(this.select).innerHTML='mzz';        }    }    aQuery.prototype.init.prototype=aQuery.prototype;    var aquery=aQuery('mzz').optionSelect();

分离构造器有什么不一样呢?
我们写构造函数一般都没有分离,故通过构造函数创建的对象不但能访问他的原型上的方法,还能访问在构造器上的属性方法,而分离构造器的结果使得创建的对象不能访问构造器的属性方法。

插件接口设计

  1. 两种接口扩展方式,一个在构造器上,另一个在原型上
  2. 他们的区别是方法挂在的this指向不同,由于前面的构造器分离,会使他们的使用也有区别。
function aQuery(select){        this.select=select;        return new aQuery.prototype.init(select);    }    aQuery.prototype={        init:function(select){            this.select=select;            return this;        },        optionSelect:function(){            document.getElementById(this.select).innerHTML='mzz';            return this;        },        extend:function(json){            var option=json,                target={};            target=this;                for(name in option){                target[name]=option[name];            }            return target;        }    }    function add(){        return this.a+this.b;    };    function setNum(a,b){        this.a=a;        this.b=b;        return this;    }    aQuery.prototype.init.prototype=aQuery.prototype;    var aquery=aQuery('mzz').optionSelect().extend({add:window.add,setNum:window.setNum}).setNum(4,5);    console.log(aquery.add());//9

回调设计

发布订阅模式两个平行的数组,一个用于存放回调函数,另一个用于存放对应函数的一个包含调用上下文和需要的参数对象。

下面是源码的一部分:体现出两个平行的数组list和queue;

fired = firing = true;for ( ; queue.length; firingIndex = -1 ) {    memory = queue.shift();    while ( ++firingIndex < list.length ) {        if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&            options.stopOnFalse ) {            firingIndex = list.length;            memory = false;        }    }}

jQuery里面的回调对象设置了一些配置参数比如
1. once,
2. memory,保持以前的值,将添加到这个列表的后面的最新的值立即执行调用任何回调 (像一个递延 Deferred),
3. unique,
4. stopOnFalse

模拟jQuery实现如上功能(jQuery内部用extend扩展,且内部也是相当于给构造函数扩展的,我就直接当成构造函数的方法写了)

aQuery.callbacks=function(options){        var queue=[];        var memory;        return {            add:function(fn){                if(options==='unique'){                    for(var i=0;i<queue.length;i++){                        if(fn===queue[i]){                            return this;                        }                    }                }                queue.push(fn);                return this;            },            fire:function(data){                var memory = options==='memory'&&data;                for(var i=0;i<queue.length;i++){                    var stopFase=queue[i].call(null,memory);                    if(options==='stopFase'){                        if(stopFase===false){                            return;                        }                    }                }                if(options==='once'){                    queue=[];                }            }        }    }    var callback=aQuery.callbacks('unique').add(window.sda).add(window.sda).add(window.ads);    callback.fire();    callback.fire();    function sda(){        console.log('xxx');        return false;    }    function ads(){        console.log('sss');    }

deferred

  1. 一个可链式操作的对象,提供多个回调函数的注册,以及回调列队的回调,并转达任何异步操作成功或失败的消息。

  2. 管道风格then:我们可以把每一次的then操作,当做是创建一个新的deferred对象,那么每一个对象都够保存自己的状态与各自的处理方法。通过一个办法把所有的对象操作都串联起来,这就是then或者pipe管道设计的核心思路了

模拟这种管道风格:

function aDeferred() {    var arr = [];    return {        then: function(fn) {            arr.push(fn)            return this;        },        resolve: function(args) {            var returned;            arr.forEach(function(fn, i) {                var o = returned || args;                returned = fn(o)            })        }    }}var d = aDeferred();d.then(function(preVale) {    return 2 * preVale //4}).then(function(preVale) {    return 3 * preVale //12}).then(function(preVale) {    console.log(preVale);});d.resolve(2)//结果输出的值为12;

学习缓存机制的思考

关于dom与js对象循环引用造成内存泄漏问题只是在采用了引用计数的垃圾回收机制有这要的问题,2008年之后由于浏览器采用了标记清除的垃圾回收机制,这个问题就没有了;

所谓标记清除:从引用根节点开始标记所有被引用的对象,第二阶段遍历整个堆,把未标记的对象清除。

内存泄漏问题理解:

  1. 轻度浏览器刷新会被回收
  2. 由循环引用造成的即使刷新也不会是内存减少的理解:

    是因为由于循环引用问题,刷新也不能使前面循环引用的对象销毁,即使新页面加载进来了并且重新渲染了。
    但只是在循环引用回收机制的IE老版本浏览器中或者使用了COM对象中存在这个问题

  3. 那现在的在DOM上直接绑定数据还会造成循环引用吗?

    这种说法只是说绑定的数据多了可能会造成内存泄漏的问题,数据多也是看在内存的数据,内存的数据爆了当然会内存泄漏,这种内存泄漏就算不是在自定义标签上绑定数据,直接在js里存超出内存容量的数据的话,也会造成内存泄漏问题。

0 0