您现在的位置是:亿华云 > IT科技
怎么把一个对象当做数组使用
亿华云2025-10-03 18:10:57【IT科技】8人已围观
简介怎么把一个对象当做数组使用?我们知道在JS中对象和数组的操作方式是不一样的,但是我们可以通过封装,给对象加一层包装器,让它可以和数组拥有同样的使用方式。我们主要借助Object.keys()、Obje
怎么把一个对象当做数组使用?对象当
我们知道在JS中对象和数组的操作方式是不一样的,但是数组使用我们可以通过封装,给对象加一层包装器,对象当让它可以和数组拥有同样的数组使用使用方式。我们主要借助Object.keys()、对象当Object.values()、数组使用Object.entries()、对象当Proxy。数组使用
Object.keys
看一下MDN上的对象当解释:
Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组,数组中属性名的数组使用排列顺序和正常循环遍历该对象时返回的顺序一致。
也就是对象当Object.keys可以获取对象的所有属性名,并生成一个数组。数组使用
var obj = { a: 0,对象当 b: 1, c: 2 };
console.log(Object.keys(obj));
// console: [a, b, c]Object.values
看一下MDN上的解释:
Object.values()方法返回一个给定对象自身的所有可枚举属性值的数组,值的数组使用顺序与使用for...in循环的顺序相同 ( 区别在于 for-in 循环枚举原型链中的属性 )。
Object.values()返回一个数组,对象当元素是云服务器提供商对象上找到的可枚举属性值。
var obj = { foo: bar, baz: 42 };
console.log(Object.values(obj));
// [bar, 42]Object.entries
看一下MDN上的解释:
Object.entries()方法返回一个给定对象自身可枚举属性的键值对数组,其排列与使用 for...in 循环遍历该对象时返回的顺序一致(区别在于 for-in 循环还会枚举原型链中的属性)。
Object.entries()返回一个数组,元素是由属性名和属性值组成的数组。
const obj = { foo: bar, baz: 42 };
console.log(Object.entries(obj));
// [ [foo, bar], [baz, 42] ]Proxy
Proxy是JS最新的对象代理方式,用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
使用Proxy可以封装对象的原始操作,在执行对象操作的时候,会经过Proxy的处理,这样我们就可以实现数组操作命令。
基础 get 示例
const handler = {
get: function(obj, prop) {
return prop in obj ? obj[prop] : 37;
}
}
const p = new Proxy({ }, handler);
p.a = 1;
p.b = undefined;
console.log(p.a, p.b)
console.log(c in p, p.c)以上示例的中,当对象中不存在属性名时,默认返回值为37。香港云服务器
无操作转发代理
使用Proxy包装原生对象生成一个代理对象p,对代理对象的操作会转发到原生对象上。
let target = { };
let p = new Proxy(target, { });
p.a = 37; // 操作转发到目标
console.log(target.a); // 37. 操作已经被正确地转发我们要实现以下几个函数:forEach、map、filter、reduce、slice、find、findKey、includes、keyOf、lastKeyOf。
实现数组函数
forEach
数组中的forEach函数定义:arr.forEach(callback(currentValue [, index [, array]])[, thisArg])。
数组中的forEach需要传入一个函数,函数的第一个参数是当前操作的元素值,第二个参数是当前操作的元素索引,第三个参数是正在操作的对象。
对于对象,我们将参数定为:currentValue、key、target。我们可以使用Object.keys来遍历对象。
Object.keys(target).forEach(key => callback(target[key], key, target))这里需要target和callback参数,云服务器我们通过函数封装一下。
function forEach(target, callback) {
Object.keys(target).forEach(key => callback(target[key], key, target))
}这样我们就可以使用以下方式调用:
const a = { a: 1, b: 2, c: 3}
forEach(a, (v, k) => console.log(`${ k}-${ v}`))
// a-1
// b-2
// c-3通过Proxy封装:
const handler = {
get: function(obj, prop) {
return forEach(obj)
}
}
const p = new Proxy(a, handler)
p.forEach((v, k) => console.log(`${ k}-${ v}`))以上方式当然是不行的,我们主要看最后一句,其执行方式和数组的forEach完全相同,我们在调用Proxy封装的对象时,获取数据时,会调用get函数,第一个参数为原生对象,第二个参数为属性名-forEach,在这里就要修改我们的forEach函数了。首先p.forEach的参数是一个函数,因此我们代理对象的返回值需要接收一个函数作为参数,因此修改如下:
function forEach(target) {
return (callback) => Object.keys(target).forEach(key => callback(target[key], key, target))
}因此完成代码为:
function forEach(target) {
return (callback) => Object.keys(target).forEach(key => callback(target[key], key, target))
}
const handler = {
get: function(obj, prop) {
return forEach(obj)
}
}
const a = { a: 1, b: 2, c: 3}
const p = new Proxy(a, handler)
p.forEach((v, k) => console.log(`${ k}-${ v}`))
// a-1
// b-2
// c-3我们应该把以上代码封装为模块,方便对外使用:
const toKeyedArray = (obj) => {
const methods = {
forEach(target) {
return (callback) => Object.keys(target).forEach(key => callback(target[key], key, target));
}
}
const methodKeys = Object.keys(methods)
const handler = {
get(target, prop) {
if (methodKeys.includes(prop)) {
return methods[prop](target)
}
return Reflect.get(...arguments)
}
}
return new Proxy(obj, handler)
}
const a = { a: 1, b: 2, c: 3}
const p = toKeyedArray(a)
p.forEach((v, k) => console.log(`${ k}-${ v}`))以上是forEach的实现和封装,其他函数的实现方式类似。
全部源码如下:
const toKeyedArray = (obj) => {
const methods = {
forEach(target) {
return (callback) => Object.keys(target).forEach(key => callback(target[key], key, target));
},
map(target) {
return (callback) =>
Object.keys(target).map(key => callback(target[key], key, target));
},
reduce(target) {
return (callback, accumulator) =>
Object.keys(target).reduce(
(acc, key) => callback(acc, target[key], key, target),
accumulator
);
},
forEach(target) {
return callback =>
Object.keys(target).forEach(key => callback(target[key], key, target));
},
filter(target) {
return callback =>
Object.keys(target).reduce((acc, key) => {
if (callback(target[key], key, target)) acc[key] = target[key];
return acc;
}, { });
},
slice(target) {
return (start, end) => Object.values(target).slice(start, end);
},
find(target) {
return callback => {
return (Object.entries(target).find(([key, value]) =>
callback(value, key, target)
) || [])[0];
};
},
findKey(target) {
return callback =>
Object.keys(target).find(key => callback(target[key], key, target));
},
includes(target) {
return val => Object.values(target).includes(val);
},
keyOf(target) {
return value =>
Object.keys(target).find(key => target[key] === value) || null;
},
lastKeyOf(target) {
return value =>
Object.keys(target)
.reverse()
.find(key => target[key] === value) || null;
}
}
const methodKeys = Object.keys(methods)
const handler = {
get(target, prop) {
if (methodKeys.includes(prop)) {
return methods[prop](target)
}
const [keys, values] = [Object.keys(target), Object.values(target)];
if (prop === length) return keys.length;
if (prop === keys) return keys;
if (prop === values) return values;
if (prop === Symbol.iterator)
return function* () {
for (value of values) yield value;
return;
};
return Reflect.get(...arguments)
}
}
return new Proxy(obj, handler)
}
const x = toKeyedArray({ a: A, b: B });
x.a; // A
x.keys; // [a, b]
x.values; // [A, B]
[...x]; // [A, B]
x.length; // 2
// Inserting values
x.c = c; // x = { a: A, b: B, c: c }
x.length; // 3
// Array methods
x.forEach((v, i) => console.log(`${ i}: ${ v}`)); // LOGS: a: A, b: B, c: c
x.map((v, i) => i + v); // [aA, bB, cc]
x.filter((v, i) => v !== B); // { a: A, c: c }
x.reduce((a, v, i) => ({ ...a, [v]: i }), { }); // { A: a, B: b, c: c }
x.slice(0, 2); // [A, B]
x.slice(-1); // [c]
x.find((v, i) => v === i); // c
x.findKey((v, i) => v === B); // b
x.includes(c); // true
x.includes(d); // false
x.keyOf(B); // b
x.keyOf(a); // null
x.lastKeyOf(c); // c很赞哦!(9)