猿问

增强 Vanialla JS 功能

我有一个带有属性的对象。这些属性可能存在也可能不存在。

为了可以访问属性,我的工作如下:

myData.properties.find(p => p.name == 'target').value = 'Foo';

现在可能发生myData根本没有名称的属性target。因此,我想扩展该Array.prototype.find()功能以创建缺少的元素。

Array.prototype.findOrCreate()

它应该稍后可用:

myData.properties.findOrCreate(p => p.name == 'target', { name: 'target', value: '' });

但是,我不知道如何使用该功能。

我不是在这里寻找解决方案(我什至要求没有人在这里提供解决方案),而是我实现它时的必要理论。

在 PHP 中,我会查看函数定义并对其进行扩展。但是,我找不到Array.prototype.find()的函数定义。


侃侃无极
浏览 158回答 3
3回答

婷婷同学_

无需扩展数组原型(因为这可能导致冲突和前向兼容性问题)。相反,您可以创建一个单独的函数,以数组作为输入来执行此操作。如果返回,您可以使用.find()条件 ( ?) 运算符来默认值:.find()undefinedconst 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: ""}

呼如林

您只需将新功能添加到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来存储键值对(甚至是简单的对象)

翻翻过去那场雪

在你绝对可以扩展 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在解析期间使用自定义来使用您的类而不是本机数组。
随时随地看视频慕课网APP

相关分类

JavaScript
我要回答