资讯专栏INFORMATION COLUMN

underscore.js 源码分析之 _.each() 函数

xbynet / 3197人阅读

摘要:遍历中的所有元素,按顺序用遍历输出每个元素。如果传递了参数,则把绑定到对象上。返回以方便链式调用。

each _.each(list, iteratee, [context]) Alias: forEach 
遍历list中的所有元素,按顺序用遍历输出每个元素。如果传递了context参数,则把iteratee绑定到context对象上。每次调用iteratee都会传递三个参数:(element, index, list)。如果list是个JavaScript对象,iteratee的参数是 (value, key, list))。返回list以方便链式调用。

_.each([1, 2, 3], alert);
=> alerts each number in turn...
_.each({one: 1, two: 2, three: 3}, alert);
=> alerts each number value in turn...

_.each 源码

  // The cornerstone, an `each` implementation, aka `forEach`.
  // Handles raw objects in addition to array-likes. Treats all
  // sparse array-likes as if they were dense.
  _.each = _.forEach = function(obj, iteratee, context) {
    iteratee = optimizeCb(iteratee, context);
    var i, length;
    if (isArrayLike(obj)) {
      for (i = 0, length = obj.length; i < length; i++) {
        iteratee(obj[i], i, obj);
      }
    } else {
      var keys = _.keys(obj);
      for (i = 0, length = keys.length; i < length; i++) {
        iteratee(obj[keys[i]], keys[i], obj);
      }
    }
    return obj;
  };

分析

_.each([1, 2, 3], alert); // _.each()使用方法,其中`alert`可以换成自己写的function

obj[1, 2, 3] , iterateealert , context 没有

iteratee = optimizeCb(iteratee, context);

首先是调用optimizeCb()函数

分析 optimizeCb 源码

var optimizeCb = function(func, context, argCount) {
    if (context === void 0) return func;
};

因为context 没有,所以这里直接返回alert , 所以 iteratee 现在是alert

再使用 isArrayLike 判断 传进来的obj是不是数组,判断数组的方法

//原理就是通过判断它是否具有长度且长度大于0且小于MAX_ARRAY_INDEX
var MAX_ARRAY_INDEX = Math.pow(2, 53) - 1;
var getLength = property("length");
var isArrayLike = function(collection) {
    var length = getLength(collection);
    return typeof length == "number" && length >= 0 && length <= MAX_ARRAY_INDEX;
  };

因为这里是数组,所以继续

// 通过 for 循环来遍历数组里面每一个值,传给 iteratee 函数来运行
for (i = 0, length = obj.length; i < length; i++) {
  iteratee(obj[i], i, obj); // 等于 alert(obj[i], i, obj);
}

如果不是数组呢?对象默认是没有length 属性的

var keys = _.keys(obj);
for (i = 0, length = keys.length; i < length; i++) {
  iteratee(obj[keys[i]], keys[i], obj);
}

使用了_.keys() 函数,下面分析 _keys() 源码

_.keys = function(obj) {
    if (!_.isObject(obj)) return [];
    if (nativeKeys) return nativeKeys(obj);
    var keys = [];
    for (var key in obj) if (_.has(obj, key)) keys.push(key);
    // Ahem, IE < 9.
    if (hasEnumBug) collectNonEnumProps(obj, keys);
    return keys;
};

首先使用_.isObject函数判断是不是对象

// Is a given variable an object?
  _.isObject = function(obj) {
    var type = typeof obj;
    return type === "function" || type === "object" && !!obj;
  };

首先判断传进来的参数的类型,然后返回true或者false

注意,通过以下两个例子可知, && 的优先级比 || 的高

console.log(true || false && false) // true
console.log(true || false && true) // true 

然后如果浏览器支持 ES5Object.keys 方法,就优先使用

nativeKeys = Object.keys,

不支持就继续遍历循环 对象

var keys = [];
// own enumerable properties
for (var key in obj)
// hasOwnProperty
if (_.has(obj, key)) keys.push(key);

使用了 _.has() 函数,下面解析_.has()函数

// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
  return obj != null && hasOwnProperty.call(obj, key);
};

通过判断 传进来的obj 是否为null 并且调用hasOwnProperty 方法判断该对象是否有该键值

hasOwnProperty   = ObjProto.hasOwnProperty = Object.prototype.hasOwnProperty;

如果有该属性,返回true ,这时回到_.keys() ,该简直pushkeys[]

// IE9以下不能用 for in 来遍历,所以使用collectNonEnumProps()函数来解决问题,暂时可以不看
if (hasEnumBug) collectNonEnumProps(obj, keys);

这时已经把对象转化成数组了,回到_.each() 函数,继续使用for 循环遍历数组 ,把参数传递给alert函数

for (i = 0, length = keys.length; i < length; i++) {
  iteratee(obj[keys[i]], keys[i], obj); //  等于 alert(obj[keys[i]], keys[i], obj);
}

最后再返回obj

整个分析_.each() 函数,相继分析了_.has()_.keys() 函数,大概看了一下underscore.js 的源码,感觉不是太难,一个函数一个函数分析就好。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/80826.html

相关文章

  • 学习 underscore 源码整体架构,打造属于自己的函数式编程类库

    摘要:译立即执行函数表达式处理支持浏览器环境微信小程序。学习整体架构,利于打造属于自己的函数式编程类库。下一篇文章可能是学习的源码整体架构。也可以加微信,注明来源,拉您进前端视野交流群。 前言 上一篇文章写了jQuery整体架构,学习 jQuery 源码整体架构,打造属于自己的 js 类库 虽然看过挺多underscore.js分析类的文章,但总感觉少点什么。这也许就是纸上得来终觉浅,绝知此...

    junnplus 评论0 收藏0
  • underscore源码学习(一)

    摘要:所以,刚开始,我从源码比较短的包含注释只有行开始学习起。一般,在客户端浏览器环境中,即为,暴露在全局中。学习以后判断直接使用看起来也优雅一点滑稽脸。在的函数视线中,的作用执行一个传入函数次,并返回由每次执行结果组成的数组。 前言 最近在社区浏览文章的时候,看到了一位大四学长在寻求前端工作中的面经,看完不得不佩服,掌握知识点真是全面,无论是前端后台还是其他,都有涉猎。 在他写的文章中,有...

    gclove 评论0 收藏0
  • underscore 0.1.0版本源码阅读

    摘要:前面的的目的在于利用自定义抛出错误令遍历停止如果是数组直接过滤输出不是数组遍历操作压入数组返回有点像,过滤符合条件的注意感叹号取反有点像设置默认迭代器判断是否存在即需要所有元素都满足迭代条件。 前言 这篇文章是为之后的underscore现版本的源码做铺垫,先感受下最先版本 0.1.0版本足够小 这个版本已经有将近小10年的历史了 还是有一些不错的地方。 0.1.0版本源码分析 ...

    Coly 评论0 收藏0
  • underscore.js 源码解读】常用类型判断以及一些有用的工具方法

    摘要:最近开始看源码,并将源码解读放在了我的计划中。今天就跟大家聊一聊中一些常用类型检查方法,以及一些工具类的判断方法。用是否含有属性来判断工具类判断方法接下来看下一些常用的工具类判断方法。 Why underscore 最近开始看 underscore.js 源码,并将 underscore.js 源码解读 放在了我的 2016 计划中。 阅读一些著名框架类库的源码,就好像和一个个大师对话...

    tanglijun 评论0 收藏0
  • Underscore源码中文注释(转)

    摘要:创建一个全局对象在浏览器中表示为对象在中表示对象保存下划线变量被覆盖之前的值如果出现命名冲突或考虑到规范可通过方法恢复被占用之前的值并返回对象以便重新命名创建一个空的对象常量便于内部共享使用将内置对象的原型链缓存在局部变量方便快速调用将 // Underscore.js 1.3.3 // (c) 2009-2012 Jeremy Ashkenas, DocumentCloud Inc....

    Guakin_Huang 评论0 收藏0

发表评论

0条评论

xbynet

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<