分类导航

Underscore.js 源码学习笔记(上)

发布时间:2019-11-07 发布网站:大佬教程
大佬教程收集整理的这篇文章主要介绍了Underscore.js 源码学习笔记(上)大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

版本 Underscore.js 1.9.1

一共 1693 行。注释我就删了,太长了…

整体是一个 () {...}());  这样的东西,我们应该知道这是一个 IIFE(立即执行函数)。

<div class="cnblogs_code">

 root =  self == 'object' && self.self === self && self ||
     global == 'object' && global.global === global && global ||
     ||

获取当前运行环境根对象。

在浏览器中为 self(=window)  在服务端中是 global 在一些虚拟机中是 this

<div class="cnblogs_code">

 previousUnderscore = root._;

如果环境中已经定义了同名变量,防止对其造成覆盖,先把这个变量缓存起来。

<div class="cnblogs_code">

 ArrayProto = Array.prototype,ObjProto = SymbolProto =  Symbol !== 'undefined' ? Symbol.prototype : <span style="color: #0000ff;">var push =<span style="color: #000000;"> ArrayProto.push,slice =<span style="color: #000000;"> ArrayProto.slice,toString =<span style="color: #000000;"> ObjProto.toString,hasOwnProperty =<span style="color: #000000;"> ObjProto.hasOwnProperty;

<span style="color: #0000ff;">var nativeIsArray =<span style="color: #000000;"> Array.isArray,nativeKeys =<span style="color: #000000;"> Object.keys,nativeCreate = Object.create;

定义一些变量来存储 JS 定义的对象原型和方法,以便后续使用。

<div class="cnblogs_code">

 Ctor = (){};

根据注释,这个裸函数是用来代理原型交换的?英文不好……后面应该可以看到用处,不急。

<div class="cnblogs_code">

 _ =  (obj  _)  (!(  _))  ._wrapped =

_ 是一个构造函数,传入的对象如果已经是 _ 实例就直接返回

我们知道当我们通过 new foo() 创建对象时会创建一个新的对象,然后将它的原型链绑定为 foo.propotype ,然后把这个对象作为 foo 调用的this,如果 foo 没有返回值的话,就返回这个对象。

所以通过    _  可以判断是否是构造调用(是否加 new)如果不是的话 就手动加一个 new 调用一次。

通过foo生成一个对象,他有一个属性  的值是传入的obj。

<div class="cnblogs_code">

 ( exports != 'undefined' && ! ( module != 'undefined' && !module.nodeType &&= module.exports ===

因为 node 环境中会有 exports 变量,由此判断是在浏览器还是服务端。服务端的话就导出 _ ,否则在根元素上添加 _ 变量。

<div class="cnblogs_code">

_.VERSION = '1.9.1';

版本号

<div class="cnblogs_code">

 optimizeCb =  (context ===  0)  (argCount ==  ? 3 1:  
     3:   4:   

其实这个函数可以简化成

optimizeCb =

所以说这就相当于实现了一个 bind 。  

那为什么要分那么多情况呢?因为   比  慢,而且某些情况下,还会慢很多

至于  0 是什么,void + 表达式会返回 undefined 这个算常识吧。而不使用 undefined 因为在某些老的浏览器中 undefined 可以被赋值,出于兼容性考虑。

<div class="cnblogs_code">

<span style="color: #0000ff;">var cb = <span style="color: #0000ff;">function<span style="color: #000000;">(value,argCount) {
<span style="color: #0000ff;">if (.iteratee !== builtinIteratee) <span style="color: #0000ff;">return<span style="color: #000000;"> .iteratee(value,context);
<span style="color: #0000ff;">if (value == <span style="color: #0000ff;">null) <span style="color: #0000ff;">return .identity; <span style="color: #008000;">//<span style="color: #008000;"> .identity 函数: value => value
<span style="color: #0000ff;">if (.isFunction(value)) <span style="color: #0000ff;">return<span style="color: #000000;"> optimizeCb(value,argCount);
<span style="color: #0000ff;">if (
.isObject(value) && !.isArray(value)) <span style="color: #0000ff;">return<span style="color: #000000;"> .matcher(value);
<span style="color: #0000ff;">return<span style="color: #000000;"> _.property(value);
};

_.iteratee = builtinIteratee = <span style="color: #0000ff;">function<span style="color: #000000;">(value,context) {
<span style="color: #0000ff;">return<span style="color: #000000;"> cb(value,Infinity);
};

这个看到有点懵比……

首先  就是一个用来判断   是否被用户改变的临时变量,没有其他用处。

  是一个函数 默认返回 cb

cb 作为操作集合的函数的回调函数使用

如果   被修改就调用修改后的函数

如果   就返回   一个传入什么就返回什么的函数

如果 value 是函数 就返回   也就是  

如果 value 是对象 且不是数组 就返回   

以上都不符合就返回  

<div class="cnblogs_code">

_.isMatch =  keys = _.keys(attrs),length = (object == )  ! obj = ( i = 0; i < length; i++ key = (attrs[key] !== obj[key] || !(key  obj))   .matcher = .matches = <span style="color: #0000ff;">function<span style="color: #000000;">(attrs) {
attrs
=<span style="color: #000000;"> .extendOwn({},attrs);
<span style="color: #0000ff;">return
<span style="color: #0000ff;">function
<span style="color: #000000;">(obj) {
<span style="color: #0000ff;">return
<span style="color: #000000;"> .isMatch(obj,attrs);
};
};
<span style="color: #008000;">//
<span style="color: #008000;"> e.g.

<span style="color: #0000ff;">var
isZhangsan = _.matcher({ firstname: 'san',lastname: 'zhang'<span style="color: #000000;"> });

console.log(isZhangsan({ firstname: 'san',lastname: 'zhang',age: 55 })); <span style="color: #008000;">//<span style="color: #008000;"> true
<span style="color: #000000;">
console.log(isZhangsan({ firstname: 'si',lastname: 'zhang' })); <span style="color: #008000;">//<span style="color: #008000;"> false

好了 现在知道不是正序写的了 哭唧唧 先不看   是什么鬼东西了 反正看名字肯定是一个扩展对象的函数

首先看 isMatch ,  相当于  ,  就是判断 attrs 中的 key 是否在 object 中都存在且对应的值都相等。

那么   就是设定 attrs 返回函数。返回的函数传入 obj 看其是否符合 attrs。

<div class="cnblogs_code">

 shallowProperty =   obj ==  ?  0<span style="color: #0000ff;">var deepGet = <span style="color: #0000ff;">function<span style="color: #000000;">(obj,path) {
<span style="color: #0000ff;">var
length =<span style="color: #000000;"> path.length;
<span style="color: #0000ff;">for
(<span style="color: #0000ff;">var
i = 0; i < length; i++<span style="color: #000000;">) {
<span style="color: #0000ff;">if
(obj == <span style="color: #0000ff;">null) <span style="color: #0000ff;">return <span style="color: #0000ff;">void 0<span style="color: #000000;">;
obj =<span style="color: #000000;"> obj[path[i]];
}
<span style="color: #0000ff;">return length ? obj : <span style="color: #0000ff;">void 0<span style="color: #000000;">;
};

.property = <span style="color: #0000ff;">function<span style="color: #000000;">(path) {
<span style="color: #0000ff;">if (!<span style="color: #000000;">
.isArray(path)) {
<span style="color: #0000ff;">return<span style="color: #000000;"> shallowProperty(path);
}
<span style="color: #0000ff;">return <span style="color: #0000ff;">function<span style="color: #000000;">(obj) {
<span style="color: #0000ff;">return<span style="color: #000000;"> deepGet(obj,path);
};
};

如果传入的不是数组,就返回获取对象属性path的值的函数,如果传入一个数组,就返回获取对象属性[path]对应的值的函数。

<div class="cnblogs_code">

 restArguments = = startIndex ==  ? func.length - 1 : +  length = Math.max(arguments.length - startIndex,0== 0 (; index < length; index++= arguments[index + 0:  func.call( 1:  func.call(,arguments[0 2:  func.call(,arguments[0],arguments[1 args = Array(startIndex + 1 (index = 0; index < startIndex; index++== func.apply(

相当于 ES6 的剩余参数,从  开始的所有参数当做一个数组传入。分情况使用 call 还是上面提到的效率问题。

使用举例:

arr.reduce((previous,current) => previous +<span style="color: #0000ff;">var restArgumentsWrapperSum =<span style="color: #000000;"> restArguments(sum);

console.log(restArgumentsWrapperSum(1,2,3));

<div class="cnblogs_code">


<span style="color: #0000ff;">var baseCreate = <span style="color: #0000ff;">function<span style="color: #000000;">(prototype) {
<span style="color: #0000ff;">if (!_.isObject(prototype)) <span style="color: #0000ff;">return<span style="color: #000000;"> {};
<span style="color: #0000ff;">if (nativeCreate) <span style="color: #0000ff;">return<span style="color: #000000;"> nativeCreate(prototype);
Ctor.prototype =<span style="color: #000000;"> prototype;
<span style="color: #0000ff;">var result = <span style="color: #0000ff;">new<span style="color: #000000;"> Ctor;
Ctor.prototype = <span style="color: #0000ff;">null<span style="color: #000000;">;
<span style="color: #0000ff;">return<span style="color: #000000;"> result;
};

相当于手动实现了一个   利用了上面不知道什么用空函数 Ctor 。

  Ctor 没有加括号,在构造调用的时候,如果不传入参数,可以不加括号。相当于   Ctor() 。

  就是创建一个对象 对象的 [[Prototype]] 为 foo.prototype,这里通过 new 实现。结束之后再将 Ctor 的 protottype 赋值为 null 。

<div class="cnblogs_code">

 shallowProperty =   obj ==  ?  0
 getId = shallowProperty('id'let obj = { id: 233,otherKey: 'who care'<span style="color: #000000;"> };

console.log(getId(obj)); <span style="color: #008000;">//<span style="color: #008000;"> 233

传入一个 key 生成一个 获取对象属性 key 的值 的函数。

<div class="cnblogs_code">


<span style="color: #0000ff;">var has = <span style="color: #0000ff;">function<span style="color: #000000;">(obj,path) {
<span style="color: #0000ff;">return obj != <span style="color: #0000ff;">null &&<span style="color: #000000;"> hasOwnProperty.call(obj,path);
}

就是使用了   判断对象 obj 是否存在属性 path

<div class="cnblogs_code">

 deepGet =  length = ( i = 0; i < length; i++ (obj == )   0= length ? obj :  0
 obj ='san''zhang'3console.log(deepGet(obj,['user','name','last'])); <span style="color: #008000;">//<span style="color: #008000;"> zhang

根据路径获取对象指定嵌套属性的值。

<div class="cnblogs_code">

 MAX_ARRAY_INDEX = Math.pow(2,53) - 1 getLength = shallowProperty('length' isArrayLike =  length =  length == 'number' && length >= 0 && length <=

如果一个对象有属性   ,属性值为数字且在 [0,2^53-1] 之间,则判断这个对象为类数组。

类数组常见的有 arguments、HTML Collection,数组也是类数组。

到这里是 174 行,下面就是集合相关函数了,明天再看 =。=

<div class="cnblogs_code">

_.each = _.forEach = 
  iteratee =
     (i = 0,length = obj.length; i < length; i++
     keys = (i = 0,length = keys.length; i < length; i++

这个函数相当于实现了 ES 的 forEach,传入(类)数组就遍历对每一项执行传入的函数   ,如果传入的是对象就对每一个键值对执行   

举个使用例子

'类数组 --->' _.each(arguments, console.log(`item=${item},idx=${idx},arr=${JSON.stringify(arr)},=${'上下文''对象 --->' obj = { k: 'v',kk: 'vv' ['k','kk'] _.each(obj,=${value},key=${key},obj=${JSON.stringify(obj)},'上下文'foo('one',[2],{ three: <span style="color: #0000ff;">false<span style="color: #000000;"> });

<span style="color: #008000;">//<span style="color: #008000;"> 类数组 ---><span style="color: #008000;">
//<span style="color: #008000;"> item=one,idx=0,arr={"0":"one","1":[2],"2":{"three":false}},this=上下文<span style="color: #008000;">
//<span style="color: #008000;"> item=2,idx=1,this=上下文<span style="color: #008000;">
//<span style="color: #008000;"> item=[object Object],idx=2,this=上下文<span style="color: #008000;">
//<span style="color: #008000;"> 对象 ---><span style="color: #008000;">
//<span style="color: #008000;"> value=v,key=k,obj={"k":"v","kk":"vv"},this=上下文<span style="color: #008000;">
//<span style="color: #008000;"> value=vv,key=kk,this=上下文

<div class="cnblogs_code">

_.map = _.collect = = keys = !isArrayLike(obj) &&= (keys ||= ( index = 0; index < length; index++ currentKey = keys ?=

这个和上面实现和功能差不多,无非两个循环放到一起写了,且对每一项执行传入函数后都有了返回值,并返回这些返回值组成的数组。

<div class="cnblogs_code">

 createReduce =  reducer =  keys = !isArrayLike(obj) &&= dir > 0 ? 0 : length - 1 (!
      memo = obj[keys ?+= (; index >= 0 && index < length; index += currentKey = keys ?=<span style="color: #0000ff;">return <span style="color: #0000ff;">function<span style="color: #000000;">(obj,context) {
<span style="color: #0000ff;">var
initial = arguments.length >= 3; <span style="color: #008000;">//
<span style="color: #008000;"> 根据参数个数 判断有没有初始值

<span style="color: #0000ff;">return
reducer(obj,optimizeCb(iteratee,4<span style="color: #000000;">),initial);
};
};

.reduce = .foldl = _.inject = createReduce(1<span style="color: #000000;">);

.reduceRight = .foldr = createReduce(-1);

reduce的实现,  通过传入 +1/-1 可以返回 正向/反向 reduce ,返回函数的函数称作高阶函数 createReduce 就是。

源码倒是不难理解。不过 reduce 的实现可以参考一下。手写代码什么的。。。

<div class="cnblogs_code">

 cb =  (_.isObject(value) && !_.isArray(value)) <span style="color: #0000ff;">var createPredicateIndexFinder = <span style="color: #0000ff;">function<span style="color: #000000;">(dir) {
<span style="color: #0000ff;">return
<span style="color: #0000ff;">function
<span style="color: #000000;">(array,predicate,context) {
predicate
=<span style="color: #000000;"> cb(predicate,context);
<span style="color: #0000ff;">var length =<span style="color: #000000;"> getLength(array);
<span style="color: #0000ff;">var index = dir > 0 ? 0 : length - 1<span style="color: #000000;">;
<span style="color: #0000ff;">for (; index >= 0 && index < length; index +=<span style="color: #000000;"> dir) {
<span style="color: #0000ff;">if (predicate(array[index],array)) <span style="color: #0000ff;">return<span style="color: #000000;"> index;
}
<span style="color: #0000ff;">return -1<span style="color: #000000;">;
};
};

.findIndex = createPredicateIndexFinder(1<span style="color: #000000;">);
.findLastIndex = createPredicateIndexFinder(-1<span style="color: #000000;">);

.findKey = <span style="color: #0000ff;">function<span style="color: #000000;">(obj,context) {
predicate =<span style="color: #000000;"> cb(predicate,context);
<span style="color: #0000ff;">var keys =<span style="color: #000000;">
.keys(obj),key;
<span style="color: #0000ff;">for (<span style="color: #0000ff;">var i = 0,length = keys.length; i < length; i++<span style="color: #000000;">) {
key =<span style="color: #000000;"> keys[i];
<span style="color: #0000ff;">if (predicate(obj[key],obj)) <span style="color: #0000ff;">return<span style="color: #000000;"> key;
}
};

.find = .detect = <span style="color: #0000ff;">function<span style="color: #000000;">(obj,context) {
<span style="color: #0000ff;">var keyFinder = isArrayLike(obj) ?<span style="color: #000000;"> .findIndex : .findKey;
<span style="color: #0000ff;">var key =<span style="color: #000000;"> keyFinder(obj,context);
<span style="color: #0000ff;">if (key !== <span style="color: #0000ff;">void 0 && key !== -1) <span style="color: #0000ff;">return<span style="color: #000000;"> obj[key];
};

这一段可能比较复杂,可以顺便好好理解一下cb函数。

=><span style="color: #008000;">//<span style="color: #008000;"> =========以下几个例子便于理解;=========

<span style="color: #0000ff;">var obj =<span style="color: #000000;"> {
a: '2333'<span style="color: #000000;">,b: 666<span style="color: #000000;">,c: 10086<span style="color: #000000;">,d: { propertyName: 'mdzz'<span style="color: #000000;"> }
};
<span style="color: #0000ff;">var arr = ['2333',666,10086,{ propertyName: 'mdzz'<span style="color: #000000;"> }];

<span style="color: #008000;">/<span style="color: #008000;"> 获取 number 类型的值 <span style="color: #008000;">/
<span style="color: #0000ff;">function predicate(item,arr) { <span style="color: #0000ff;">return <span style="color: #0000ff;">typeof item === 'number'<span style="color: #000000;">; }

console.log( .find(obj,predicate) ) <span style="color: #008000;">//<span style="color: #008000;"> predicate 是函数, 获取 obj 中第一个属性值类型为数字的值 > 666
console.log(
.find(obj) ) <span style="color: #008000;">//<span style="color: #008000;"> 没有传入 predicate 就是 .identity 对于每一个 truly 值都符合 所以返回第一个值 > '2333'
console.log(
.find(obj,{ propertyName: 'mdzz' }) ) <span style="color: #008000;">//<span style="color: #008000;"> predicate 是对象,查找符合对象的值 > { propertyName: 'mdzz' }
console.log( .find(obj,'propertyName') ) <span style="color: #008000;">//<span style="color: #008000;"> predicate 字符串,获取含有对应属性的值 > { propertyName: 'mdzz' }
<span style="color: #000000;">
console.log(
.find(arr,predicate) ) <span style="color: #008000;">//<span style="color: #008000;"> 666
console.log( .find(arr) ) <span style="color: #008000;">//<span style="color: #008000;"> '2333'
console.log(
.find(arr,{ propertyName: 'mdzz' }) ) <span style="color: #008000;">//<span style="color: #008000;"> { propertyName: 'mdzz' }
console.log( _.find(arr,'propertyName') ) <span style="color: #008000;">//<span style="color: #008000;"> { propertyName: 'mdzz' }

<div class="cnblogs_code">

_.filter = _.select =  results ==.each = .forEach = <span style="color: #0000ff;">function<span style="color: #000000;">(obj,context) {
iteratee
=<span style="color: #000000;"> optimizeCb(iteratee,length;
<span style="color: #0000ff;">if
<span style="color: #000000;"> (isArrayLike(obj)) {
<span style="color: #0000ff;">for
(i = 0,obj);
}
}
<span style="color: #0000ff;">else
<span style="color: #000000;"> {
<span style="color: #0000ff;">var
keys =<span style="color: #000000;"> _.keys(obj);
<span style="color: #0000ff;">for (i = 0,obj);
}
}
<span style="color: #0000ff;">return<span style="color: #000000;"> obj;
};

看到这里已经能理解 underscore 的这个逻辑了,如果是对象就 _.keys(obj) 遍历key,如果是 isLikeArray 就遍历下标。

_.each 就是对遍历的每一项执行传入函数。_.filter 就是执行传入函数后返回 true 项的放入返回对象。

<div class="cnblogs_code">

_.reject = _.negate = <span style="color: #0000ff;">function<span style="color: #000000;">(predicate) {
<span style="color: #0000ff;">return
<span style="color: #0000ff;">function<span style="color: #000000;">() {
<span style="color: #0000ff;">return !predicate.apply(<span style="color: #0000ff;">this<span style="color: #000000;">,arguments);
};
};

_.negate 将传入函数返回值取反,_reject 就是反向 _filter 所有不符合 predicate 的项放入返回数组返回。

<div class="cnblogs_code">

_.every = _.all = = (keys || ( index = 0; index < length; index++ currentKey = keys ? (!predicate(obj[currentKey],obj))   

如果数组的每一项都符合 predicate 就返回 true 否则返回 false

<div class="cnblogs_code">

_.some = _.any = = (keys || ( index = 0; index < length; index++ currentKey = keys ? (predicate(obj[currentKey],obj))   

数组中存在符合 predicate 的项就返回 true 否则返回 false

<div class="cnblogs_code">

_.contains = _.includes = _.include =  (!isArrayLike(obj)) obj = ( fromIndex != 'number' || guard) fromIndex = 0 _.indexOf(obj,fromIndex) >= 0<span style="color: #0000ff;">var createIndexFinder = <span style="color: #0000ff;">function<span style="color: #000000;">(dir,predicateFind,sortedIndex) {
<span style="color: #0000ff;">return
<span style="color: #0000ff;">function
<span style="color: #000000;">(array,idx) {
<span style="color: #0000ff;">var
i = 0,length =<span style="color: #000000;"> getLength(array);
<span style="color: #0000ff;">if (<span style="color: #0000ff;">typeof idx == 'number'<span style="color: #000000;">) {
<span style="color: #008000;">//<span style="color: #008000;"> 如果 idx 是数字类型 代表开始查找的位置
<span style="color: #0000ff;">if (dir > 0<span style="color: #000000;">) {
i = idx >= 0 ? idx : Math.max(idx +<span style="color: #000000;"> length,i);
} <span style="color: #0000ff;">else<span style="color: #000000;"> {
length = idx >= 0 ? Math.min(idx + 1,length) : idx + length + 1<span style="color: #000000;">;
}
} <span style="color: #0000ff;">else <span style="color: #0000ff;">if (sortedIndex && idx &&<span style="color: #000000;"> length) {
<span style="color: #008000;">//<span style="color: #008000;"> 如果 idx 不是数字类型 则代表 isSorted
idx =<span style="color: #000000;"> sortedIndex(array,item);
<span style="color: #0000ff;">return array[idx] === item ? idx : -1<span style="color: #000000;">;
}
<span style="color: #0000ff;">if (item !== item) { <span style="color: #008000;">//<span style="color: #008000;"> 判断 item 是否为 NaN
idx =<span style="color: #000000;"> predicateFind(slice.call(array,length),_.isNaN);
<span style="color: #0000ff;">return idx >= 0 ? idx + i : -1<span style="color: #000000;">;
}
<span style="color: #0000ff;">for (idx = dir > 0 ? i : length - 1; idx >= 0 && idx < length; idx +=<span style="color: #000000;"> dir) {
<span style="color: #0000ff;">if (array[idx] === item) <span style="color: #0000ff;">return<span style="color: #000000;"> idx;
}
<span style="color: #0000ff;">return -1<span style="color: #000000;">;
};
};

.indexOf = createIndexFinder(1<span style="color: #000000;">,.findIndex,.sortedIndex);
.lastIndexOf = createIndexFinder(-1<span style="color: #000000;">,_.findLastIndex);

_.sortedIndex = <span style="color: #0000ff;">function<span style="color: #000000;">(array,obj,context) {
iteratee = cb(iteratee,1<span style="color: #000000;">);
<span style="color: #0000ff;">var value =<span style="color: #000000;"> iteratee(obj);
<span style="color: #0000ff;">var low = 0,high =<span style="color: #000000;"> getLength(array);
<span style="color: #0000ff;">while (low <<span style="color: #000000;"> high) {
<span style="color: #0000ff;">var mid = Math.floor((low + high) / 2<span style="color: #000000;">);
<span style="color: #0000ff;">if (iteratee(array[mid]) < value) low = mid + 1; <span style="color: #0000ff;">else high =<span style="color: #000000;"> mid;
}
<span style="color: #0000ff;">return<span style="color: #000000;"> low;
};

又是比较长的的几个函数。

首先 sortedIndex 二分查找符合 iteratee 的下标。是对有序的数组进行查找。注意返回的是 iteratee(obj) <= iteratee(idx) 的最小下标 idx 查找不到的时候不返回 -1

indexOf 正向查找符合 iteratee 的下标 不存在返回 -1

lastIndexOf 反向向查找符合 iteratee 的下标 不存在返回 -1

对于 _.contains 判断 obj 中是否存在 item 从 fromIndex 开始查找

guard 存在的时候就一定是从 0 开始查找(不知道加这个参数是出于什么考虑

<div class="cnblogs_code">

_.invoke = restArguments(= = path.slice(0,-1= path[path.length - 1 _.map(obj, method = (! (contextPath &&= (context == )   0= method ==  ?<span style="color: #008000;">//<span style="color: #008000;"> e.g.
_.invoke({a: 1,b: '2'},<span style="color: #0000ff;">function
<span style="color: #000000;"> (...args) {
console.log(
<span style="color: #0000ff;">this
<span style="color: #000000;">,args);
},
'参数1','参数2'<span style="color: #000000;">);
<span style="color: #008000;">//
<span style="color: #008000;"> [Number: 1] [ '参数1','参数2' ]
<span style="color: #008000;">
//
<span style="color: #008000;"> [String: '2'] [ '参数1','参数2' ]

<span style="color: #000000;">
let obj
=<span style="color: #000000;"> {
one: {
a: {
b:
<span style="color: #0000ff;">function
<span style="color: #000000;"> () {
console.log(
<span style="color: #0000ff;">this
<span style="color: #000000;">,arguments);
}
}
},two: {
a: {
b:
<span style="color: #0000ff;">function
<span style="color: #000000;"> () {
console.log(
'哈哈哈哈哈'<span style="color: #000000;">);
}
}
}
};

_.invoke(obj,['a','b'<span style="color: #000000;">]);
<span style="color: #008000;">//<span style="color: #008000;"> { b: [Function: b] } {}<span style="color: #008000;">
//<span style="color: #008000;"> 哈哈哈哈哈

_.invoke 首先通过 restArguments 将函数包裹起来 会将多余的参数作为一个数组 args 统一传入

判断 path 是否是一个函数 如果是数组的话 就获取数组的除最后一项的所有项作为 contextPath 然后获得最后一项为 path 重新赋值

如果 path 是函数的话 就分别以 obj 的每一项作为 this 调用 path 参数为 ...args

否则 获取到 obj 每一项中对应 path 的属性值 然后每一项作为 this 调用该属性值 参数为 ...args

320行 =。= 看不下去了 明天继续……

<div class="cnblogs_code">

_.pluck = <span style="color: #008000;">//<span style="color: #008000;"> e.g.
let arr = [{id: 1},{name: 'zs',id: 2<span style="color: #000000;">},{}];
console.log(_.pluck(arr,
'id')); <span style="color: #008000;">//<span style="color: #008000;"> [ 1,undefined ]

这个好理解,就是获取数组每一项指定 key 的值。

<div class="cnblogs_code">

_.where = 
 attrs = { name: 'glory' arr = [{name:'glory'},{name:'saber'},{name:'glory',id: 1console.log(_.where(arr,attrs));

筛选出数组 obj (或者 _.keys(obj)) 中符合 attr 的项。

<div class="cnblogs_code">

_.findWhere = 

_.find 查找的是第一个 所以区别就是上面查找所有符合的项组成的数组,这个返回的是符合 attr 的第一项。没有就是 undefined

<div class="cnblogs_code">

_.max =  result = -Infinity,lastComputed = - (iteratee ==  ||  iteratee == 'number' &&  obj[0] != 'object' && obj != = isArrayLike(obj) ? ( i = 0,length = obj.length; i < length; i++= (value !=  && value >=== (computed > lastComputed || computed === -Infinity && result === -==
 arr = [{x:3,y:4},{x:4,y:5 comp =  obj.x * 3 + obj.y * 4

如果传入比较函数(iteratee)就用该函数对每一项进行处理,返回处理值最大那一项。(注意返回的原元素而不是经过 iteratee 处理后的)

如果不传就直接比较。注意他判断了 value != null 所以 null 和 undefined 是不参与比较的。(null > -1 值为 true)

如果是传入比较函数的时候,初始值和计算值设为   ,通过判断   来确定是不是初始状态,但是感觉这样会有 bug 看了下讨论区确实有人提了 ,还没有被解决。

但是鬼知道他判断 number 什么的是什么意思……(突然发现这个代码都七个月没更新了……

<div class="cnblogs_code">

_.min =  result = Infinity,lastComputed == (value !=  && value <== (computed < lastComputed || computed === Infinity && result =====

和最大值的逻辑相同。

<div class="cnblogs_code">

_.shuffle = .sample = <span style="color: #0000ff;">function<span style="color: #000000;">(obj,n,guard) {
<span style="color: #0000ff;">if
(n == <span style="color: #0000ff;">null ||<span style="color: #000000;"> guard) {
<span style="color: #0000ff;">if (!isArrayLike(obj)) obj =<span style="color: #000000;">
.values(obj);
<span style="color: #0000ff;">return obj[.random(obj.length - 1<span style="color: #000000;">)];
}
<span style="color: #0000ff;">var sample = isArrayLike(obj) ?<span style="color: #000000;">
.clone(obj) : .values(obj);
<span style="color: #0000ff;">var length =<span style="color: #000000;"> getLength(sample);
n = Math.max(Math.min(n,0<span style="color: #000000;">);
<span style="color: #0000ff;">var last = length - 1<span style="color: #000000;">;
<span style="color: #0000ff;">for (<span style="color: #0000ff;">var index = 0; index < n; index++<span style="color: #000000;">) {
<span style="color: #0000ff;">var rand =<span style="color: #000000;">
.random(index,last);
<span style="color: #0000ff;">var temp =<span style="color: #000000;"> sample[index];
sample[index] =<span style="color: #000000;"> sample[rand];
sample[rand] =<span style="color: #000000;"> temp;
}
<span style="color: #0000ff;">return sample.slice(0<span style="color: #000000;">,n);
};

.clone = <span style="color: #0000ff;">function<span style="color: #000000;">(obj) {
<span style="color: #0000ff;">if (!
.isObject(obj)) <span style="color: #0000ff;">return<span style="color: #000000;"> obj;
<span style="color: #0000ff;">return .isArray(obj) ?<span style="color: #000000;"> obj.slice() : .extend({},obj);
};

_.random = <span style="color: #0000ff;">function(min,max) { <span style="color: #008000;">//<span style="color: #008000;"> max ? [min,max] : [0,min]
<span style="color: #0000ff;">if (max == <span style="color: #0000ff;">null<span style="color: #000000;">) {
max =<span style="color: #000000;"> min;
min = 0<span style="color: #000000;">;
}
<span style="color: #008000;">//<span style="color: #008000;"> min + floor( [0,(max - min + 1)) ) -> min + [0,(max - min)] -> [min,max]
<span style="color: #0000ff;">return min + Math.floor(Math.random() * (max - min + 1<span style="color: #000000;">));
};

_.clone 浅复制一个数组或对象。

  随机获得 [min,max] 之间的整数。

_.sample(obj,guard) 获得数组或对象所有值中随机的 n 个值,如果 n 等于 obj.length 就相当于打乱数组了。

guard 存在的话就忽略 n 使得 sample 可以直接应用到 map 中。

<div class="cnblogs_code">

_.sortBy =  index = 0= _.pluck(_.map(obj,++ a = b = (a !== (a > b || a ===  0)  1 (a < b || b ===  0)  -1 left.index -'value'

虽然不难理解 但是觉得挺巧妙的。

首先映射成 { value,comp(value,...)(比较函数的计算值) } 对象,然后通过 sort 比较大小,如果计算值相同,会根据 index 保持原顺序。然后取 'value' 的值来获取数组原值。

<div class="cnblogs_code">


 group =   result = partition ?= key =_.groupBy = group(<span style="color: #0000ff;">function<span style="color: #000000;">(result,key) {
<span style="color: #0000ff;">if
(has(result,key)) result[key].push(value); <span style="color: #0000ff;">else
result[key] =<span style="color: #000000;"> [value];
});

_.indexBy = group(<span style="color: #0000ff;">function<span style="color: #000000;">(result,key) {
result[key] =<span style="color: #000000;"> value;
});

_.countBy = group(<span style="color: #0000ff;">function<span style="color: #000000;">(result,key)) result[key]++; <span style="color: #0000ff;">else result[key] = 1<span style="color: #000000;">;
});

.partition = group(<span style="color: #0000ff;">function<span style="color: #000000;">(result,pass) {
result[pass ? 0 : 1<span style="color: #000000;">].push(value);
},<span style="color: #0000ff;">true<span style="color: #000000;">);
<span style="color: #008000;">//<span style="color: #008000;"> e.g.
<span style="color: #0000ff;">function<span style="color: #000000;"> getScoreLevel(score) {
<span style="color: #0000ff;">if (score > 90) <span style="color: #0000ff;">return 'A'<span style="color: #000000;">;
<span style="color: #0000ff;">if (score > 60) <span style="color: #0000ff;">return 'B'<span style="color: #000000;">;
<span style="color: #0000ff;">return 'C'<span style="color: #000000;">;
}
console.log(
.groupBy([30,40,50,60,70,80,90,100<span style="color: #000000;">],getScoreLevel));
<span style="color: #008000;">//<span style="color: #008000;"> { C: [ 30,60 ],B: [ 70,90 ],A: [ 100 ] }

<span style="color: #0000ff;">function<span style="color: #000000;"> isPass(score) {
<span style="color: #0000ff;">return score >= 60<span style="color: #000000;">;
}
console.log(_.partition([30,isPass));
<span style="color: #008000;">//<span style="color: #008000;"> [ [ 60,100 ],[ 30,50 ] ]

groupBy 按照传入函数的计算值进行分类。indexBy 后面的值会覆盖前面的,所以应该是计算值唯一的时候使用。countBy 按照计算值统计个数。

partition 根据计算值分为两类。

<div class="cnblogs_code">

 reStrSymbol = /[^\ud800-\udfff]|[\ud800-\udbff][\udc00-\udfff]|[\ud800-\udfff]/=  (!obj)  (_.isArray(obj))  (isArrayLike(obj)) 

把一个对象转为数组。如果是 falsely 返回空数组。如果是数组返回数组副本,如果字符串就返回字符串分割成每个字符的数组,类数组转成数组返回,对象返回值的集合。

reStrSymbol正则,可以处理各种字符。

[^\ud800-\udfff] 是普通的 BMP 字符

[\ud800-\udbff][\udc00-\udfff] 是成对的代理项对

[\ud800-\udfff] 是未成对的代理项字

<div class="cnblogs_code">

_.size =  (obj == )  0 isArrayLike(obj) ?

获取(类)数组的长度或者对象属性的个数。

492行,我终于把集合部分看完了!!!明天继续。

<div class="cnblogs_code">

_.first = _.head = _.take =  (array ==  || array.length < 1)  n ==  ?  0 (n ==  || guard)  array[0 _.initial(array,array.length -_.initial = <span style="color: #0000ff;">function<span style="color: #000000;">(array,guard) {
<span style="color: #0000ff;">return
slice.call(array,Math.max(0,array.length - (n == <span style="color: #0000ff;">null
|| guard ? 1<span style="color: #000000;"> : n)));
};

initial 是获取数组除去最后 n 个元素的剩余部分,n 默认 1,如果传入 guard 也相当于 n 为 1。

first 是获取数组前 n 个元素。不传 n 或者传入 guard 则获取第一个元素。

guard 为了能够直接在 map 函数中使用。

<div class="cnblogs_code">


_.last =  (array ==  || array.length < 1)  n ==  ?  0 (n ==  || guard)  array[array.length - 1 _.rest(array,array.length -<span style="color: #008000;">//<span style="color: #008000;"> 获得数组除了前 n 个元素的剩余部分
.rest = .tail = _.drop = <span style="color: #0000ff;">function
<span style="color: #000000;">(array,n == <span style="color: #0000ff;">null
|| guard ? 1<span style="color: #000000;"> : n);
};

见注释,没什么好说的。

<div class="cnblogs_code">

_.compact = 

返回数组中除了假值的元素。

<div class="cnblogs_code">

 flatten = = output || idx = ( i = 0,length = getLength(input); i < length; i++ value = (isArrayLike(value) && (_.isArray(value) || j = 0,len = (j < len) output[idx++] = value[j++=  (!++] =.flatten = <span style="color: #0000ff;">function<span style="color: #000000;">(array,shallow) {
<span style="color: #0000ff;">return
flatten(array,<span style="color: #0000ff;">false
<span style="color: #000000;">);
};
<span style="color: #008000;">//
<span style="color: #008000;"> e.g.

let a = [ [1,3],[5,6],7,[ [8],[9<span style="color: #000000;">] ] ];
console.log(
.flatten(a));
<span style="color: #008000;">//
<span style="color: #008000;"> [ 1,3,5,6,8,9 ]

console.log(_.flatten(a,<span style="color: #0000ff;">true
)) <span style="color: #008000;">//
<span style="color: #008000;"> [ 1,[ 8 ],[ 9 ] ]

从名字来看 flatten 要做的就是把一个多维数组拍平

如果传了 shallow 只会把二维数组拍平成一维数组 否则就递归全部拍平

shallow = false 的话 strict 应该不为 true,strict 表示扩展二维数组时如果一项不是数组就不加入最后扩展的结果。

output 不需要传 是在递归的时候用到的参数

<div class="cnblogs_code">

_.without = restArguments(.difference = restArguments(<span style="color: #0000ff;">function<span style="color: #000000;">(array,rest) {
rest
= flatten(rest,<span style="color: #0000ff;">true
,<span style="color: #0000ff;">true<span style="color: #000000;">);
<span style="color: #0000ff;">return
.filter(array,<span style="color: #0000ff;">function<span style="color: #000000;">(value){
<span style="color: #0000ff;">return !<span style="color: #000000;">.contains(rest,value);
});
});
<span style="color: #008000;">//<span style="color: #008000;"> e.g.
console.log(
.difference([1,8],[1,[[8],[9]])); <span style="color: #008000;">//<span style="color: #008000;"> [1,8] 中不在 [ 1,[ 9 ] ] 的元素 => [ 5,8 ]
console.log(.without([1,1,3)); <span style="color: #008000;">//<span style="color: #008000;"> [1,3 ] 的元素 => [ 5,8 ]
let obj = [{ m: 'd' },{ z: 'z'<span style="color: #000000;"> }];
console.log(
.without(obj,obj[0],{ z: 'z' })); <span style="color: #008000;">//<span style="color: #008000;"> [ { z: 'z' } ]

difference 将多余的参数作为数组 [rest] 传入 然后在拍平为一维数组,也就是说 difference 的参数是一堆参数

然后求的是第一个数组中删除后面所有数组都不包含的元素 剩下的部分

without 把多余的参数作为数组 [otherArrays] 传入 然后在传入 difference

也就是说 without 传入一个数组和一些值 判断数组中不包含在后面那些值的元素

<div class="cnblogs_code">

_.uniq = _.unique =  (!_.isBoolean(isSorted)) { 
    context ===  (iteratee != ) iteratee = result = seen = ( i = 0,length = getLength(array); i < length; i++ value == iteratee ?
     (isSorted && !
      
       (!i || seen !===  (iteratee) { 
       (!  (!_.contains(result,value)) { 
.union = restArguments(<span style="color: #0000ff;">function<span style="color: #000000;">(arrays) {
<span style="color: #0000ff;">return
.uniq(flatten(arrays,<span style="color: #0000ff;">true
<span style="color: #000000;">));
});
<span style="color: #008000;">//
<span style="color: #008000;"> e.g.

<span style="color: #0000ff;">var
getName = .property('name'); <span style="color: #008000;">//
<span style="color: #008000;"> 获取一个对象的 name 属性

<span style="color: #0000ff;">var
staff = [ { name: 'joy',age: 19 },{ name: 'john',{ name: 'joy',age: 88<span style="color: #000000;"> } ];
.uniq(staff,getName);
<span style="color: #008000;">//
<span style="color: #008000;"> [ { name: 'joy',age: 19 } ]

_.union([1,2],[2,[3,4]); <span style="color: #008000;">//
<span style="color: #008000;"> [ 1,4 ]

_.uniq 将数组去重,如果传入计算函数就按照计算值去重 留第一个元素 否则直接比较元素

_.union 将传入的多个数组合并成一个数组然后去重

<div class="cnblogs_code">

_.intersection =  result = argsLength = ( i = 0,length = getLength(array); i < length; i++ item = (_.contains(result,item))  (j = 1; j < argsLength; j++ (!_.contains(arguments[j],item))  (j ===
_.intersection([1,4]); 

取多个数组的交集。在遍历第一个数组的元素,如果后面每个数组都包含,就加入结果数组。

<div class="cnblogs_code">

_.unzip = 
   length = array && _.max(array,getLength).length || 0; 
   result =
   ( index = 0; index < length; index++=<span style="color: #008000;">//<span style="color: #008000;"> 传入多个数组 然后通过 restArguments 合成一个二维数组传入 unzip
.zip =<span style="color: #000000;"> restArguments(.unzip);
<span style="color: #008000;">//
<span style="color: #008000;"> e.g.

<span style="color: #0000ff;">var
obj = [ ['张三',18,'男'],['李四',16,'女'],['王五',23,'男'<span style="color: #000000;">] ];
.unzip(obj);
<span style="color: #008000;">//
<span style="color: #008000;"> [ [ '张三','李四','王五' ],[ 18,23 ],[ '男','女','男' ] ]

.zip([ '张三','男' ]); <span style="color: #008000;">//
<span style="color: #008000;"> [ [ '张三','男' ],[ '李四','女' ],[ '王五','男' ] ]

zip 和 unzip 功能差不多啊 就是传入多个数组,然后把下标相同的元素放到同一个数组,不过 zip 传入多个数组 unzip 传入二维数组

目前不太理解有什么用

<div class="cnblogs_code">

_.object =  result = ( i = 0,length = getLength(list); i < length; i++=0]] = list[i][1
_.object([ ['LENGTH',34],['WIDTH',43] ]); 
_.object([ '叶修','苏沐橙' ],['君莫笑','沐雨橙风']); 

数组转键值对,一种是二维数组,一种是两个对应的数组。

<div class="cnblogs_code">

_.range =  (stop == ) { 
    stop = start || 0= 0 (!step) { 
    step = stop < start ? -1 : 1
   length = Math.max(Math.ceil((stop - start) / step),0 range =<span style="color: #0000ff;">for (<span style="color: #0000ff;">var idx = 0; idx < length; idx++,start +=<span style="color: #000000;"> step) {
range[idx]
=<span style="color: #000000;"> start;
}

<span style="color: #0000ff;">return<span style="color: #000000;"> range;
};
<span style="color: #008000;">//<span style="color: #008000;"> e.g.
.range(10); <span style="color: #008000;">//<span style="color: #008000;"> [ 0,4,9 ]
.range(13,100,17); <span style="color: #008000;">//<span style="color: #008000;"> [ 13,30,47,64,81,98 ]

设定初始值,结束值和步长,生成一个数组。

<div class="cnblogs_code">

_.chunk =  (count ==  || count < 1)  result = i = 0,length = (i <+=
 _1To10 = _.range(1,11); 
_.chunk(_1To10,3); 

将数组分块,按顺序,每 count 个分成一块。

755 行,下面是函数部分了。再开一篇博客写,太长了。

下接 《

大佬总结

以上是大佬教程为你收集整理的Underscore.js 源码学习笔记(上)全部内容,希望文章能够帮你解决Underscore.js 源码学习笔记(上)所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ群:277859234,请注明来意。
标签:Underscore.js 源码学习笔记(上)
猜你在找的程序笔记相关文章
其他相关热搜词更多
php如何使用2javascriptJavaPythoncocosc#编程问答csschtmlrubydjs3cocos2d文件
全站导航更多
最新程序笔记教程
热门程序笔记教程