【学习笔记】jQuery的实现原理

JQuery是用于操作页面元素的便捷之道,里面封装了兼容各个浏览器的hack 处理,在幅DOM操作的运用环境中引用jQuery作为辅助工具将会是一个很不错的选择。
一、诞生
在没有jQuery之前要获取DOM元素非常的繁琐:

1querySelector2querySelectorAll3)getElementById4)getElementsByTagName5)getElementsByClassName
var btn= document.getElementById("btn");
    var text =  document.getElementById("text");
    btn.onclick = function (e) {
        text.style.display = "none";
    }

以上操作相比jQuery$(“.name”)的结构而言,是不是非常的方便的。
所以就会想要将以上的选择器如ID选择器等进行封装:

var $ = function (id) {
        return document.getElementById(id);
    }
    $("btn").onclick = function (e) {
       $("text").style.display = "none";
    }

上面的代码经过改装后可以实现一样的效果,但是上面的隐藏操作还是比较复杂,因而可以进一步进行封装这样需要隐藏元素的时候直接调用hide即可代码量。因为隐藏需要在特定的元素上进行操作,不能像上面直接进行function,利用原型对象进行封装扩展。

function F(id) {
        this.ele = document.getElementById(id);
    }
    F.prototype.hide = function () {
        this.ele.style.display = "none";
    }
    var text = new F("text");
    var btn= document.getElementById("btn");
    btn.onclick = function () {
        text.hide();
    }

上面封装的不够完善,获取元素的属性的方法私有没有被共享(继承),所以应该将获取元素的方法写到原型上:

function F(id) {
       return  this.getElementById(id);
    }
    F.prototype.getElementById = function (id) {
        this.ele = document.getElementById(id);
        return this;
    }
    F.prototype.hide = function () {
        this.ele.style.display = "none";
    }
    var btn = document.getElementById("btn");
    btn.onclick = function (e) {
        new F("text").hide();
    }

有人说我不想调用的时候还来new一下,想要直接利用$的方式进行调用,所以又有如下的改进方式:

var $ = function(id){
  return new F(id);
 }
function F(id) {
       return  this.getElementById(id);
    }
    F.prototype.getElementById = function (id) {
        this.ele = document.getElementById(id);
        return this;
    }
    F.prototype.hide = function () {
        this.ele.style.display = "none";
    }
    var btn = document.getElementById("btn");
    btn.onclick = function (e) {
          $("text").hide();
    }

以上的方法中值能够通过id的方式获取到元素,所以应该要继续进行扩展:

 var $ = function(selector,context){
        return new F(selector,context);
    }
    function F(selector,context) {
        return  this.getNodeList(selector,context);
    }
    F.prototype.getNodeList = function (selector,context) {
        context = context || document;
        this.element= context.querySelectorAll(selector);
        return this;
    }

    F.prototype.hide = function () {
        var len = this.element.length;
        for(var i =0; i< len ;i++){
            this.nodeList[0].style.display = "none";
        }
    }
    var btn = document.getElementById("btn");
    btn.onclick = function (e) {
        $("#text").hide();
    }

由于querySelectorAll获取的是元素列表所以需要进行遍历操作,当元素如果还有显示的操作时,那就有需要使用一次遍历,对于多个地方重复的代码最好是使用封装,所以再给原型添加一个each的方法:

 var $ = function(selector,context){
        return new F(selector,context);
    }
    function F(selector,context) {
        return  this.getNodeList(selector,context);
    }
    F.prototype.getNodeList = function (selector,context) {
        context = context || document;
        this.element= context.querySelectorAll(selector);
        return this;
    }
   F.prototype.each = function (fn) {
        var len = this.element.length;
       for(var i =0;i<len ;i++){
           fn.call(this.nodeList[i]);
       }
   }
    F.prototype.hide = function () {
       this.each(function () {
           this.style.display = "none";
       })
    }
    var btn = document.getElementById("btn");
    btn.onclick = function (e) {
        $("#text").hide();
    }

上面的初始化时还是和jQuery有些不一样,其中多了element的属性,同时不能直接利用$()[0]这样下标的方式进行访问元素成员,而是需要以$().element[0]的形式进行访问,所以还需要进行改进,使得this直接成为类数组对象:

var $ = function(selector,context){
        return new F(selector,context);
    }
    function F(selector,context) {
        return  this.init(selector,context);
    }
    F.prototype.init = function (selector,context) {
        context = context || document;
        var nodeList = context.querySelectorAll(selector);
        this.length = nodeList.length;
        for (var i=0; i<nodeList.length; i+=1) {
            this[i] = nodeList[i];
        }
        return this;
    }
    F.prototype.each = function (fn) {
        var len = this.length;
        for(var i =0;i<len ;i++){
            fn.call(this[i]);
        }
    }
    F.prototype.hide = function () {
        this.each(function () {
            this.style.display = "none";
        })
    }
    var btn = document.getElementById("btn");
    btn.onclick = function (e) {
        $("#text").hide();
    }

还没结束哦!!!!继续将F进行替换:

 var $ = function(selector,context){
        return new $.fn(selector,context);
    }
    $.fn =function (selector,context) {
        return  this.init(selector,context);
    }
    $.fn.prototype.init = function (selector,context) {
        context = context || document;
        var nodeList = context.querySelectorAll(selector);
        this.length = nodeList.length;
        for (var i=0; i<nodeList.length; i+=1) {
            this[i] = nodeList[i];
        }
        return this;
    }
    $.fn.prototype.each = function (fn) {
        var len = this.length;
        for(var i =0;i<len ;i++){
            fn.call(this[i]);
        }
    }
    $.fn.prototype.hide = function () {
        this.each(function () {
            this.style.display = "none";
        })
    }
    var btn = document.getElementById("btn");
    btn.onclick = function (e) {
        $("#text").hide();
    }

同时上面的代码每次都会看到prototype的身影,能不能继续改进能:

 var $ = function(selector,context){
        return new F(selector,context);
    }
    F =function (selector,context) {
        return  this.init(selector,context);
    }
    $.fn = F.prototype;
    $.fn.init = function (selector,context) {
        context = context || document;
        var nodeList = context.querySelectorAll(selector);
        this.length = nodeList.length;
        for (var i=0; i<nodeList.length; i+=1) {
            this[i] = nodeList[i];
        }
        return this;
    }
    $.fn.each = function (fn) {
        var len = this.length;
        for(var i =0;i<len ;i++){
            fn.call(this[i]);
        }
    }
    $.fn.hide = function () {
        this.each(function () {
            this.style.display = "none";
        })
    }
    var btn = document.getElementById("btn");
    btn.onclick = function (e) {
        $("#text").hide();
    }

不过还是和jQuery有些不一样,多了一个多余的F,而 function$.fn=F.prototype$.fn=$.prototype 对象上的,初始化的希望将$将对象进行实例化这样外面就不需要在new了,如果直接:

 var $ = function(selector,context){
        return new $(selector,context);
    }
    $.fn = $.prototype;
    $.fn.init = function (selector,context) {
        context = context || document;
        var nodeList = context.querySelectorAll(selector);
        this.length = nodeList.length;
        for (var i=0; i<nodeList.length; i+=1) {
            this[i] = nodeList[i];
        }
        return this;
    }

利用上诉方式将会导致循环引用出错,所以在jQuery中利用了他的属性init方法作为构造函数,结合原型链达到效果:

 var $ = function(selector,context){
        return new $.fn.init(selector,context);
    }
    $.fn = $.prototype;
    $.fn.init.prototype = $.fn;//这一步非常关键,如果没有这一步上面new之后返回的是init的实例,将会是一个空的实例,利用此处使得返回的对象将会继承$的所有属性,以及下面的each等方法。
    $.fn.init = function (selector,context) {
        context = context || document;
        var nodeList = context.querySelectorAll(selector);
        this.length = nodeList.length;
        for (var i=0; i<nodeList.length; i+=1) {
            this[i] = nodeList[i];
        }
        return this;
    }
    $.fn.each = function (fn) {
        var len = this.length;
        for(var i =0;i<len ;i++){
            fn.call(this[i]);
        }
    }
    $.fn.hide = function () {
        this.each(function () {
            this.style.display = "none";
        })
    }
    var btn = document.getElementById("btn");
    btn.onclick = function (e) {
        $("#text").hide();
    }

上面就是jQuery的基本思想和原理,纯属本人理解,如有不对之处请指出,以便相互学习!!!!
参考链接:http://www.cnblogs.com/kidney/p/5879255.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值