3 回答
TA贡献1844条经验 获得超8个赞
无需扩展数组原型(因为这可能导致冲突和前向兼容性问题)。相反,您可以创建一个单独的函数,以数组作为输入来执行此操作。如果返回,您可以使用.find()条件 ( ?) 运算符来默认值:.find()undefined
const findOrCreate = (arr, f, def) => {
const res = arr.find(f);
return res === undefined ? def : res;
}
const data = [{name: 'foo', value: 1}, {name: 'bar', value: 1}];
const obj = findOrCreate(data, p => p.name === 'xyz', { name: 'target', value: '' });
console.log(obj);
或者,如果您支持 ES2020,则可以使用nullish 合并运算符( ??),如下所示:
const findOrCreate = (arr, f, def) => arr.find(f) ?? def;
const data = [{name: 'foo', value: 1}, {name: 'bar', value: 1}];
const obj = findOrCreate(data, p => p.name === 'xyz', { name: 'target', value: '' });
console.log(obj); // {name: "target", value: ""}
TA贡献1798条经验 获得超3个赞
您只需将新功能添加到Array.prototype. find()是一个简单的循环,数组没有其他索引魔法,它必须遍历数组并且偶然发现合适的元素。
var a=[{name:"something",value:1},{name:"somethingelse",value:2}];
Array.prototype.findOrCreate=function(name){
for(var elem of this)
if(elem.name === name)
return elem;
var newelem={name:name};
this.push(newelem);
return newelem;
}
console.log("original",JSON.stringify(a));
a.findOrCreate("something").value=3;
console.log("modified",JSON.stringify(a));
a.findOrCreate("somethingbrandnew").value=4;
console.log("extended",JSON.stringify(a));
请注意,您宁愿使用 aMap来存储键值对(甚至是简单的对象)
TA贡献2065条经验 获得超13个赞
在你绝对可以扩展 Vanilla JS 对象的地方,这种做法通常被认为是不好的,因为它会导致冲突和兼容性问题。
另外,在这种情况下,由于您想target在数组中查找具有名称的项目,如果没有,则创建一个新项目,我将拥有更多原子函数。这些动作对我来说显然是分开的,把它们放在一种方法中也不是好的做法——因为原子函数很容易组合。
在您的情况下,代码很简单:
let target = myData.properties.find(p => p.name == 'target') || {name: "target"};
target.value = "Foo";
如果您还想将此新对象添加到properties数组中:
let target = myData.properties.find(p => p.name == 'target');
if (!target) {
target = {name: "target"};
myData.properties.push(target);
}
target.value = "Foo";
但是,如果你真的,真的,真的想扩展原生数组:
Array.prototype.findOrCreate = function findOrCreate(predicate, item) {
let target = this.find(predicate);
if (!target) {
this.push(item);
return item;
}
return target;
}
myData.properties.findOrCreate(p => p.name == 'target', {name: "target"}).value = "Foo";
但是,具有 as 功能可能会更安全:
function findOrCreate (array, predicate, item) {
let target = array.find(predicate);
if (!target) {
array.push(item);
return item;
}
return target;
}
findOrCreate(myData.properties, p => p.name == 'target', {name: "target"}).value = "Foo";
因为您不会发生冲突(您也可以避免使用Symbol发生冲突,但是每次您想访问该方法时都必须在代码中折腾它)。
作为更多的原子功能,您可以拥有:
find(myData.properties, item => item.name == "target")
.or(create({name : "target"}))
.value = "Foo";
该方法的实施可能类似于:
function find(array, predicate) {
const item = array.find(predicate);
return {
or(action) {
return item || action(array);
}
}
}
const create = (item) => (array) => (array.push(item), item);
但是,如果您真的更喜欢 OOP 方法,我强烈建议Array您在自己的类中扩展:
class MyArray extends Array {
constructor(...items) {
super(...items);
}
findOrCreate(predicate, item) {
let target = this.find(predicate);
if (!target) {
this.push(item);
return item;
}
return target;
}
}
此时,您可以使用所有数组的方法,以及您的方法。您也可以从常规数组转换为您的数组 - 如果您不能直接创建它们,例如您从外部 API 获得它:
myData.properties = MyArray.from(myData.properties);
如果您从 JSON 字符串中获取,您还可以reviver在解析期间使用自定义来使用您的类而不是本机数组。
添加回答
举报