jQuery 源码解析

jQuery的无new构建

先看下一下初始想法

var aQuery = function(selector, context) {
        //构造函数
}
aQuery.prototype = {
    //原型
    name:function(){},
    age:function(){}
}

var a = new aQuery();

a.name();

由上可知,这样写会导致每个jQuery需要new一次,而真正的jQuery并不需要这样
所以这样尝试一下

var aQuery = function(selector, context) {
       return new aQuery();
}
aQuery.prototype = {
    name:function(){},
    age:function(){}
}

虽然return 出来了一个实例,然而这次直接进入死循环了


在javascript中实例this只跟原型有关系

可以把jQuery类当作一个工厂方法来创建实例,把这个方法放到jQuery.prototye原型中。在原型中使用this指向构造函数,返回原型中构造出的新实例,解决了死循环问题

var aQuery = function(selector, context) {
       return  new aQuery.prototype.init();
}
aQuery.prototype = {
    init: function() {
        this.age = 18
        return this;
    },
    name: function() {},
    age: 20
}

但是构造函数变了,那绑定在aQuery上的公有属性和方法不都没了吗?(即aQuery.prototype.init.prototype为空)

由上可知,可以通过原型链解决这个问题。

var aQuery = function(selector, context) {
       return  new aQuery.prototype.init();
}
aQuery.prototype = {
    init: function() {
        return this;
    },
    name: function() {
        return this.age
    },
    age: 20
}

aQuery.prototype.init.prototype = aQuery.prototype;
核心是jQuery.prototype.init.prototype = jQuery.prototype;

链式调用

代码可以采用链式调用,即$().show().hide();
想要使用链式调用,每个函数返回的结果必须是执行完毕后的对象

aQuery.prototype = {
    init: function() {
        return this;
    },
    name: function() {
        return this
    }
}

插件接口

如果要为jQuery或者jQuery prototype添加属性方法,同样如果要提供给开发者对方法的扩展,从封装的角度讲是不是应该提供一个接口才对,字面就能看懂是对函数扩展,而不是看上去直接修改prototype.友好的用户接口
jQuery设置了jQuery.fn === jQuery.prototype

jQuery.extend = jQuery.fn.extend = function() {}
  • jQuery.extend 调用的时候,this是指向jQuery对象的(jQuery是函数,也是对象),所以这里扩展在jQuery上。
  • 而jQuery.fn.extend 调用的时候,this指向fn对象,jQuery.fn 和jQuery.prototype指向同一对象,扩展fn就是扩展jQuery.prototype原型对象。
  • 这里增加的是原型方法,也就是对象方法了。所以jQuery的api中提供了以上2中扩展函数。

推荐阅读更多精彩内容