3

I'm just wondering if it's possible to refer to self (object) value inside the object sibling like below?

[
  {
    "name": "Zulh",
    "name_uppercase": uppercase(self.name) // expects ZULH
  },
  {
    "name": "John",
    "name_uppercase": uppercase(self.name) // expects JOHN
  }
]

Note:

Code for uppercase is omitted for brevity. In my real code, it's doing synchronous complex stuff and is not actually simple string case manipulation like that.

Kokogino
  • 984
  • 1
  • 5
  • 17
Zulhilmi Zainudin
  • 9,017
  • 12
  • 62
  • 98

7 Answers7

4

Using a GETTER

If you want to keep it dynamic and make it work even if you change the name property, you can use a GETTER to do this kind of thing:

const names = [
  {
    "name": "John",
    get name_uppercase() {
      return this.name.toUpperCase();
    }
  }
]

console.log(names[0].name_uppercase)

GETTER for multiple objects

You don't have to write this for every property manually! Use .forEach:

const names = [
  {
    "name": "John"    
  },
  {
    "name": "Mike"
  }
]

names.forEach(object => {

  Object.defineProperty(object, 'nameUppercase', {
  
    get: function() { return this.name.toUpperCase() }
  
  });
  
});



console.log(names[0].nameUppercase)
console.log(names[1].nameUppercase)

Using a class and a GETTER

Or as @Rajesh pointed out you can use a class instead:

class Person {

  constructor(name) {
  
    this.name = name;
    
  }

  get nameUpperCase() {
  
    return this.name.toUpperCase();
  
  }

}

const names = [ new Person("John"), new Person("Mike")];

console.log(names[0].nameUpperCase);
console.log(names[1].nameUpperCase);
Ivan
  • 34,531
  • 8
  • 55
  • 100
  • so OP has to write a `getter` for each and every object in the array? – Isaac Jul 11 '18 at 09:02
  • 1
    A better approach would be to create a class and add this function to prototype – Rajesh Jul 11 '18 at 09:05
  • For more info on my previous comment, refer following **[JSFiddle](http://jsfiddle.net/a46v2wp9/4/)** – Rajesh Jul 11 '18 at 09:10
  • Indeed, that's what I thought about @Rajesh, I'll add this to my answer – Ivan Jul 11 '18 at 09:12
  • @Ivan The point of defining a class is to eradicate unnecessary loop. Adding a getter property in loop is a bad idea. Hence I depicted both possible approaches in fiddle link – Rajesh Jul 11 '18 at 09:14
3

You can't reference an object during initialization when using object literal syntax.. Inshort, that's not possible what you expect above

Well, you can use map and add additional/modified properties to you object like

data.map(o=> ({name: o.name, upper_case : o.name.toUpperCase()}))

var data = [
  {
    "name": "Zulh" 
    
  },
  {
    "name": "John" 
   
  }
];

var x = data.map(o=> ({name: o.name, upper_case : o.name.toUpperCase()}))

console.log(x)
Muhammad Usman
  • 10,039
  • 22
  • 39
0

You can use Array.forEach and update the objects in Array

var data = [{"name": "Zulh"},{"name": "John"}];
data.forEach(o=> o.upper_case = o.name.toUpperCase());
console.log(data);
Nikhil Aggarwal
  • 28,197
  • 4
  • 43
  • 59
0

Why not create a function that transforms your incoming array? A way to do it could be like this:

const value = [
  {
    "name": "Zulh"
  },
  {
    "name": "John"
  }
];

const transform = ( array, propertyToUpdate, propertyToCreate, transformation ) => {
  return array.map( item => ({ ...item, [propertyToCreate]: transformation( item[propertyToUpdate] ) }) );
};

console.log( transform( value, 'name', 'name_uppercase', ( item ) => item.toUpperCase() ) );
Icepickle
  • 12,689
  • 3
  • 34
  • 48
0

You can't do this with the object literal syntax, since it's 'this' property will not be set at that time. For example, if you'd run your code in the browser, 'this' would refer to the window object.

So you'll either have to use one of the other answers or go for a 'class':

var uppercase = function( str ) {
  return str.toUpperCase();
};
var Person = function( name ) {
  this.name = name;
  this.name_uppercase = uppercase( this.name );
};
var persons = [
  new Person( 'zuhi' ),
  new Person( 'john' )
];
console.log( persons );

Same can be written in ES6 class syntax.

Shilly
  • 8,511
  • 1
  • 18
  • 24
0

I would suggest 2 approaches:

  1. If you DO NOT want to change your initial array ( which is recommended ), use map which returns a new array with changed values ( calls a function for every array item ) .

See below

let arr = [
  {
    "name": "Zulh",
  },
  {
    "name": "John",
  }
];
const newArr = arr.map((x)=>{
 x.name_uppercase = (x.name).toUpperCase()
    return x
})
console.log(newArr)
  1. If you don't mind changing your initial array, you can use forEach. Keep in mind that unlike map, forEach changes your array and so it doesn't return anything.

let arr = [
  {
    "name": "Zulh",
  },
  {
    "name": "John",
  }
];
arr.forEach((x)=>{
  x.name_uppercase = (x.name).toUpperCase()
})
console.log(arr)

So it all depends if you want to change your current array or not

Mihai T
  • 17,254
  • 2
  • 23
  • 32
0

How about using a getter method?

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get

The get syntax binds an object property to a function that will be called when that property is looked up.

foo = [
  {
    "name": "Zulh",
    get name_uppercase () {
        return (this.name).toUpperCase();
    }
  },
  {
    "name": "John",
    get name_uppercase () {
        return (this.name).toUpperCase();
    }
  }
]

console.log(foo[1].name_uppercase); //returns JOHN

Hope it helps :)

Nimeshka Srimal
  • 8,012
  • 5
  • 42
  • 57