原型方法map跟each类似调用的是同名静态方法,只不过返回来的数据必须经过另一个原型方法pushStack方法处理之后才返回,源码如下:

  1. map: function( callback ) {
  2. return this.pushStack( jQuery.map(this, function( elem, i ) {
  3. return callback.call( elem, i, elem );
  4. }));
  5. },

本文主要就是分析静态map方法至于pushStack在下一篇随笔里面分析;

首先了解下map的使用(手册内容)

$.map将一个数组中的元素转换到另一个数组中。

作为参数的转换函数会为每个数组元素调用,而且会给这个转换函数传递一个表示被转换的元素作为参数。

转换函数可以返回转换后的值、null(删除数组中的项目)或一个包含值的数组,并扩展至原始数组中。

参数

arrayOrObject,callbackArray/Object,FunctionV1.6

arrayOrObject:数组或者对象。

为每个数组元素调用,而且会给这个转换函数传递一个表示被转换的元素作为参数。

函数可返回任何值。

另外,此函数可设置为一个字符串,当设置为字符串时,将视为“lambda-form”(缩写形式?),其中 a 代表数组元素。

如“a * a”代表“function(a){ return a * a; }”。

示例1:

  1. //将原数组中每个元素加 4 转换为一个新数组。
  2.  
  3. //jQuery 代码:
  4.  
  5. $.map( [0,1,2], function(n){
  6. return n + 4;
  7. });
  8. //结果:
  9.  
  10. [4, 5, 6]

示例2:

  1. //原数组中大于 0 的元素加 1 ,否则删除。
  2.  
  3. //jQuery 代码:
  4.  
  5. $.map( [0,1,2], function(n){
  6. return n > 0 ? n + 1 : null;
  7. });
  8. //结果:
  9.  
  10. [2, 3]

示例3:

  1. //原数组中每个元素扩展为一个包含其本身和其值加 1 的数组,并转换为一个新数组
  2.  
  3. //jQuery 代码:
  4.  
  5. $.map( [0,1,2], function(n){
  6. return [ n, n + 1 ];
  7. });
  8. //结果:
  9.  
  10. [0, 1, 1, 2, 2, 3]

可以看出map方法跟each方法类似通过循环每个对象或者数组的“项”执行回调函数来实现对数组或者对象的操作,但是这两个方法也有很多不同点

比如each()返回的是原来的数组,并不会新创建一个数组,而map则会创建新的数组,;each遍历是this指向当前数组或对象值,map则指向window,因为在源码中并不像each那样使用对象冒充;

例如:

  1. var items = [1,2,3,4];
  2. $.each(items, function() {
  3. alert('this is ' + this);
  4. });
  5. var newItems = $.map(items, function(i) {
  6. return i + 1;
  7. });
  8. // newItems is [2,3,4,5]
  9.  
  10. //使用each时,改变的还是原来的items数组,而使用map时,不改变items,只是新建一个新的数组。
  11.  
  12. var items = [0,1,2,3,4,5,6,7,8,9];
  13. var itemsLessThanEqualFive = $.map(items, function(i) {
  14. // removes all items > 5
  15. if (i > 5)
  16.   return null;
  17.   return i;
  18. });
  19. // itemsLessThanEqualFive = [0,1,2,3,4,5]

言归正传回到map源码

  1. // arg is for internal usage only
  2. map: function( elems, callback, arg ) {
  3. var value, key, ret = [],
  4. i = 0,
  5. length = elems.length,
  6. // jquery objects are treated as arrays
  7. isArray = elems instanceof jQuery || length !== undefined && typeof length === "number" && ( ( length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems ) ) ;
  8.  
  9. // Go through the array, translating each of the items to their
  10. if ( isArray ) {
  11. for ( ; i < length; i++ ) {
  12. value = callback( elems[ i ], i, arg );
  13.  
  14. if ( value != null ) {
  15. ret[ ret.length ] = value;
  16. }
  17. }
  18.  
  19. // Go through every key on the object,
  20. } else {
  21. for ( key in elems ) {
  22. value = callback( elems[ key ], key, arg );
  23.  
  24. if ( value != null ) {
  25. ret[ ret.length ] = value;
  26. }
  27. }
  28. }
  29.  
  30. // Flatten any nested arrays
  31. return ret.concat.apply( [], ret );
  32. },

首先还是声明几个变量为接下来的遍历做准备,其中jsArray变量用来简单区分对象和数组,这个布尔复合表达式比较长不过只要记住js运算符的有优先顺序就不难理解了,首先括号优先执行然后就是逻辑与》逻辑或》全等》赋值,然后就可以分析啦

首先圆括号里先计算然后结果加上 length !== undefined 、 typeof length === "number这两个必要条件最后的结果再跟elems instanceof jQuery进行逻辑或的运算,简单的说就是isArray为真的情况有:

1、elems instanceof jQuery  为true 换言之就是jquery对象

2、length !== undefined && typeof length === "number" 和  length > 0 && elems[ 0 ] && elems[ length -1 ] ) || length === 0 || jQuery.isArray( elems )这三个至少成立一个

可以拆分为3个小情况

length是存在并且是数字而且待遍历的数组或者类数组等length属性大于0 length-1存在  这样就保证了是能遍历的,比如对于jquery对象  domList对象等

length是存在并且是数字而且length属性等于0  如果是0也没关系就是不会遍历

length是存在并且是数字而且待遍历对象是纯数组

满足这些条件之后开始根据isArray的结果分开遍历,对于“数组”采用for循环,对于对象采用for...in循环

  1. // Go through the array, translating each of the items to their
  2. if ( isArray ) {
  3. for ( ; i < length; i++ ) {
  4. value = callback( elems[ i ], i, arg );
  5.  
  6. if ( value != null ) {
  7. ret[ ret.length ] = value;
  8. }
  9. }

是数组或者类数组的时候直接把循环的每一项的值和指针以及arg参数传入回调函数中执行,arg参数是此方法内部使用的参数,跟each以及一些其他jquery方法很相似,只要在执行回调函数时不返回null就把执行返回的结果添加到新数组中,对象操作亦是如此直接略过

  1. // Flatten any nested arrays
  2. return ret.concat.apply( [], ret );

最后将结果集扁平化,为什么有这一步呢?因为map是可以扩展数组的在前面第3个示例就是如此:

  1. $.map( [0,1,2], function(n){
  2. return [ n, n + 1 ];
  3. });

如果是这样使用的话得到的新数组是一个二维数组,所以必须降维

  1. ret.concat.apply( [], ret )等价于[].concat.apply([],ret)关键作用的是apply,因为apply的第二个参数把ret的数组分成多个参数传入给concat把二维数组转化为一维数组这个用法还是值得收藏的的
    map方法简单分析完毕,能力有限错误之处望多多指正。

jquery原型方法map的使用和源码分析的更多相关文章

  1. jQuery原型属性constructor,selector,length,jquery和原型方法size,get,toArray源码分析

    首先看一下在jQuery1.7.1中定义的原型属性和方法有哪些? init方法作为实际的构造函数已经详细分析过了,需要了解可以参考http://www.cnblogs.com/yy-hh/p/4492 ...

  2. jQuery静态方法inArray,grep,merge,makeArray方法使用和源码分析

    inArray方法 确定第一个参数在数组中的位置,从0开始计数(如果没有找到则返回 -1 ). 示例: var arr = [ 4, "Pete", 8, "John&q ...

  3. Quartz学习--二 Hello Quartz! 和源码分析

    Quartz学习--二  Hello Quartz! 和源码分析 三.  Hello Quartz! 我会跟着 第一章 6.2 的图来 进行同步代码编写 简单入门示例: 创建一个新的java普通工程 ...

  4. jQuery 2.1.4版本的源码分析

    jQuery 2.1.4版本的源码分析 jquery中获取元素的源码分析 jQuery.each({// 获取当前元素的父级元素 parent: function(elem) { var parent ...

  5. Android Debuggerd 简要介绍和源码分析(转载)

    转载: http://dylangao.com/2014/05/16/android-debuggerd-%E7%AE%80%E8%A6%81%E4%BB%8B%E7%BB%8D%E5%92%8C%E ...

  6. Java并发编程(七)ConcurrentLinkedQueue的实现原理和源码分析

    相关文章 Java并发编程(一)线程定义.状态和属性 Java并发编程(二)同步 Java并发编程(三)volatile域 Java并发编程(四)Java内存模型 Java并发编程(五)Concurr ...

  7. Kubernetes Job Controller 原理和源码分析(二)

    概述程序入口Job controller 的创建Controller 对象NewController()podControlEventHandlerJob AddFunc DeleteFuncJob ...

  8. Kubernetes Job Controller 原理和源码分析(三)

    概述Job controller 的启动processNextWorkItem()核心调谐逻辑入口 - syncJob()Pod 数量管理 - manageJob()小结 概述 源码版本:kubern ...

  9. Kubernetes Job Controller 原理和源码分析(一)

    概述什么是 JobJob 入门示例Job 的 specPod Template并发问题其他属性 概述 Job 是主要的 Kubernetes 原生 Workload 资源之一,是在 Kubernete ...

随机推荐

  1. Linux下如何删除Oracle

    一. 停止Oracle数据库服务 shutdown immediate 二. 停止监听服务 lsnrctl stop 三. 用dbca卸载数据库实例 四. 删除相关文件  -->> 如果只 ...

  2. Example of BeanFactoryAware in Spring--转

    原文地址:http://www.concretepage.com/spring/example_beanfactoryaware_spring If a bean in spring implemen ...

  3. Fragment响应返回键

    Activty可以直接响应返回键,而Fragment却不行,可用如下方式: 创建一个抽象类BackHandledFragment,该类中有一个抽象方法onBackPress(),所有BackHandl ...

  4. Wee – 为现代 Web 开发打造的 CSS 脚手架

    Wee 包含许多开发人员在搭建响应的,互动的网站和应用程序时需要的组件.正如它的名字一样,Wee 是一个微小.移动优先的 CSS 复位框架.Wee 组织在一个简单的.可扩展的层次结构,拥有一致的样式和 ...

  5. 输入URL之后都发生了什么

    输入URL之后都发生了什么 这个标题印象中已经有很多讨论了.也来说说这个话题. 从头开始,当你的电脑使用网线连接到网络的时候,我们都知道,这个时候你的电脑会获取一个IP,这个IP就是你的唯一标识了.好 ...

  6. C#多线程技术总结(异步)

    我这里针对现有的C#多线程技术进行一个汇总,一是复习,二是方便索引,文章部份知识点来源于网络,非本人原创. 一.并行(异步): 1.System.Threading.Tasks命名空间下的(TPL): ...

  7. Newtonsoft.Json 的序列化与反序列化

    首先补充一点,Json.Net是支持序列化和反序列化DataTable,DataSet,Entity Framework和NHibernate的.我举例说明DataTable的序列化和反序列化.创建一 ...

  8. LINQ的Expression与delegate表达式

    Linq的delegate表达式,Insus.NET觉得它封装得好,让开发时简化了很多代码,而且容易阅读与检索. 比如,我们需要计算优惠给客户金额,打85%折,可以这样写: using System; ...

  9. 浅谈你感兴趣的 C# GC 机制底层

    本文内容是学习CLR.via C#的21章后个人整理,有不足之处欢迎指导. 昨天是1024,coder的节日,我为自己coder之路定下一句准则--保持学习,保持自信,保持谦逊,保持分享,越走越远. ...

  10. 介绍开源的.net通信框架NetworkComms框架 源码分析(二)ConnectionInfo

    原文网址: http://www.cnblogs.com/csdev Networkcomms 是一款C# 语言编写的TCP/UDP通信框架  作者是英国人  以前是收费的 目前作者已经开源  许可是 ...