参考资料
源码拷贝仓库地址(阅读的源码版本)
isSymbol(value)
getTag(value)
返回 value 的 toStringTag,相比Object.prototype.toString,添加了对 null 和 undefined 的 tag
const toString = Object.prototype.toString
/**
* 返回 value 的 toStringTag
*
* @param {*} value 传入要获取 tag 的对象
* @returns {string} 返回对象对应的 tag
*/
function getTag(value) {
if (value == null) {
// 如果 value 是 null 或者 undefined,返回对应的 tag
return value === undefined ? '[object Undefined]' : '[object Null]'
}
return toString.call(value)
}
export default getTag
isSymbol(value)
检测传入的 value 是否是 Symbol 数据类型或者 Symbol 对象
import getTag from './.internal/getTag.js'
/**
* 检测传入的 `value` 是否是 `Symbol` 数据类型或者 `Symbol` 对象
*
* @param {*} value 要被检测的值
* @returns {boolean} 返回检测结果
* @example
*
* isSymbol(Symbol.iterator)
* // => true
*
* isSymbol('abc')
* // => false
*/
function isSymbol(value) {
const type = typeof value
// || 后面的作用是用来判断 Symbol 的 polyfill 生成的 Symbol 对象
return type == 'symbol' || (type === 'object' && value != null && getTag(value) == '[object Symbol]')
}
export default isSymbol
检测传入的 value 的 typeof 值是否为 object 或者 function,null 除外
isObject(value)
/**
* 检测传入的 value 的 typeof 值是否为 object 或者 function,null 除外
*
* @param {*} value 要被检测的值
* @returns {boolean} 返回检测结果
* @example
*
* isObject({})
* // => true
*
* isObject([1, 2, 3])
* // => true
*
* isObject(Function)
* // => true
*
* isObject(null)
* // => false
*/
function isObject(value) {
const type = typeof value
return value != null && (type === 'object' || type === 'function')
}
export default isObject
toNumber(value)
将传入的 value 转换为 number 类型
import isObject from './isObject.js'
import isSymbol from './isSymbol.js'
/** NAN 常量 */
const NAN = 0 / 0
/** 正则匹配字符串开头和结尾处的空字符 */
const reTrim = /^\s+|\s+$/g
/** 正则检测是否是带符号的十六进制字符串 */
const reIsBadHex = /^[-+]0x[0-9a-f]+$/i
/** 正则检测是否是二进制字符串 */
const reIsBinary = /^0b[01]+$/i
/** 正则检测是否是八进制字符串 */
const reIsOctal = /^0o[0-7]+$/i
/** 不依赖与内置 root 的方法引用 */
const freeParseInt = parseInt
/**
* 将传入的 value 转换为 number 类型
*
* @param {*} 要被转换的值
* @returns {number} 返回转换后的结果
* @see isInteger, toInteger, isNumber
* @example
*
* toNumber(3.2)
* // => 3.2
*
* toNumber(Number.MIN_VALUE)
* // => 5e-324
*
* toNumber(Infinity)
* // => Infinity
*
* toNumber('3.2')
* // => 3.2
*/
function toNumber(value) {
// 判断 value 是否是 number 类型,如果是直接返回 value
if (typeof value === 'number') {
return value
}
// 判断 value 是否是 Symbol 数据类型或者 Symbol 对象,如果是,返回 NAN
if (isSymbol(value)) {
return NAN
}
// 判断 value 是否是对象
if (isObject(value)) {
// 如果 value 是对象,并且 valueOf 属性是一个 function,执行 valueOf 并且将结果赋值给 other。如果 valueOf 属性不是 function,将 value 赋值给 other
const other = typeof value.valueOf === 'function' ? value.valueOf() : value
// 如果 other 是对象,toString 转换为 字符串赋值给 value。如果不是,直接赋值给 value
value = isObject(other) ? `${other}` : other
}
// 如果 value 不是 string 类型
if (typeof value !== 'string') {
// 判断 value 是否为 0,如果是直接返回 value,如果不是,转换 value 为 number 类型返回
return value === 0 ? value : +value
}
// 将 value 首尾空字符串去除
value = value.replace(reTrim, '')
const isBinary = reIsBinary.test(value)
// 判断 value 是否是二进制字符串或者是八进制字符串,如果使用 parseInt 方法转换为十进制 number 类型返回
// 如果是带有符号的十六进制字符串,直接返回 NAN
// 否则直接将字符串转换成 number 类型返回
return (isBinary || reIsOctal.test(value))
? freeParseInt(value.slice(2), isBinary ? 2 : 8)
: (reIsBadHex.test(value) ? NAN : +value)
}
export default toNumber
通过阅读源码可以发现,toNumber 如果传入带有符号的二进制,八进制或者十六进制的字符串返回的结果是 NAN
console.log(toNumber('+0x1')) // NAN
console.log(toNumber('-0x1')) // NAN
console.log(toNumber('+0b1')) // NAN
console.log(toNumber('-0b1')) // NAN
console.log(toNumber('+0o1')) // NAN
console.log(toNumber('-0o1')) // NAN
在最后的此符串检测中可以做一个小改动,是上面的例子返回正确的数值
...
const reIsBadHex = /^[+-]0x[0-9a-f]+$/i
const reIsHex = /^[+-]?0x[0-9a-f]+$/i
const reIsBinary = /^[+-]?0b[01]+$/i
const reIsOctal = /^[+-]?0o[0-7]+$/i
const reNumberBase = /0[box]/
...
return (isBinary || reIsOctal.test(value))
? freeParseInt(value.replace(reNumberBase, ''), isBinary ? 2 : 8)
: (reIsHex.test(value) ? freeParseInt(value.replace(reNumberBase, ''), 16) : +value)
toFinite(value)
将传入的 value 值转换为有限数值 number 类型
import toNumber from './toNumber.js'
/** INFINITY 常量 */
const INFINITY = 1 / 0
/** 最大数值 */
const MAX_INTEGER = 1.7976931348623157e+308
/**
* 将传入的 value 值转换为有限数值 number 类型
*
* @param {*} value 要被转换的值
* @returns {number} 返回结果
* @example
*
* toFinite(3.2)
* // => 3.2
*
* toFinite(Number.MIN_VALUE)
* // => 5e-324
*
* toFinite(Infinity)
* // => 1.7976931348623157e+308
*
* toFinite('3.2')
* // => 3.2
*/
function toFinite(value) {
// 判断 value 值是否有效。如果值为 0 或者无效,返回 0
if (!value) {
return value === 0 ? value : 0
}
// 将值转换为 number 类型
value = toNumber(value)
if (value === INFINITY || value === -INFINITY) {
// 判断值是否为 INFINITY,如果是,返回最大或最小数值
const sign = (value < 0 ? -1 : 1)
return sign * MAX_INTEGER
}
// 判断 value 是否是 NAN,如果是,返回 0,不是返回 value
return value === value ? value : 0
}
export default toFinite
toInteger(value)
将 value 值转换为整型数值(向下取整)
import toFinite from './toFinite.js'
/**
* 将 value 值转换为整型数值(向下取整)
*
* @param {*} value 要被转换的值
* @returns {number} 返回转换结果
* @see isInteger, isNumber, toNumber
* @example
*
* toInteger(3.2)
* // => 3
*
* toInteger(Number.MIN_VALUE)
* // => 0
*
* toInteger(Infinity)
* // => 1.7976931348623157e+308
*
* toInteger('3.2')
* // => 3
*/
function toInteger(value) {
// 将 value 转换为有限的数值
const result = toFinite(value)
// 去除小数点后的数值
const remainder = result % 1
// 如果小数点后的数值不为 0,向下取整返回,否则返回 result
return remainder ? result - remainder : result
}
export default toInteger
slice(array, start, end)
浅拷贝传入的数组 array 中起始位置 start 到结束位置 end (不包括 end )的元素组成数组并返回
/**
* 浅拷贝传入的数组 array 中起始位置 start 到结束位置 end (不包括 end )的元素组成数组并返回
*
* @param {Array} array 要被截取元素的数组
* @param {number} [start=0] 截取起始位置,默认为 0
* @param {number} [end=array.length] 截取的结束位置,默认为数组的长度
* @returns {Array} 返回截取后的数组
* @example
*
* var array = [1, 2, 3, 4]
*
* _.slice(array, 2)
* // => [3, 4]
*/
function slice(array, start, end) {
// 数组的长度,没有传入数组或者数组的长度为 0 返回空数组
let length = array == null ? 0 : array.length
if (!length) {
return []
}
// 起始位置和结束位置,如果没有传入,使用默认值
start = start == null ? 0 : start
end = end === undefined ? length : end
if (start < 0) {
// 如果 start 小于 0,从数组的末端倒数起始位置
start = -start > length ? 0 : (length + start)
}
// 如果 end 大于 length,将 length 赋值 end
end = end > length ? length : end
if (end < 0) {
// 如果 end 小于 0,从数组的末端倒数结束位置
end += length
}
// 计算将要截取的数组长度
length = start > end ? 0 : ((end - start) >>> 0)
// start 向下取整
start >>>= 0
let index = -1
const result = new Array(length)
while (++index < length) {
result[index] = array[index + start]
}
// 返回截取后的数组
return result
}
export default slice