We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
源码地址
经常我们在项目中会使用条件判定,&&必须2边都是true的时候,才会返回true, ||有一边是true就返回true, 很少关心是否它的返回值,因为if语句会自动转换成布尔值。下面我们来讨论下,它不转换成布尔值的时候返回的值
&&
true
||
if
// && true && 3 => 3 false && 2 => false 0 && false => 0 // || false || 3 => 3 9 || 0 => 9 undefined || 4 => 4
总结: 从上面可以看出,返回值是有一个规律的,当&& 和 ||的值决定的时候,返回那个起决定作用的值。
createCallback
// createCallback函数 var createCallback = function(func, context, argCount) { // 如果没有传递上下文context 则直接返回函数 (void 0 === undefined) if (context === void 0) return func; // 这里可以看出underscore的内部通过参数的长度进行了分类 默认值第三类 switch (argCount == null ? 3 : argCount) { case 1: return function(value) { return func.call(context, value); }; case 2: return function(value, other) { return func.call(context, value, other); }; case 3: return function(value, index, collection) { return func.call(context, value, index, collection); }; case 4: return function(accumulator, value, index, collection) { return func.call(context, accumulator, value, index, collection); }; } return function() { return func.apply(context, arguments); }; };
var ArrayProto = Array.prototype, ObjProto = Object.prototype, FuncProto = Function.prototype; var push = ArrayProto.push, slice = ArrayProto.slice, concat = ArrayProto.concat, toString = ObjProto.toString, hasOwnProperty = ObjProto.hasOwnProperty; var nativeIsArray = Array.isArray, nativeKeys = Object.keys, nativeBind = FuncProto.bind;
调用方式:
_.each([1, 2, 3], alert); // alert(1) alert(2) alert(3) _.each({one: 1, two: 2, three: 3}, alert); // alert每一项的value
源码:
// obj => 值 iteratee => 构造器 context=> 函数的执行上下文 _.each = _.forEach = function(obj, iteratee, context) { if(obj === null ) return obj; // 这里有createCallback函数,这么没有传递上下文,直接返回函数 iteratee = createCallback(iteratee, context); let i, length = obj.length // 由于对象是没有length属性的,可以通过length和+length来判定是数组还是对象 (+length转换成数字类型) if(length === +length) { for(i = 0; i< length; i++) { iteratee(obj[i], i, obj) } } else { // 这里确定是对象,获取keys let keys = _.keys(obj); for(i = 0, length = keys.length; i < length; i++) { iteratee(obj[keys[i]], keys[i] , obj) } } return obj } // 上面使用了内部的_.keys() 下面分析_.keys()
_.keys = function(obj) { if(!_.isObject) return []; if(nativeKeys) return nativeKeys(obj); var keys = []; for(let key in obj) { if(_.has(obj, key)){ keys.push(key) } } return keys }
_.isObject = function(obj) { let type = typeof obj; return type === 'function' || type === 'object' && !!obj; } // 反思: 为什么还要添加 !!obj // typeof null === 'object' !!null === false
_.has = function(obj, key) { return obj != null && hasOwnProperty.call(obj,key) }
调用:
_.map([1, 2, 3], function(num){ return num * 3; }); => [3, 6, 9] _.map({one: 1, two: 2, three: 3}, function(num, key){ return num * 3; }); => [3, 6, 9] _.map([[1, 2], [3, 4]], _.first); => [1, 3]
_.map = _.collect = function(obj, iteratee, context) { if(obj === null) return [] // 得到回调函数 iteratee = _.iteratee(iteratee, context); // 如果不是数组就返回包含对象的keys的数组,如果是数组返回false var keys = obj.length !== +obj.length || _.keys(obj), //length = keys ? obj.length : keys.length, length = (keys || obj).length, // 生成一个长度为length的数组, 值为undefined results = Array(length), currentKey; for(let index = 0; index < length ; index++){ // 获取当前的key currentKey = keys ? keys[index] : index; results[index] = iteratee(obj[currentKey], currentKey , obj) } return results }
_.iteratee = function(value, context, argCount) { if (value == null) return _.identity; // 如果是函数 if (_.isFunction(value)) return createCallback(value, context, argCount); // 如果是对象 if (_.isObject(value)) return _.matches(value); return _.property(value); };
_.reduce([1, 2, 3], function(memo, num){ return memo + num; }, 0);
// createCallback第4部分 接受4个参数,第一个参数是memo return function(accumulator, value, index, collection) { return func.call(context, accumulator, value, index, collection); }; _.reduce = function(obj, iteratee, memo, context) { if(obj == null) return []; iteratee = createCallback(iteratee, context ,4) // 数组keys=false 对象key等于一个arr var keys = obj.length !== +obj.length && _.keys(obj), length = (keys || obj).length, index = 0; currentIndex; // 没有传递memo if(arguments.length < 3) { if(!length) throw new TypeError(reduceError); // 获取数组的第一项,并index加一,获得对象的第一个的value memo = obj[keys ? keys[index++] : index++]; } for(; index < length ; index++) { // 如果是对象就获取对应的key,是数组就获取index currentIndex = keys ? keys[index] : index; memo = iteratee(memo, obj[currentIndex], index, obj) } return meno; }
The text was updated successfully, but these errors were encountered:
add _.reduce
Sorry, something went wrong.
No branches or pull requests
underscore源码解析
源码地址
&&和||返回值解析
经常我们在项目中会使用条件判定,
&&
必须2边都是true
的时候,才会返回true
,||
有一边是true
就返回true
, 很少关心是否它的返回值,因为if
语句会自动转换成布尔值。下面我们来讨论下,它不转换成布尔值的时候返回的值总结: 从上面可以看出,返回值是有一个规律的,当
&&
和||
的值决定的时候,返回那个起决定作用的值。公共函数
createCallback
公共变量
集合部分
_.each()
调用方式:
源码:
_.keys(obj) 获取对象的keys,返回一个包含keys的数组
_.isObject(obj) 判定是否是对象
_.has(obj, key) 判定属性在自己作用域内,而不是原型链中
_.map(list, iteratee, [context]) 计算数组每一项,返回一个新数组
调用:
源码:
_.iteratee(value, context)
_.reduce(list, iteratee, memo, context)
调用:
源码:
The text was updated successfully, but these errors were encountered: