baseToString
Be yourself. Everyone else is already taken. — Oscar Wilde
本文为 《lodash 源码阅读》 系列文章,后续内容会在 github 中发布,欢迎 star,gitbook 同步更新。
依赖
import isSymbol from '../isSymbol.js';
源码
/** 声明 无穷大 变量 */
const INFINITY = 1 / 0;
/** 用于将 symbols 转化为原始值或字符串 */
const symbolToString = Symbol.prototype.toString;
/**
* 优化实现 'toString'
*
* @private
* @param {*} value 需要处理的值
* @returns {string} 返回一个字符串
*/
function baseToString(value) {
// 若参数为 string 类型,则提前返回自身,避免某些环境下的性能损失
if (typeof value == 'string') {
return value;
}
if (Array.isArray(value)) {
// 递归进行值转换(易受调用堆栈限制)
return `${value.map(baseToString)}`;
}
if (isSymbol(value)) {
return symbolToString ? symbolToString.call(value) : '';
}
const result = `${value}`;
return result == '0' && 1 / value == -INFINITY ? '-0' : result;
}
原理
baseToString
相较于 toString
,主要有三个优化点:
递归转换数组类型
Symbol
类型String
化特殊处理
-''
、-null
、-'0'
、-false
等多种情况,返回-0
值
1、3 两点都比较容易理解,第 2 个点,有一个比较精妙的写法,便是缓存了 Symbol.prototype.toString
给 symbolToString
变量,这里为什么要这么做而不直接使用 Symbol
类型中的 toString
呢? 刚开始我也没有明白这样做的写法,后来在看了对应的 isSymbol.test.js
测试文件后,得到了启发,部分代码是这样的:
var symbol = Symbol('a');
// ...
assert.strictEqual(isSymbol(symbol), true);
assert.strictEqual(isSymbol(Object(symbol)), true);
// ...
Object(symbol)
是一个包装对象,包装对象存在被覆写 原始数据 方法的可能:
const symbol = Object(Symbol());
symbol.toString();
// "Symbol()"
symbol.toString = () => console.log('我被覆写了');
symbol.toString();
// "我被覆写了"
而使用 Symbol.prototype.toString
可以避免这种情况的发生:
Symbol.prototype.toString.call(symbol);
// "Symbol()"
针对 Symbol
的特殊处理原因,我另起一篇文章讲解 从 ECMAScript 中理解 Symbol 类型转换
相关链接
参考
Last updated
Was this helpful?