Home > Back-end >  Function stored in object property returns array instead of object
Function stored in object property returns array instead of object

Time:10-29

I'm trying to set an object property using a function that returns and object.

The problem is when setting the property I'm getting back an array as a value instead of the object.

const newUserRights = {
  A: { id: '1'},
  B: { id: '2'},
  C: { id: '3'},
  D: { id: '4'},
  E: { id: '5'},
  F: { id: '6'},
  G: { id: '7'},
};

var Post = {
  name: '',
  rs: function r(rights = []) {
    let r = {};
    for (let [k, v] of Object.entries(newUserRights)) {
      r[v.id] = false;
    }
    if (rights.length > 0) {
      for (ri of rights) {
        r[ri] = true;
      }
    }
    return r;
  },
};

// trying to set the property
Post.rs = ['1', '2'];

Desired output:

Post: {
    name:'',
    rs:{
        1: true,
        2: true,
        3: false,
        4: false,
        5: false,
        6: false,
        7: false
    }
}

But getting:

Post: {
    name:'',
    rs:['1', '2']
}

I want to know

  • what I'm doing wrong
  • How to return the Object
  • Is this a good practice

Thank you

CodePudding user response:

There are lots of ways to do this, but this keeps the solution close to your attempt.

I considered an implementation using this, but thought that would add unhelpful complexity.

I will note, however, that any time you have a series of incrementing integers, an Array should be considered because it has those keys implicitly.

const newUserRights = {
  A: { id: '1'},
  B: { id: '2'},
  C: { id: '3'},
  D: { id: '4'},
  E: { id: '5'},
  F: { id: '6'},
  G: { id: '7'},
};

const applyRights = (o, rights = []) => {
  const rs = {};
  for (const [, { id }] of Object.entries(newUserRights)) {
    rs[id] = false;
  }
  
  for (const r of rights) {
    rs[r] = true;
  }
  
  o.rs = rs;
  return o;
};

const Post = { name: '' };
console.log(applyRights(Post, ['1', '2']));

CodePudding user response:

You might be looking for a setter (and probably also a getter to read the value).

const newUserRights = {
  A: { id: '1'},
  B: { id: '2'},
  C: { id: '3'},
  D: { id: '4'},
  E: { id: '5'},
  F: { id: '6'},
  G: { id: '7'},
};

var Post = (() => {
  let rs;

  return {
    name: '',
    get rs() { return rs },
    set rs(rights = []) {
      rs = {};
      for (let [k, v] of Object.entries(newUserRights)) {
        rs[v.id] = false;
      }
      if (rights.length > 0) {
        for (ri of rights) {
          rs[ri] = true;
        }
      }
    },
  };
})();

// trying to set the property
Post.rs = ['1', '2'];
console.log(Post);

I've used an IIFE here to limit the scope of the rs variable, so only the returned Post has access to it. Alternatively you could also omit the IIFE and store the value as an object property instead.

var Post = {
  name: '',
  get rs() { return this._rs },
  set rs(rights = []) {
    this._rs = {};
    for (let [k, v] of Object.entries(newUserRights)) {
      this._rs[v.id] = false;
    }
    if (rights.length > 0) {
      for (ri of rights) {
        this._rs[ri] = true;
      }
    }
  },
};

This does however result in Post having 3 properties instead of 2. name, rs holding the getter/setter, and _rs to store the actual value.

Another thing I want to point out is that if (rights.length > 0) is unnecessary. Looping with for (ri of rights) over an empty list will execute the for-block content for each element in the list, but since the list is empty nothing is executed.

CodePudding user response:

Solution 1:

You just need to call the function proper way Post.rs(['1', '2'])

const newUserRights = {
      A: { id: '1'},
      B: { id: '2'},
      C: { id: '3'},
      D: { id: '4'},
      E: { id: '5'},
      F: { id: '6'},
      G: { id: '7'},
    };
    
    var Post = {
      name: '',
      rs: function (rights = []) {
        let r = {};
        for (let [k, v] of Object.entries(newUserRights)) {
          r[v.id] = false;
        }
        if (rights.length > 0) {
          for (ri of rights) {
            r[ri] = true;
          }
        }
        return r;
      },
    };
    
    // trying to set the property
    
    console.log(Post.rs(['1', '2']));

Solution 2:

Little bit cleaner way:

const newUserRights = {
  A: { id: '1'},
  B: { id: '2'},
  C: { id: '3'},
  D: { id: '4'},
  E: { id: '5'},
  F: { id: '6'},
  G: { id: '7'},
};

var Post = {
  name: '',
  rs: function (rights = []) {
  const refDict = rights.reduce((obj, value) => {
  return {...obj, [value]: value};
  }, {});
  
  const userRights = {};
  
  for (const [, { id }] of Object.entries(newUserRights)) {
   userRights[id] = id in refDict && true; 
  }
  return userRights;
  },
};

// trying to set the property

console.log(Post.rs(['1', '2']));
  • Related