为了账号安全,请及时绑定邮箱和手机立即绑定

增强 Vanialla JS 功能

增强 Vanialla JS 功能

侃侃无极 2022-01-07 10:22:41
我有一个带有属性的对象。这些属性可能存在也可能不存在。为了可以访问属性,我的工作如下: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()的函数定义。
查看完整描述

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: ""}


查看完整回答
反对 回复 2022-01-07
?
呼如林

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来存储键值对(甚至是简单的对象)


查看完整回答
反对 回复 2022-01-07
?
翻翻过去那场雪

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在解析期间使用自定义来使用您的类而不是本机数组。


查看完整回答
反对 回复 2022-01-07
  • 3 回答
  • 0 关注
  • 157 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信