@segment/analytics.js-core
Version:
The hassle-free way to integrate analytics into any web application.
164 lines (147 loc) • 4.81 kB
JavaScript
;
/*
* The MIT License (MIT)
* Copyright (c) 2015 Nathan Houle
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/*
* Module dependencies.
*/
var keys = require('@ndhoule/keys');
var objToString = Object.prototype.toString;
/**
* Tests if a value is a number.
*
* @name isNumber
* @api private
* @param {*} val The value to test.
* @return {boolean} Returns `true` if `val` is a number, otherwise `false`.
*/
var isNumber = function isNumber(val) {
var type = typeof val;
return (
type === 'number' ||
(type === 'object' && objToString.call(val) === '[object Number]')
);
};
/**
* Tests if a value is an array.
*
* @name isArray
* @api private
* @param {*} val The value to test.
* @return {boolean} Returns `true` if the value is an array, otherwise `false`.
*/
var isArray =
typeof Array.isArray === 'function'
? Array.isArray
: function isArray(val) {
return objToString.call(val) === '[object Array]';
};
/**
* Tests if a value is array-like. Array-like means the value is not a function and has a numeric
* `.length` property.
*
* @name isArrayLike
* @api private
* @param {*} val
* @return {boolean}
*/
var isArrayLike = function isArrayLike(val) {
return (
val != null &&
(isArray(val) || (val !== 'function' && isNumber(val.length)))
);
};
/**
* Internal implementation of `each`. Works on arrays and array-like data structures.
*
* @name arrayEach
* @api private
* @param {Function(value, key, collection)} iterator The function to invoke per iteration.
* @param {Array} array The array(-like) structure to iterate over.
* @return {undefined}
*/
var arrayEach = function arrayEach(iterator, array) {
for (var i = 0; i < array.length; i += 1) {
// Break iteration early if `iterator` returns `false`
if (iterator(array[i], i, array) === false) {
break;
}
}
};
/**
* Internal implementation of `each`. Works on objects.
*
* @name baseEach
* @api private
* @param {Function(value, key, collection)} iterator The function to invoke per iteration.
* @param {Object} object The object to iterate over.
* @return {undefined}
*/
var baseEach = function baseEach(iterator, object) {
var ks = keys(object);
for (var i = 0; i < ks.length; i += 1) {
// Break iteration early if `iterator` returns `false`
if (iterator(object[ks[i]], ks[i], object) === false) {
break;
}
}
};
/**
* Iterate over an input collection, invoking an `iterator` function for each element in the
* collection and passing to it three arguments: `(value, index, collection)`. The `iterator`
* function can end iteration early by returning `false`.
*
* @name each
* @api public
* @param {Function(value, key, collection)} iterator The function to invoke per iteration.
* @param {Array|Object|string} collection The collection to iterate over.
* @return {undefined} Because `each` is run only for side effects, always returns `undefined`.
* @example
* var log = console.log.bind(console);
*
* each(log, ['a', 'b', 'c']);
* //-> 'a', 0, ['a', 'b', 'c']
* //-> 'b', 1, ['a', 'b', 'c']
* //-> 'c', 2, ['a', 'b', 'c']
* //=> undefined
*
* each(log, 'tim');
* //-> 't', 2, 'tim'
* //-> 'i', 1, 'tim'
* //-> 'm', 0, 'tim'
* //=> undefined
*
* // Note: Iteration order not guaranteed across environments
* each(log, { name: 'tim', occupation: 'enchanter' });
* //-> 'tim', 'name', { name: 'tim', occupation: 'enchanter' }
* //-> 'enchanter', 'occupation', { name: 'tim', occupation: 'enchanter' }
* //=> undefined
*/
var each = function each(iterator, collection) {
return (isArrayLike(collection) ? arrayEach : baseEach).call(
this,
iterator,
collection
);
};
/*
* Exports.
*/
module.exports = each;