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

来源:互联网 发布:ssh建立连接的端口号 编辑:程序博客网 时间:2024/06/05 20:57

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

原创粉丝点击