`
lcyangily
  • 浏览: 22353 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论

jQuery源码分析之数据存储

 
阅读更多

一.引子

    大家想想,在未使用jQuery或者其他js框架前,只用原生js的时候,怎么存储数据的呢?在刚结束js的时候,我是将每个跟节点有关的属性都使用setAttribute(name,value)保存在节点上。下次取就可以直接getAttribute(name),一个节点使用这种方式保存很多数据,效率肯定不高的。在有时候要对节点保存大量的数据的时候,还有没更好的办法来存储数据呢?下面来看看jQuery是如何做的。

 

二.原理

    jQuery数据的存储原理是:

1)定义了一个对象$.cache 保存所有数据

2)对每一个存储数据的DOM节点都对应一个数字index,这个DOM节点下的所有值都存储在$.cache(index)对象中(这么看是不是觉得$.cache是一个数组? 其实js中数组和对象很像,数组也是对象,对象就是一组属性的集合)。

3)对每一个存储数据的DOM节点都生成一个唯一的index。这个index值保存在节点的expando属性中。

4)expando是什么?就是每一个jQuery框架加载的时候内部生成的一个随机序列。这个序列一个jQuery加载完只有唯一一个。

 

让图片来更清楚的描述:



调用$(“#test”).data(“name”)时会先找到对象属性jQuery17102199497243038011($.expando)的值(当前为1),这个值就1就是上面说的index。对象所有存储的值都是放在$.cache[“1”]对象中。
下面代码可验证:
$("#test").data("abc", "def");
var cacheIndex = document.getElementById("test")[$.expando];  //获取index
//$.expando在1.2版本里访问不到,不能
var obj = $.cache[cacheIndex];
alert(obj["abc"]);  //def 注:这是jQuery1.6 前取值方式
//注: 在jquery1.7版本中对存储值有所改变。需要obj[“data”]["abc"]才能取到。也就是说$(“#test”).data(“abc”,”def”)不是存在上述obj对象中,而是存在obj[“data”]对象中(多了一层data对象,变得更深了)。

三.源码
下面来看代码是如何做到的:
jQuery.fn.extend({
  //扩展jQuery的对象方法data
  data: function( key, value ) {
    var parts, attr, name,data = null;
    //如果key没有,执行的操作
    if ( typeof key === "undefined" ) {
      if ( this.length ) {
        /**获取对象数组第一个元素的数据缓存cache
         * (该对象包含当前元素的所有存储的数据)
         */
        data = jQuery.data( this[0] );
        //元素节点
        if ( this[0].nodeType === 1 && !jQuery._data( this[0], "parsedAttrs" ) ) {
        	attr = this[0].attributes;
        	for ( var i = 0, l = attr.length; i < l; i++ ) {
        		name = attr[i].name;
        
        		if ( name.indexOf( "data-" ) === 0 ) {
        			name = jQuery.camelCase( name.substring(5) );
        
        			dataAttr( this[0], name, data[ name ] );
        		}
        	}
        	jQuery._data( this[0], "parsedAttrs", true );
        }
      }
      return data;
      
    } else if ( typeof key === "object" ) {
      return this.each(function() {
        jQuery.data( this, key );
      });
    }
    
    parts = key.split(".");
    parts[1] = parts[1] ? "." + parts[1] : "";
    
    //.data(name)格式,取值
    if ( value === undefined ) {
      data = this.triggerHandler("getData" + parts[1] + "!", [parts[0]]);
      
      // Try to fetch any internally stored data first
      if ( data === undefined && this.length ) {
        data = jQuery.data( this[0], key );
        data = dataAttr( this[0], key, data );
      }
      
      return data === undefined && parts[1] ?
        this.data( parts[0] ) :
        data;
    		
    //.data(name, value)格式,设置值
    } else {
      return this.each(function() {
        var self = jQuery( this ),
            args = [ parts[0], value ];

        //触发事件,如果对节点设置值绑定了事件,在做操作时触发事件
        self.triggerHandler( "setData" + parts[1] + "!", args );
        jQuery.data( this, key, value );
        self.triggerHandler( "changeData" + parts[1] + "!", args );
      });
    }
  }
});
 

下面是静态方法:

 

jQuery.extend({
  /** jQuery静态方法,算是data的核心了
    * jQuery很多都是这种模式,在静态方法里定义一个核心的处理方法
    * 在对象方法中定义用户操作的接口,就是API。
    * 如事件:$("#id").click(),$("xx").hover()等等。
    * 但最终处理都是调$("#id").on() 到最后是$.event.add()方法
    */
  data: function( elem, name, data, pvt /* Internal Use Only */ ) {
    //判断当前节点能不能存储数据
    if ( !jQuery.acceptData( elem ) ) {
      return;
    }

    var privateCache, thisCache, ret,
        internalKey = jQuery.expando,
        getByName = typeof name === "string",

      /**判断元素是否是DOM对象,如果是DOM对象才使用全局cache,普通js对象,直接增加属性即可.
        * DOM对象可以直接增加属性,为什么这个非得用全局对象呢?
        * 这主要是解决IE6-7浏览器垃圾回收对于js创建的DOM对象的属性不能回收
        * 验证方法:(使用sIEve 可看到有内存泄露)
        * function A() {
        *   var a = document.createElement("div");
        *   a["b"] = function(){};
        *   document.getElementById("test").appendChild(a);
        *   a.parentNode.removeChild(a);
        * }
        * A();
        */
        isNode = elem.nodeType,
        cache = isNode ? jQuery.cache : elem,
        //获取index
        id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey,
        isEvents = name === "events";

    // Avoid doing any more work than we need to when trying to get data on an
    // object that has no data at all
    if ( (!id || !cache[id] || (!isEvents && !pvt && !cache[id].data)) && getByName && data === undefined ) {
      return;
    }
    
    if ( !id ) {
      //为每一个存储数据在全局cache中的DOM节点分配一个唯一index
      if ( isNode ) {
        elem[ internalKey ] = id = ++jQuery.uuid;
      } else {
        id = internalKey;
      }
    }

    if ( !cache[ id ] ) {
      cache[ id ] = {};
      
      // Avoids exposing jQuery metadata on plain JS objects when the object
      // is serialized using JSON.stringify
      if ( !isNode ) {
        cache[ id ].toJSON = jQuery.noop;
      }
    }

    //如果name是对象或函数,继承里面所有方法.注意:这边为什么判断pvt ?
    if ( typeof name === "object" || typeof name === "function" ) {
      if ( pvt ) {
        cache[ id ] = jQuery.extend( cache[ id ], name );
      } else {
        cache[ id ].data = jQuery.extend( cache[ id ].data, name );
      }
    }

    privateCache = thisCache = cache[ id ];

    //要知道pvt是jQuery自己内部使用的,将保存用户和jQuery内部数据的保存分开了。
    //将我们设置的name/value值
    //放在了cache[id].data对象中,而jQuery内部数据直接放在了cache[id]中
    //好处不言而喻,将用户和jQuery框架的数据分开保存,避免了名称冲突
    //1.7版本之后才区分开.上面例子已经说了
    if ( !pvt ) {
      if ( !thisCache.data ) {
        thisCache.data = {};
      }
      
      thisCache = thisCache.data;
    }
    //存储数据
    if ( data !== undefined ) {
      thisCache[ jQuery.camelCase( name ) ] = data;
    }

    // Users should not attempt to inspect the internal events object using jQuery.data,
    // it is undocumented and subject to change. But does anyone listen? No.
    if ( isEvents && !thisCache[ name ] ) {
      return privateCache.events;
    }
    
    if ( getByName ) {
      ret = thisCache[ name ];
      if ( ret == null ) {
        ret = thisCache[ jQuery.camelCase( name ) ];
      }
    } else {
      ret = thisCache;
    }
    return ret;
  }
});
 

本章结束,有不对和不准确的地方望大家指正。有疑问欢迎留言。

 

  • 大小: 33.3 KB
分享到:
评论

相关推荐

    Jquery源码分析 源码

    《jQuery源码分析》 jQuery,作为一款广泛使用的JavaScript库,极大地简化了DOM操作、事件处理、动画制作以及Ajax交互。深入理解其源码对于提升JavaScript编程技能和优化前端性能至关重要。本文将从核心概念、设计...

    jQuery源码分析系列_1.6

    ### jQuery源码分析系列_1.6 #### 一、前言 在现代Web开发领域,jQuery无疑是一款具有里程碑意义的JavaScript库。它通过简洁、强大的API极大地简化了DOM操作、事件处理、Ajax交互以及动画等功能,使得前端开发变得...

    139.jQuery源码分析-魔术方法.rar

    《jQuery源码分析——魔术方法》 jQuery,作为一款广泛使用的JavaScript库,以其简洁的API和强大的功能赢得了开发者们的喜爱。在深入理解jQuery的工作原理时,我们常常会遇到一些“魔术方法”,这些方法在特定场景...

    jquery1.2.6源码分析rar + API

    《jQuery 1.2.6 源码分析与API详解》 jQuery 是一个广泛使用的JavaScript库,它极大地简化了JavaScript编程,使得DOM操作、事件处理、动画制作以及Ajax交互变得更加便捷。本篇文章将深入剖析jQuery 1.2.6版本的源码...

    JQUERY博客源码 JQUERY博客源码

    **jQuery博客源码详解** jQuery,作为一款广泛使用的JavaScript库,极大地简化了DOM...通过分析和实践这些源码,你可以深入了解jQuery的工作原理,提升你的前端开发技能,并能更好地构建高效、互动性强的博客系统。

    如何使用PHP+jQuery+MySQL实现异步加载ECharts地图数据(附源码下载)

    在本教程中,我们使用PHP作为服务器端编程语言,jQuery用于简化JavaScript的开发和进行异步HTTP请求(AJAX),MySQL作为数据库存储数据。整个流程可以概括为:前端通过jQuery发起AJAX请求,请求被发送至后端的PHP...

    jQuery+EasyUI实例源码

    总的来说,这个实例源码是学习jQuery和EasyUI结合使用的一个良好起点,通过阅读和理解代码,你可以掌握如何使用这两种工具来构建数据驱动的Web应用,实现CRUD操作。同时,也能了解到常见的三层架构在Web开发中的应用...

    jQuery 1.3 及其参考手册 源码分析

    **jQuery 1.3及其参考手册源码分析** jQuery是一个广泛使用的JavaScript库,极大地简化了JavaScript的DOM操作、事件处理、动画制作以及Ajax交互。在jQuery 1.3版本中,这一系列特性得到了进一步的优化和增强,为...

    锋利的jquery源码

    《锋利的jQuery源码》是一本专注于深入解析jQuery库的书籍,其第二版更是针对jQuery的最新版本进行了详尽的分析。这本书的核心是通过实际案例来帮助读者理解并掌握jQuery的内部工作原理,从而提升JavaScript开发技能...

    jquery 坦克大战源码

    《jQuery坦克大战源码解析与游戏开发技术探析》 jQuery坦克大战是一款基于JavaScript和jQuery库开发的在线游戏,它沿袭了经典FC游戏坦克大战的玩法,为玩家提供了丰富的娱乐体验。本篇文章将深入探讨该源码的技术...

    [精华]网站论坛源码C# Jquery,完全自制,有很多jquery自己写的插件

    2. 主题和帖子管理:C#处理数据存储和检索,Jquery实现动态加载和分页。 3. 评论和回复功能:C#处理用户互动,Jquery实现实时更新和通知。 4. 用户权限系统:C#实现角色和权限分配,Jquery可能用于前端权限展示和...

    jQueryAPI(附源码)

    `each()`函数遍历集合,`extend()`处理对象扩展,`data()`管理元素的数据存储。 ### 8. 性能优化 jQuery 1.3版本已经考虑了性能优化,如缓存DOM查询结果、批量操作DOM、避免内存泄漏等策略。随着版本迭代,jQuery...

    牛人写的jQuery1.26版的代码分析

    1. **选择器引擎Sizzle**:jQuery的核心之一是选择器引擎Sizzle,它实现了CSS1至CSS3的选择器,使我们能够用类似CSS的语法来选取DOM元素。例如,`$("#id")`选取ID为id的元素,`$(".class")`选取所有class为class的...

    jQuery 未压缩版本源码学习

    通过以上分析,我们可以看到jQuery未压缩版本源码的学习不仅涉及到了JavaScript的基础知识,还涵盖了DOM操作、字符串处理、浏览器兼容性等多个方面。这为我们深入理解和掌握jQuery的内部工作原理提供了宝贵的资料。

    jQuery源码分析-01总体架构分析

    《jQuery源码分析-总体架构解析》 在深入探究jQuery的源码之前,我们首先要理解其总体架构的设计理念。jQuery以其高效、易用的特性深受开发者喜爱,而这背后离不开其精心设计的架构。本文将围绕jQuery的核心构造...

    jQuery:jQuery 源码分析

    **jQuery: 深入理解与源码分析** jQuery 是一个广泛使用的 JavaScript 库,它极大地简化了 DOM 操作、事件处理、动画效果以及 AJAX 交互。jQuery 的流行在于其简洁的 API 和高效的代码实现,使得开发者能够用更少的...

    jQuery 源码分析笔记

    "jQuery 源码分析笔记"探讨了jQuery的核心设计和实现,特别是其如何简化JavaScript开发,并且深入研究了jQuery的源码结构。 jQuery的创建方式是一个自执行的匿名函数,这样做的好处在于它不会污染全局命名空间,...

    jquery源码

    《jQuery源码解析与经典应用探析》 jQuery,作为一款强大的JavaScript库,自诞生以来就深受开发者喜爱,它的简洁语法、高效的DOM操作以及丰富的插件生态,使得网页动态效果的实现变得轻而易举。本文将深入探讨...

    JQuery1.4 文档及源码

    本文将深入探讨 jQuery 1.4 版本,包括其核心特性、API 使用以及源码分析。 1. **jQuery 的核心理念** - **选择器**: jQuery 提供了丰富的 CSS 选择器,使得选取 HTML 元素变得简单。例如,`$("#id")` 用于选取 ID...

Global site tag (gtag.js) - Google Analytics