开发者社区> 虫师2016> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

jQuery源码-美元背后的一点小技巧

简介:
+关注继续查看

写在前面:本文比较基础,仅是一枚菜鸟接触jquery过程中的一点思考和总结,内容较基础,希望能对刚接触jQuery的童鞋有一点帮助 :)   

按照国际惯例(其实就是俺写作的习惯),首先抛出待问题的场景。至于问题的答案,文章并不会急着揭晓,而是通过逐层递进的方式,展现思考、解决一个问题的过程

 

1、如何给一个id为casper的标签添加一个名为“world”的class

考虑下面一个场景,假设我们页面上有个id为casper的div标签,如下所示



<div id="casper" class="hello">casper是个大傻瓜,啦啦啦啦啦</div>

现在我们想要给它添加一个class,比如“world”,用jquery的话如何实现?很简单,不卖关子



$('#casper').addClass('world');

很好,接下来我们思考:如何不用jquery,我们如何如何实现实现上述功能?最简单的方式:

var node = document.getElementById('casper');
node.className += ' world'; 

getElementById、getElementsByTagName神马的,名字老长老长的,写着有点不爽,于是把getElementById这个方法用美元($)包装下:



function $(id){
  return document.getElementById(id);
}

$('casper').className += ' world';

className品字符串神马的,jquery的调用方式相比麻烦多了,那再改进下:

function $(id){
    var node = document.getElementById(id);
    node.addClass = function(addName){
        node.className += ' ' + addName;
    };
    return document.getElementById(id);
}
$('casper').addClass('world');

看上去挺像那么一回事了,多优雅的接口啊(热泪盈眶中)~

真的是这样吗,再仔细瞧瞧?于是果断发现不对劲的地方:对于$,每次调用,都会给返回的dom元素上添加一个addClass方法,这对空间来说是极大的浪费。当然,可以将addClass方法抽取出来:

function addClass(className){
    //实现略
}
function $(id){
    var node = document.getElementById(id);
    node.addClass = addClass;
    return document.getElementById(id);
}
$('casper').addClass('world');

原先的空间浪费问题可以在很大程度上得到解决,但明显这解决方法还不够好。如果有那么一种实现方式,让所有的对象实例都共享一个方法。。。

 

2、jQuery中的实现思路

同样不必卖关子,这里说的就是原型方法,我们再看下jquery的调用方式



$('#casper').addClass('world');

$('#casper')并不是像我们上面那样,简单地将id为casper的元素返回。实际上,$('#casper')返回的是一个jQuery对象,该对象特征如下:

  1. 拥有一个length属性,length等于你调用$选中的元素的数目,在$('#casper')中为1
  2. 拥有0~n-1的实例属性,分别对应调用$时选中的第1~第n个元素,如本例中$('#casper')[0]即为目标dom元素
  3. 拥有一堆原型方法,如常见的addClass、removeClass、bind等

根据上面三点,很容易对我们之前写的代码进行修改,如下:

function $(id){
    this[0] = document.getElementById(id);
    this.length = 1;
}
$.prototype.addClass = function(className){
    this[0].className += ' ' + className;
};

var noode = new $('casper');
node.addClass('world');

其实就几行代码的事情,但。。。还是觉得有些不对劲,new $('casper'),平常在用jquery的时候似乎不需要new一下的说,想想看,我们代码中一坨new是多么可怕的事情~

好吧,其实是因为jQuery帮你完成了构造函数调用的这部分工作,这一小小的细节改善对jQuery的流行起到了很大的帮助。按照这个思路,继续修改之前的代码:

function $(id){
    if(!(this instanceof $) return new $(id);    //加了这么个语句
    this[0] = document.getElementById(id);
    this.length = 1;
}

//其他一样,节省空间不贴代码

在上面的代码中,只有一点小小的修改,就是加了个判断语句 if(!(this instanceof $)) ,作用在于判断,当$被调用时,究竟是采用以下两种调用方式的哪一种,关于这种判断方式,可参考之前写的《【经验总结】构造函数的强制调用》

  1. $('casper'),直接调用,于是this为window
  2. new $('casper'),此时$为构造方法,this instanceof $ == true

 

3、jQuery中的源码实现以及问题所在(俺的疑惑)

罗嗦了这么多,我们看看关于这点,jQuery里是如何实现的,源码大致如下,一些不相干的代码略过:

(function( window, undefined ) {

//去掉无关变量声明等,防止干扰分析
var jQuery = (function() {

    // Define a local copy of jQuery
    var jQuery = function( selector, context ) {
        // The jQuery object is actually just the init constructor 'enhanced'
        return new jQuery.fn.init( selector, context, rootjQuery );
    },

    //一堆无关细节暂时略过

    jQuery.fn = jQuery.prototype = {
        constructor: jQuery,
        init: function( selector, context, rootjQuery ) {
            //继续略过
        }
    };
    // Give the init function the jQuery prototype for later instantiation
    jQuery.fn.init.prototype = jQuery.fn;

    return jQuery;

})();

window.jQuery = window.$ = jQuery;

})( window );

对于研究过jQuery源码或曾经打算研究jQuery源码的同学来说,上面这段代码肯定不会陌生,它有一个特点:看上去比较晦涩,特别是是结合了jQuery源码里面比较诡异的代码缩进~

通过闭包返回的jQuery对象,闭包里面是有jQuery函数定义,jQuery函数里面return了new jQuery.fn.init 。。。快速看懂上面这段代码的秘诀在于:一个支持代码高亮和职能中括号匹配的编辑器,比如webstorm。。。

上面只是开个小玩笑,绕了这么久,无法是想做下面几件事情:

  1. 无论有没有new,只要调用$,都给你返回一个jQuery对象(实际上jQuery.fn.init才是实际的构造函数)
  2. 将jQuery.fn.init.fn指向jQuery.prototype,这样的话,当我们通过$.fn.newPrototypeAttr 方式向jQuery添加原型属性或方法,其实最终都成为了jQuery.fn.init地原型属性或方法
  3. 将constructor属性指向jQuery,不然$('#casper').constructor 获得的会是jQuery.fn.init

 

个人觉得上面这段代码有些费解,似乎完全可以采用相对不那么曲折的方式实现,如下所示,其实思路都是相同的:

然后,就是添加各种原型方法了,兼容性处理和优雅的API,这块才是精华,这里还没讲到。

(function(){

    var jQuery = function(id){
        return new _jquery(id);
    };

    var _jquery = function(id){
        //此处各种选择分支神马的都忽略~
        this[0] = document.getElementById(id);
        this.length = 1;
    };

    jQuery.fn = jQuery.prototype = {
        constructor: jQuery,
        addClass: function(className){
            this[0].className += ' ' + className;
        }
    };

    _jquery.prototype = jQuery.fn;

    window.$ = window.jQuery = jQuery;

})();

 

问题:jQuery源码的那种实现方式,至今不明白作用在哪?是有其他的考虑??知道的筒子往不吝赐教! 

 

写在后面:

  文中示例如有错漏,请指出;如觉得文章对您有用,可点击“推荐” :)

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
Dynatable – 基于 HTML5 & jQuery 的交互表格插件
  Dynatable 一款有趣的,语义化,交互式的表格插件,使用 jQuery,HTML5 和 JSON 实现。Dynatable 的目的是提供一种简单的、可扩展的 API,能够轻松的浏览和操作大规模的数据集。
1227 0
Web 开发最有用的50款 jQuery 插件集锦——《图片特效篇》
  《Web 开发最有用的50款 jQuery 插件集锦》系列文章向大家分享最具创新的50款 jQuery 插件,这些插件分成以下类别:网页布局插件,导航插件,表格插件,滑块和转盘插件,图表插件,图片特效插件,视频插件等等,将陆续分享给大家,记得关注和收藏啊。
1038 0
Lazy Load, 延迟加载图片的 jQuery 插件【备忘】
http://www.neoease.com/lazy-load-jquery-plugin-delay-load-image/   jQuery Unveil – 另一款非常轻量的延迟加载插件 http://luis-almeida.github.io/unveil/
727 0
43个多图片轮转jquery插件
在网页设计中,在一个有限的空间中让用户可以通过左右滚动的方式来浏览多张图片,是我们常用到的一种控件。下面我们将为您介绍43个多图片轮换播放jQuery教程和插件。 1. rCarousel 2.
1120 0
jQuery Unveil – 另一款非常轻量的延迟加载插件
  jQuery Unveil 是一款轻量的延迟加载插件,支持提供用于视网膜显示设备的高分辨率图像。这个插件非常有用,它能提高长网页中图像的加载性能,因为视口以外的图像(可见部分网页)将不会被加载,直到用户滚动到它们所在的区域。
695 0
星级评分jquery插件
星级评分jquery插件 分享几个星型评级插件   1)jRating 是一个非常灵活的jQuery插件用于快速创建一个Ajax星型投票系统。
748 0
【精心挑选】10款基于 jQuery 的图片360度旋转插件
  之前的文章向大家分享了实现网站功能的各种优秀的 jQuery 插件,今天这篇文章向大家推荐10款基于 jQuery 的图片360度旋转插件,同时还有非常详细的制作教程可以学习和参考。图片旋转展示是一种非常有趣的技术,通过把多张图片合并在一起让你可以实现360度浏览,这种效果常用于旅游网站或者酒店网站,用于展示风景或者房间的内景。
1062 0
jquery插件整理篇(七)表格插件
(1)Flexigrid Flexigrid是一个类似于Ext Gird,但基于jQuery开发的Grid。它具有的功能包括:可以调整列宽,合并列标题,分页,排序,显示/隐藏表格等。Flexigrid显示的数据能够通过Ajax获取或者从一个普通的表格转换。
899 0
推荐18款非常棒的 jQuery 表格插件
  我们一般都是用HTML表格来显示结构化数据,如今有很多的 jQuery 表格插件可以帮助我们更好的组织和控制表格数据,增强表格的功能和操作。今天要与大家分享的是18个非常优秀的 jQuery 表格插件,有用到朋友可以参考一下。
1344 0
+关注
虫师2016
专注于软件测试技术的分享与推广
204
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载