These are two forEach
functions; the one I wrote vs. the one I imported from lodash
via Browserify.
(I removed the comments to be more fair.)
These are two forEach
functions; the one I wrote vs. the one I imported from lodash
via Browserify.
(I removed the comments to be more fair.)
window._ = {}; | |
window._.forEach = function (ar, fn) { | |
for (var i = 0; i < ar.length; i++) { | |
fn.call(this, ar[i]); | |
} | |
}; |
// var forEach = require('lodash/collection/forEach'); | |
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
var forEach = require('lodash/collection/forEach'); | |
},{"lodash/collection/forEach":2}],2:[function(require,module,exports){ | |
var arrayEach = require('../internal/arrayEach'), | |
baseEach = require('../internal/baseEach'), | |
createForEach = require('../internal/createForEach'); | |
var forEach = createForEach(arrayEach, baseEach); | |
module.exports = forEach; | |
},{"../internal/arrayEach":3,"../internal/baseEach":4,"../internal/createForEach":12}],3:[function(require,module,exports){ | |
function arrayEach(array, iteratee) { | |
var index = -1, | |
length = array.length; | |
while (++index < length) { | |
if (iteratee(array[index], index, array) === false) { | |
break; | |
} | |
} | |
return array; | |
} | |
module.exports = arrayEach; | |
},{}],4:[function(require,module,exports){ | |
var baseForOwn = require('./baseForOwn'), | |
createBaseEach = require('./createBaseEach'); | |
var baseEach = createBaseEach(baseForOwn); | |
module.exports = baseEach; | |
},{"./baseForOwn":6,"./createBaseEach":10}],5:[function(require,module,exports){ | |
var createBaseFor = require('./createBaseFor'); | |
var baseFor = createBaseFor(); | |
module.exports = baseFor; | |
},{"./createBaseFor":11}],6:[function(require,module,exports){ | |
var baseFor = require('./baseFor'), | |
keys = require('../object/keys'); | |
function baseForOwn(object, iteratee) { | |
return baseFor(object, iteratee, keys); | |
} | |
module.exports = baseForOwn; | |
},{"../object/keys":23,"./baseFor":5}],7:[function(require,module,exports){ | |
function baseProperty(key) { | |
return function(object) { | |
return object == null ? undefined : object[key]; | |
}; | |
} | |
module.exports = baseProperty; | |
},{}],8:[function(require,module,exports){ | |
function baseToString(value) { | |
if (typeof value == 'string') { | |
return value; | |
} | |
return value == null ? '' : (value + ''); | |
} | |
module.exports = baseToString; | |
},{}],9:[function(require,module,exports){ | |
var identity = require('../utility/identity'); | |
function bindCallback(func, thisArg, argCount) { | |
if (typeof func != 'function') { | |
return identity; | |
} | |
if (thisArg === undefined) { | |
return func; | |
} | |
switch (argCount) { | |
case 1: return function(value) { | |
return func.call(thisArg, value); | |
}; | |
case 3: return function(value, index, collection) { | |
return func.call(thisArg, value, index, collection); | |
}; | |
case 4: return function(accumulator, value, index, collection) { | |
return func.call(thisArg, accumulator, value, index, collection); | |
}; | |
case 5: return function(value, other, key, object, source) { | |
return func.call(thisArg, value, other, key, object, source); | |
}; | |
} | |
return function() { | |
return func.apply(thisArg, arguments); | |
}; | |
} | |
module.exports = bindCallback; | |
},{"../utility/identity":27}],10:[function(require,module,exports){ | |
var getLength = require('./getLength'), | |
isLength = require('./isLength'), | |
toObject = require('./toObject'); | |
function createBaseEach(eachFunc, fromRight) { | |
return function(collection, iteratee) { | |
var length = collection ? getLength(collection) : 0; | |
if (!isLength(length)) { | |
return eachFunc(collection, iteratee); | |
} | |
var index = fromRight ? length : -1, | |
iterable = toObject(collection); | |
while ((fromRight ? index-- : ++index < length)) { | |
if (iteratee(iterable[index], index, iterable) === false) { | |
break; | |
} | |
} | |
return collection; | |
}; | |
} | |
module.exports = createBaseEach; | |
},{"./getLength":13,"./isLength":15,"./toObject":18}],11:[function(require,module,exports){ | |
var toObject = require('./toObject'); | |
function createBaseFor(fromRight) { | |
return function(object, iteratee, keysFunc) { | |
var iterable = toObject(object), | |
props = keysFunc(object), | |
length = props.length, | |
index = fromRight ? length : -1; | |
while ((fromRight ? index-- : ++index < length)) { | |
var key = props[index]; | |
if (iteratee(iterable[key], key, iterable) === false) { | |
break; | |
} | |
} | |
return object; | |
}; | |
} | |
module.exports = createBaseFor; | |
},{"./toObject":18}],12:[function(require,module,exports){ | |
var bindCallback = require('./bindCallback'), | |
isArray = require('../lang/isArray'); | |
function createForEach(arrayFunc, eachFunc) { | |
return function(collection, iteratee, thisArg) { | |
return (typeof iteratee == 'function' && thisArg === undefined && isArray(collection)) | |
? arrayFunc(collection, iteratee) | |
: eachFunc(collection, bindCallback(iteratee, thisArg, 3)); | |
}; | |
} | |
module.exports = createForEach; | |
},{"../lang/isArray":20,"./bindCallback":9}],13:[function(require,module,exports){ | |
var baseProperty = require('./baseProperty'); | |
var getLength = baseProperty('length'); | |
module.exports = getLength; | |
},{"./baseProperty":7}],14:[function(require,module,exports){ | |
var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; | |
function isIndex(value, length) { | |
value = +value; | |
length = length == null ? MAX_SAFE_INTEGER : length; | |
return value > -1 && value % 1 == 0 && value < length; | |
} | |
module.exports = isIndex; | |
},{}],15:[function(require,module,exports){ | |
var MAX_SAFE_INTEGER = Math.pow(2, 53) - 1; | |
function isLength(value) { | |
return typeof value == 'number' && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; | |
} | |
module.exports = isLength; | |
},{}],16:[function(require,module,exports){ | |
function isObjectLike(value) { | |
return !!value && typeof value == 'object'; | |
} | |
module.exports = isObjectLike; | |
},{}],17:[function(require,module,exports){ | |
var isArguments = require('../lang/isArguments'), | |
isArray = require('../lang/isArray'), | |
isIndex = require('./isIndex'), | |
isLength = require('./isLength'), | |
keysIn = require('../object/keysIn'), | |
support = require('../support'); | |
var objectProto = Object.prototype; | |
var hasOwnProperty = objectProto.hasOwnProperty; | |
function shimKeys(object) { | |
var props = keysIn(object), | |
propsLength = props.length, | |
length = propsLength && object.length; | |
var allowIndexes = length && isLength(length) && | |
(isArray(object) || (support.nonEnumArgs && isArguments(object))); | |
var index = -1, | |
result = []; | |
while (++index < propsLength) { | |
var key = props[index]; | |
if ((allowIndexes && isIndex(key, length)) || hasOwnProperty.call(object, key)) { | |
result.push(key); | |
} | |
} | |
return result; | |
} | |
module.exports = shimKeys; | |
},{"../lang/isArguments":19,"../lang/isArray":20,"../object/keysIn":24,"../support":26,"./isIndex":14,"./isLength":15}],18:[function(require,module,exports){ | |
var isObject = require('../lang/isObject'); | |
function toObject(value) { | |
return isObject(value) ? value : Object(value); | |
} | |
module.exports = toObject; | |
},{"../lang/isObject":22}],19:[function(require,module,exports){ | |
var isLength = require('../internal/isLength'), | |
isObjectLike = require('../internal/isObjectLike'); | |
var argsTag = '[object Arguments]'; | |
var objectProto = Object.prototype; | |
var objToString = objectProto.toString; | |
function isArguments(value) { | |
var length = isObjectLike(value) ? value.length : undefined; | |
return isLength(length) && objToString.call(value) == argsTag; | |
} | |
module.exports = isArguments; | |
},{"../internal/isLength":15,"../internal/isObjectLike":16}],20:[function(require,module,exports){ | |
var isLength = require('../internal/isLength'), | |
isNative = require('./isNative'), | |
isObjectLike = require('../internal/isObjectLike'); | |
var arrayTag = '[object Array]'; | |
var objectProto = Object.prototype; | |
var objToString = objectProto.toString; | |
var nativeIsArray = isNative(nativeIsArray = Array.isArray) && nativeIsArray; | |
var isArray = nativeIsArray || function(value) { | |
return isObjectLike(value) && isLength(value.length) && objToString.call(value) == arrayTag; | |
}; | |
module.exports = isArray; | |
},{"../internal/isLength":15,"../internal/isObjectLike":16,"./isNative":21}],21:[function(require,module,exports){ | |
var escapeRegExp = require('../string/escapeRegExp'), | |
isObjectLike = require('../internal/isObjectLike'); | |
var funcTag = '[object Function]'; | |
var reIsHostCtor = /^\[object .+?Constructor\]$/; | |
var objectProto = Object.prototype; | |
var fnToString = Function.prototype.toString; | |
var objToString = objectProto.toString; | |
var reIsNative = RegExp('^' + | |
escapeRegExp(objToString) | |
.replace(/toString|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' | |
); | |
function isNative(value) { | |
if (value == null) { | |
return false; | |
} | |
if (objToString.call(value) == funcTag) { | |
return reIsNative.test(fnToString.call(value)); | |
} | |
return isObjectLike(value) && reIsHostCtor.test(value); | |
} | |
module.exports = isNative; | |
},{"../internal/isObjectLike":16,"../string/escapeRegExp":25}],22:[function(require,module,exports){ | |
function isObject(value) { | |
var type = typeof value; | |
return type == 'function' || (!!value && type == 'object'); | |
} | |
module.exports = isObject; | |
},{}],23:[function(require,module,exports){ | |
var isLength = require('../internal/isLength'), | |
isNative = require('../lang/isNative'), | |
isObject = require('../lang/isObject'), | |
shimKeys = require('../internal/shimKeys'); | |
var nativeKeys = isNative(nativeKeys = Object.keys) && nativeKeys; | |
var keys = !nativeKeys ? shimKeys : function(object) { | |
if (object) { | |
var Ctor = object.constructor, | |
length = object.length; | |
} | |
if ((typeof Ctor == 'function' && Ctor.prototype === object) || | |
(typeof object != 'function' && isLength(length))) { | |
return shimKeys(object); | |
} | |
return isObject(object) ? nativeKeys(object) : []; | |
}; | |
module.exports = keys; | |
},{"../internal/isLength":15,"../internal/shimKeys":17,"../lang/isNative":21,"../lang/isObject":22}],24:[function(require,module,exports){ | |
var isArguments = require('../lang/isArguments'), | |
isArray = require('../lang/isArray'), | |
isIndex = require('../internal/isIndex'), | |
isLength = require('../internal/isLength'), | |
isObject = require('../lang/isObject'), | |
support = require('../support'); | |
var objectProto = Object.prototype; | |
var hasOwnProperty = objectProto.hasOwnProperty; | |
function keysIn(object) { | |
if (object == null) { | |
return []; | |
} | |
if (!isObject(object)) { | |
object = Object(object); | |
} | |
var length = object.length; | |
length = (length && isLength(length) && | |
(isArray(object) || (support.nonEnumArgs && isArguments(object))) && length) || 0; | |
var Ctor = object.constructor, | |
index = -1, | |
isProto = typeof Ctor == 'function' && Ctor.prototype === object, | |
result = Array(length), | |
skipIndexes = length > 0; | |
while (++index < length) { | |
result[index] = (index + ''); | |
} | |
for (var key in object) { | |
if (!(skipIndexes && isIndex(key, length)) && | |
!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { | |
result.push(key); | |
} | |
} | |
return result; | |
} | |
module.exports = keysIn; | |
},{"../internal/isIndex":14,"../internal/isLength":15,"../lang/isArguments":19,"../lang/isArray":20,"../lang/isObject":22,"../support":26}],25:[function(require,module,exports){ | |
var baseToString = require('../internal/baseToString'); | |
var reRegExpChars = /[.*+?^${}()|[\]\/\\]/g, | |
reHasRegExpChars = RegExp(reRegExpChars.source); | |
function escapeRegExp(string) { | |
string = baseToString(string); | |
return (string && reHasRegExpChars.test(string)) | |
? string.replace(reRegExpChars, '\\$&') | |
: string; | |
} | |
module.exports = escapeRegExp; | |
},{"../internal/baseToString":8}],26:[function(require,module,exports){ | |
(function (global){ | |
var objectProto = Object.prototype; | |
var document = (document = global.window) && document.document; | |
var propertyIsEnumerable = objectProto.propertyIsEnumerable; | |
var support = {}; | |
(function(x) { | |
var Ctor = function() { this.x = x; }, | |
object = { '0': x, 'length': x }, | |
props = []; | |
Ctor.prototype = { 'valueOf': x, 'y': x }; | |
for (var key in new Ctor) { props.push(key); } | |
support.funcDecomp = /\bthis\b/.test(function() { return this; }); | |
support.funcNames = typeof Function.name == 'string'; | |
try { | |
support.dom = document.createDocumentFragment().nodeType === 11; | |
} catch(e) { | |
support.dom = false; | |
} | |
try { | |
support.nonEnumArgs = !propertyIsEnumerable.call(arguments, 1); | |
} catch(e) { | |
support.nonEnumArgs = true; | |
} | |
}(1, 0)); | |
module.exports = support; | |
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{}],27:[function(require,module,exports){ | |
function identity(value) { | |
return value; | |
} | |
module.exports = identity; | |
},{}]},{},[1]) |
Wow, that is much better 😅
But it just goes to show how you don't really have good idea what's being included while coding. This is an internal function that I would waste more time finding than writing my own.
Wow, that is much better 😅
Modules rock! 😸
But it just goes to show how you don't really have good idea what's being included while coding
It looks like you have a good idea of the scope of functionality you want and _.each
is simply more functionality than you need (with support for object iteration, fixes for Safari JIT bugs, etc.). The lodash internal at least aligns more closely with _.each
than the written alternative, providing the same iteratee
arguments & allowing iteration to exit early.
"less" isn't "better". "correct" is better.
Your forEach doesn't handle objects, which lodash's does, it also is useless since Array.prototype.forEach
already exists natively - so if you're just working with arrays, why would you want a utility function at all? Yours is also broken with its handling of "this", and unlike forEach
, doesn't pass the index, or the entire array, to the callback.
See https://twitter.com/paul_irish/status/227203681462927361 and https://twitter.com/trek/status/227082154109186049
If you just want a simple forEach implementation:
npm install foreach --save
Then;
var each = require('foreach')
each(array, fn, ctx)
https://www.npmjs.com/package/foreach
@jdalton Is internal/
really safe to require? Do breaking changes in internal/
lead to major version bumps?
If you just want a simple forEach implementation:
npm install foreach --save
Careful, foreach
hits an iOS JIT bug that affects Safari on at least iOS 8.1-8.3 ARM64.
Is internal/ really safe to require? Do breaking changes in internal/ lead to major version bumps?
Internals are more relaxed than external but we try for internals to be safe with the ~
range.
Another option is MOUT require('mout/array/forEach')
Problem of roll your own solutions is that it will probably contain bugs, less tests and no documentation... There is always a cost on loading external dependencies but in many cases it does pay off. I would definitely not start MOUT if the modular lodash existed back in 2011.
A simpler one: var forEach = Function.bind.call(Function.call, Array.prototype.forEach)
A simpler one:
var forEach = Function.bind.call(Function.call, Array.prototype.forEach)
Nice one 👍 Yeah, I know mine sucks, it wasn't a very good example, but I'm just incredibly frustrated with trying to make it work and "fixing" other people's libs when the benefit is not clear to me anymore. Also, publishing Node packages which can't be used in Node is a very weird idea to me, am I the only one? I'm going to paraphrase a feature request:
Hey, could you please convert your client-side JavaScript library to Node, so I can convert it back to client-side?
I'm probably wrong and just in a moment of frustration, I'll get it eventually.
See https://twitter.com/paul_irish/status/227203681462927361 and https://twitter.com/trek/status/227082154109186049
So why do we bother with packages at all? Including vendor files is a lot easier, we don't care about a little redundant code then?
Problem of roll your own solutions is that it will probably contain bugs, less tests and no documentation...
You're right, it does have that drawback.
@silvenon "why do we bother with packages at all" - packages are the same as vendor files, but better encapsulated. "easier" isn't important, "reliable" is.
Try
require('lodash/internal/arrayEach')
andbrowserify --plugin bundle-collapser/plugin
which Uglifies to 351 bytes gzipped, 314 bytes of which is the Browserify boilerplate.