Lodash 源码阅读-keys
功能概述
keys
是 Lodash 库中的一个核心函数,用于获取对象自身的可枚举属性名称。它能够处理各种类型的对象,包括普通对象、数组、类数组对象等,并返回一个包含所有属性名的数组。
前置学习
依赖函数
keys
函数依赖以下几个 Lodash 内部函数:
- isArrayLike:检查值是否为类数组对象
- arrayLikeKeys:获取类数组对象的可枚举属性名
- baseKeys:获取非类数组对象的可枚举属性名
技术知识
- 可枚举属性:JavaScript 对象的属性可以是可枚举的或不可枚举的,可枚举属性可以通过 for...in 循环遍历
- 类数组对象:具有 length 属性和索引元素的对象,如数组、arguments、DOM 集合等
- Object.keys:ES5 引入的原生方法,用于获取对象自身的可枚举属性名
- hasOwnProperty:用于检查属性是否为对象自身的属性(而非继承的)
源码实现
javascript
/**
* Creates an array of the own enumerable property names of `object`.
*
* **Note:** Non-object values are coerced to objects. See the
* [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys)
* for more details.
*
* @static
* @since 0.1.0
* @memberOf _
* @category Object
* @param {Object} object The object to query.
* @returns {Array} Returns the array of property names.
* @example
*
* function Foo() {
* this.a = 1;
* this.b = 2;
* }
*
* Foo.prototype.c = 3;
*
* _.keys(new Foo);
* // => ['a', 'b'] (iteration order is not guaranteed)
*
* _.keys('hi');
* // => ['0', '1']
*/
function keys(object) {
return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
}
实现思路
keys
函数的实现思路非常简洁明了,可以分为以下几个步骤:
- 类型判断:首先判断传入的对象是否为类数组对象
- 分支处理 :
- 如果是类数组对象,使用
arrayLikeKeys
获取属性名 - 如果不是类数组对象,使用
baseKeys
获取属性名
- 如果是类数组对象,使用
- 返回结果:返回包含所有属性名的数组
这种实现方式既简洁又高效,通过区分不同类型的对象采用不同的处理策略,确保了在各种情况下都能正确获取对象的属性名。
源码解析
函数签名
javascript
function keys(object) {
函数接收一个参数:
object
:要查询的对象,可以是任何类型的值
类型判断和分支处理
javascript
return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object);
这行代码是函数的核心,它根据对象的类型选择不同的处理方式:
-
isArrayLike(object) :判断
object
是否为类数组对象- 类数组对象需满足:非函数、有 length 属性、length 为非负整数且不超过最大安全整数
-
arrayLikeKeys(object) :如果是类数组对象,使用
arrayLikeKeys
获取属性名- 这个函数会特殊处理数组、arguments、Buffer、TypedArray 等类数组对象
- 对于类数组对象,它会预先创建包含所有索引的数组,然后添加其他非索引属性
-
baseKeys(object) :如果不是类数组对象,使用
baseKeys
获取属性名- 这个函数会处理普通对象,通常使用
Object.keys
的包装 - 对于原型对象,它会手动遍历并筛选出自身的可枚举属性
- 这个函数会处理普通对象,通常使用
与其他函数的关系
keys
函数与 Lodash 中的其他函数有密切的关系:
-
keysIn :与
keys
类似,但包含继承的属性javascriptfunction Foo() { this.a = 1; this.b = 2; } Foo.prototype.c = 3; const foo = new Foo(); console.log(_.keys(foo)); // ['a', 'b'] console.log(_.keysIn(foo)); // ['a', 'b', 'c']
-
values :获取对象的所有值,内部使用
keys
获取属性名javascriptfunction values(object) { return object == null ? [] : baseValues(object, keys(object)); }
-
entries/toPairs :将对象转换为键值对数组,内部使用
keys
获取属性名javascriptfunction toPairs(object) { return object == null ? [] : baseToPairs(object, keys(object)); }
-
forEach/map/filter 等集合操作函数 :这些函数在处理对象时,通常使用
keys
获取属性名进行遍历 -
assign/merge 等对象操作函数 :这些函数在合并对象时,通常使用
keys
获取源对象的属性名
与原生方法的比较
keys
函数与 JavaScript 原生的 Object.keys
方法有一些区别:
-
处理非对象值:
Object.keys
会在传入非对象值时抛出错误_.keys
会将非对象值转换为对象再处理
javascriptObject.keys("hi"); // ['0', '1'] Object.keys(123); // TypeError: 123 is not an object _.keys("hi"); // ['0', '1'] _.keys(123); // []
-
处理类数组对象:
Object.keys
对所有对象的处理方式相同_.keys
对类数组对象有特殊的处理逻辑,使用arrayLikeKeys
函数
-
处理原型对象:
Object.keys
在处理原型对象时可能会包含 constructor 属性_.keys
通过baseKeys
函数特殊处理原型对象,排除 constructor 属性
总结
keys
是 Lodash 中一个核心的工具函数,用于获取对象自身的可枚举属性名。它通过区分不同类型的对象采用不同的处理策略,确保了在各种情况下都能正确获取对象的属性名。