0

I am running into an issue when attempting to access individual fields of objects stored within an array.

I have an array of non-uniform objects, we'll call cache.

var cache = new Array();

The put function allows adding items to the array.

function put(item, value) {
  cache[item] = value;
}

An example of usage:

var item_abc = { item_a: 'some value', item_b: 'another value' };

put('ITEM_ABC',item_abc);

The problematic function is called update which updates a field for an item in the array with a new value.

function update(item, field, value) {
  cache[item][field] = value;
}

Here is the troublesome code:

update('ITEM_ABC','item_a','a new value');

In the browser, this seems to work fine, but in a "--use_strict" Node.js environment, it runs into issues. I'm assuming this is related to precedence and the way in which multi-dimensional arrays are evaluated versus object fields.

How do I reference a object field without knowing the field name at runtime, when the object itself exists within an array?

Reading from the field in question always returns undefined.

function check(item, field) {
  console.log(cache[item][field]);
  if (typeof cache[item][field] !== 'undefined')
    console.log('field exists');
  else
    console.log('field undefined');
}

Running:

check('ITEM_ABC','item_a');

Outputs:

undefined
'field undefined'
7
  • Can you tell us the error you're running into when using use strict? Commented Jun 4, 2018 at 19:35
  • 2
    I don't see any JSON in this question. JSON is a data serialization format. It sounds like you're talking about JavaScript objects. Commented Jun 4, 2018 at 19:42
  • There is no error, but typeof cache[item][field] is always undefined Commented Jun 4, 2018 at 19:43
  • 1
    Start with var cache = {}; (JavaScript doesn't have associative arrays.) Commented Jun 4, 2018 at 19:43
  • If u use strict mode u can't have a variable named package. Commented Jun 4, 2018 at 19:47

1 Answer 1

1

I recommend simplified get and put functions. If you would like to implement a specialized update, it should utilize get and put

const cache =
  {}

const get = (key) =>
  cache[key]

const put = (key, value) =>
  cache[key] = value

const update = (key, field, value) =>
  put ( key
      , { ... get (key) || {}, [field]: value }
      )

put ('foo', { a: 1 })

console.log (get ('foo')) // { a: 1 }

update ('foo', 'a', 2)

console.log (get ('foo')) // { a: 2 }

Above, we write functions as simple as possible. But perhaps a more flexible way to write update would be something like Object.assign where you can update an object using another object

const cache =
  {}

const get = (key) =>
  cache[key]

const put = (key, value) =>
  cache[key] = value

const update = (key, obj) =>
  put ( key
      , Object.assign (get (key) || {}, obj)
      )
      
put ('foo', { a: 1, b: 2 })

console.log (get ('foo')) // { a: 1, b: 2 }

update ('foo', { a: 2, c: 2 })

console.log (get ('foo')) // { a: 2, b: 2, c: 2 }

If you want to support multiple caches, you can wrap the get, put, update interface in another function. Below we demonstrate the ability to interact with two separate caches, c1 and c2

const makeCache = () =>
{ const cache =
    {}

  const get = (key) =>
    cache[key]

  const put = (key, value) =>
    cache[key] = value

  const update = (key, obj) =>
    put ( key
        , Object.assign (get (key) || {}, obj)
        )
        
  return { get, put, update }
}
 
const c1 = makeCache ()
const c2 = makeCache ()

c1.put ('foo', { a: 1 })
c2.put ('foo', { a: 2 })

console.log (c1.get ('foo')) // { a: 1 }
console.log (c2.get ('foo')) // { a: 2 }

c1.update ('foo', { z: 3 })

console.log (c1.get ('foo')) // { a: 1, z: 3 }
console.log (c2.get ('foo')) // { a: 2 }

Lastly, using an object {} for the cache is not really ideal as the key is always converted to a string before the value can be associated to it. The same problem happens when we use an array [] as you did in your original code. Watch what happens when we use a non-primitive value as a key...

const cache =
  {}

const get = (key) =>
  cache[key]

const put = (key, value) =>
  cache[key] = value

const update = (key, obj) =>
  put ( key
      , Object.assign (get (key) || {}, obj)
      )

const k1 = { foo: "bar" }
const k2 = { hello: "world" }

put (k1, 1)

console.log (get (k1)) // 1
console.log (get (k2)) // 1 ???

Above, even though we never put a value for k2, we can still get a value because the string representation of k1 and k2 are the same – each is converted to [object Object] before the value is stored. Below, we avoid this problem using Map

const cache =
  new Map

const get = (key) =>
  cache .get (key)

const put = (key, value) =>
  cache .set (key, value)

const update = (key, obj) =>
  put ( key
      , Object.assign (get (key) || {}, obj)
      )

const k1 = { foo: "bar" }
const k2 = { hello: "world" }

put (k1, 1)

console.log (get (k1)) // 1
console.log (get (k2)) // undefined

put (k2, 2)
   
console.log (get (k1)) // 1
console.log (get (k2)) // 2

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.