zoukankan      html  css  js  c++  java
  • JQuery的结构Dive into jQuery

    JQuery的结构-Dive into jQuery

     

    原文参考:http://www.splashnology.com/article/the-structure-of-jquery-dive-into-source-code/2517/

    Jquery很流行了,那么它到底是怎么构造的,记得一位老师说过“结构是宝,一懂百了;结构不懂,一窍不通”。这句话深深地在我脑海里。。。。。

    总体结构

    1 (function( window, undefined ) {
    2 var document = window.document,
    3 navigator = window.navigator,
    4 location = window.location;
    5
    6 [...] // 主要的代码部分
    7
    8 window.jQuery = window.$ = jQuery;
    9 })(window);

    核心

     1 var jQuery = (function () {
    2 var jQuery = function ( selector, context ) {
    3 return new jQuery.fn.init( selector, context, rootjQuery );
    4 };
    5 // jQuery的映射,防止被重写
    6 _jQuery = window.jQuery,
    7
    8 // $的映射,防止被重写
    9 _$ = window.$,
    10
    11 rootjQuery,
    12
    13 [...]
    14
    15 rootjQuery = jQuery(document);
    16
    17 [...]
    18
    19 return jQuery;
    20 })();

    这里,可以看出jQuery的构造函数,要了解如何防止重写,需要进一步的查看jQuery.noConflict (),rootjQuery一个参考document的jQuery对象,对于rootjQuery没有很明白。

    接下来是一系列的正则表达式,在浏览器检测,解析Json,和jQuery.trim中需要用到。现代的浏览器支持字符串的.trim方法,还有数组的indexof方法,jQuery进行了本地的实现。

    1 trim = String.prototype.trim,
    2 indexOf = Array.prototype.indexOf,

    对象的构建

    进入到jQuery最“神圣”的地方,这一块是对那些没有使用过的人来说最难的地方。所以我们需要保持清醒的头脑,jQuery原型的神奇之处也就藏在这里。你已经在核心中见过它了:

    1 var jQuery = function( selector, context ) {
    2 //jQuery对象实际上是init构造器的‘加强’
    3 return new jQuery.fn.init( selector, context, rootjQuery );
    4 },

    这其实意味着,当你调用jQuery函数的时候,“jQuery.fn.init”被创建并且返回。这就是JavaScript函数式编程的体现。在下面的代码中,我们可以看到:

     1 jQuery.fn = jQuery.prototype = {
    2 constructor: jQuery,
    3 init: function( selector, context, rootjQuery ) {
    4 [...]
    5 }
    6 [...]
    7 }
    8
    9 //在以后的实例中把 jQuery的原型给给init函数
    10 jQuery.fn.init.prototype = jQuery.fn;

    到这里,我们知道了jQuery.fn就是jQuery.prototype。这会帮助我们理清下面的东西。

    同时,jQuery.fn.init.prototype也指向了jQuery.prototype(第10行代码的作用), jQuery.fn.init.prototype 构造器指向了jQuery(第10行代码使得使得jQuery.fn.init.prototype指向jQuery.fn, 而第2行中jQuery.fn的构造器是jQuery).

    这就会得到一个有趣的结果:

    1 $(document) instanceof jQuery; // true
    2 $(document) instanceof jQuery.fn.init; // true

    为了更好的理解这种行为,下面给了一个简单的例子:

     1 var Init = function () {
    2 console.log('[Init]');
    3 };
    4
    5 var jQuery = function () {
    6 console.log('[jQuery]');
    7 return new Init();
    8 };
    9
    10 Init.prototype = jQuery.prototype = {
    11 constructor: jQuery
    12 };
    13
    14 var $elem = jQuery(); // [jQuery] , [Init]
    15
    16 console.log( $elem instanceof jQuery ); // true
    17 console.log( $elem instanceof Init ); // true

    因此,所有的构造都在jQuery.fn.init这个对象的函数中,jQuery是jQuery.fn.init对象的一个工厂。

    解析参数

    有很多方式使用jQuery函数

    1 $(function () { alert('READY!') }); // 当加载一个dom元素时,函数将被执行
    2 $(document.getElementById('test')); // link on the element
    3 $('<div />'); // 创建新元素
    4 $('<div />', { title: 'test' }); //创建带属性的新元素
    5
    6 // 支持所有想得到的和想不到的css选择器
    7 $('#element'); // id为element的元素
    8 $('.element', $previous ); // 在前面的$中找到所有class为element的元素
    9 $("div[name=city]:visible:has(p)");

    让我们看一看构造器中的代码,我们已经知道构造器就是jQuery.fn.init.下面给出的是伪代码:

     1 init: function( selector, context, rootjQuery ) {
    2 if ( !selector ) return this;
    3
    4 // 处理 $(DOM元素)
    5 if ( selector.nodeType ) return this = selector;
    6
    7 // body元素只存在一个,找到它的优化方法
    8 if ( selector === "body" && !context ) return this = document.body;
    9
    10 if ( jQuery.isFunction( selector ) ) {
    11 return rootjQuery.ready( selector );
    12 }
    13
    14 // 处理 HTML 字符串
    15 if ( typeof selector === "string" ) {
    16 // 验证一个匹配,并且在上下文中没有元素#id
    17 if ( selector.match(quickExpr) ) {
    18 if ( match[1] ) {
    19 return createNewDomElement( match[1] );
    20 } else {
    21 return getById( match[2] )
    22 }
    23 } else {
    24 return jQuery( context ).find( selector );
    25 }
    26 }
    27 },

    前4中处理条件很有清楚的--对于空的选择器,DOM元素选择器以及body字符串的处理和为DomReady做的函数处理。

    一个有趣的点是,当扫描一行时,最先解析的是“快速正则表达式”,而这个式子的左边是匹配tag标记的,其后才是匹配id元素。

    1 quickExpr = /^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]*)$)/;

    只有request很复杂的情况下,才调用find方法,利用搜索引擎来寻找元素。Sizzle (Copyright The Dojo Foundation).

    组件开发

    专业写JavaScript的人都知道,利用JS的原型创建class,很容易继承。

     1 var MyClass = function () {
    2 // 构造器
    3 };
    4
    5 MyClass.prototype = {
    6 // 原型
    7 };
    8
    9 var instance = new MyClass();
    10
    11 // 我们可以继承class的原型,并且在新的特性也可以添加到它的所有实例中,及时是已经创建的实例
    12
    13 MyClass.prototype.plugin = function () {
    14 console.log("He's alive!");
    15 };
    16
    17 instance.plugin(); // He's alive!

    同样的方法,我可以也可以继承标准的jQuery原型:

    1 jQuery.prototype.plugin = function () {
    2 // 这里是我的组件
    3 };

    正如我们上面提到了,fn就是一个到jQuery.prototype的链接,我们还可以这样简洁的写:

    1 jQuery.fn.plugin = function () {
    2 // 这里是我的组件
    3 // 这里指向的是jQuery对象,方法调用也是来自jQuery对象
    4 };

    这个组件将会出现在那些已经实现或者以后将要实现的实例中。用下面的方法直接向对象添加静态属性:

    1 jQuery.plugin = function () {
    2 // 这里是我的组件
    3 };

    所以写组件的最好结构是:

     1 new function (document, $, undefined) {
    2
    3 var privateMethod = function () {
    4 // 私有方法, 只对组件用
    5 };
    6
    7 $.fn.myPlugin = function () {
    8
    9 };
    10
    11 // 如果需要,一个没有绑定dom元素的方法
    12 $.myPlugin = function () {
    13
    14 };
    15
    16 }(document, jQuery);

    这种方法可以再jQuery的大多数组件中看到。例如, DatePicker.

    结论

    在作者看来,jQuery的流行在于它的简单性和易用性,还有简短的名称,比如用css代替setStyle,attr代替setAttribute等。这种想法很简单,也迷住了很多人。

    人们往往能看到很多jQuery的“克隆”们,或者是一些想法在其他语言中运用。简单也是有欺骗性的,它也不总是好的。所以在你把方法名称缩短之前一定要三思,因为有可能就是它们会造成不必要的错误。


    ps:对jQuery的用法不熟悉,为了学习它的结构才写的这东西,有不正确的地方一定要指正。谢谢!

  • 相关阅读:
    【总结】st表
    【luogu】p2024 食物链
    【总结】stl(以后还会慢慢补上
    【总结】二叉堆
    【luogu】p1631 序列合并
    才子们博客地址
    Lemon测评软件使用说明 (对比cena)
    Cena编译器的使用 及任大佬和禚大佬解释(O2优化、C++11特性、开栈)值得大家学习
    编程求100内的素数
    【关于德育和道德方面】
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2412006.html
Copyright © 2011-2022 走看看