0

If I have an Object like this:

let obj = {
  a:{
    b:{
      c:{
        d:{
         e:'nonono'
       }
     }
   }
 }
}

and I know the structure of the Object like that:

now I want to change the innermost layer of the Object, it is the "e" property. I want to assign another value to "e". I don't want like these ways below:

  1. obj.a.b.c.d.e = 'another value';
  2. var str1 = 'a.b.c.d.e'; obj[str1[0]][str[1]][str[2]][str[3]][str[4]];
  3. var str1 = 'obj.a.b.c.d.e'; var str = str1 + "='another value'"; eval(str);

above these, I can change the property 'e' of the Object's Value, but I think it`s not grace to express what I mean.

If I have the Array like that: var arr= [a,b,c,d,e], I want to recursion a function to find the innermost layer Of the Object, but I try, if I reach the innermost layer of the Object, I lose the quote of the Object..... So I can't change the Object's Value that I want. I think I run these code, if you can help me to run.

let obj = {
  a: {
    b: {
      c: {
        d: {
          e: 'nonono'
        }
      }
    }
  }
}
let arr = ['a', 'b', 'c', 'd', 'e'];
let funKeepCite = (obj, index) => {
  if (obj[arr[index]]) {
    funKeepCite(obj[arr[index]], index + 1);
  } else {
    obj = 'test'
  }
}
funKeepCite(obj, 0)
console.log('the result', obj)

I can't change the value, I think I lose the quote of the Object, but the Answer of my question is use for .. in, and it can keep the quote of the Object, I am confused of these.

YakovL
  • 7,557
  • 12
  • 62
  • 102
NC LI
  • 149
  • 1
  • 1
  • 7
  • "lose the quote of the Object"? – jackarms Aug 15 '17 at 05:56
  • 2
    if you already know it's structure, then `obj.a.b.c.d.e = 'another value'` is the most obvious way to change the value of `obj.a.b.c.d.e` - your two other ways are simply a) wrong in the case of 2. and absurd in the case of 3. – Jaromanda X Aug 15 '17 at 05:57
  • Please show us your attempt at writing the recursive function, we cannot help you at fixing it otherwise. – Bergi Aug 15 '17 at 05:58
  • There are a number of duplicates, e.g. [*Access a nested property with a string*](https://stackoverflow.com/questions/33066787/access-a-nested-property-with-a-string) and [*Convert JavaScript string in dot notation into an object reference*](https://stackoverflow.com/questions/6393943/convert-javascript-string-in-dot-notation-into-an-object-reference). – RobG Aug 15 '17 at 06:07
  • If you want to do that repeatedly, you can use a reference: `let d = obj.a.b.c.d; d.e = 'yes'`. But not that this does not work directly on primitive types. – str Aug 15 '17 at 06:08
  • what if your object `obj` has more than one properties? would you like to check them as well? would you want to get the node which has the deepest property? – xGeo Aug 15 '17 at 06:26
  • sorry , i forget to paste my code,here it is.. – NC LI Aug 15 '17 at 07:29

3 Answers3

0

perhaps you want this kind

let obj = {
  a:{
    b:{
      c:{
        d:{
         e:'nonono'
       }
     }
   }
 }
}
function recurse(obj, val){
    for(var k in obj){
        if(typeof obj[k] == 'object') recurse(obj[k], val);
        else if(typeof obj[k] == 'string') obj[k] = val;
    }
}
recurse(obj, 'new');
console.log(obj);
raksa
  • 898
  • 6
  • 17
  • That will change **all** values to "new", not just the specified value. – RobG Aug 15 '17 at 06:12
  • yep, this is just suggest method. – raksa Aug 15 '17 at 06:14
  • thankx, I run the code,it works.but I have a question why 'obj[k]' can keep the quote of the 'obj',so it can change the value..... – NC LI Aug 15 '17 at 06:52
  • pass object as argument to function means pass referent of object, when we update its reference the original object will be updated too – raksa Aug 15 '17 at 07:01
  • ok, i know your meaning,thanx,can u help me see my example of above my func....I lose my mind why i lose reference of object – NC LI Aug 15 '17 at 07:29
0

You can't assign to obj which is just a local variable, you have to assign to a property. Recurse only until the second-to-last index, then use the last one for the assignment:

function funKeepCite(obj,index) {
  if (index < arr.length - 1) {
    funKeepCite(obj[arr[index]], index+1);
  } else if (index < arr.length) {
    obj[arr[index]] = 'test';
  } else
    throw new RangeError("there must be at least one property name in the array");
  }
}

Alternatively, use recursion with a return value and always assign:

function funKeepCite(obj, index) {
  if (index < arr.length) {
    obj[arr[index]] = funKeepCite(obj[arr[index]], index+1);
    return obj;
  } else {
    return 'test';
  }
}
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • thanx I know your meanning, i forget I have to set the value to last_second property.like these i change my fun.thx bro,your also work well.`let funKeepCite = (obj,index)=>{ if(typeof obj[arr[index]] == 'object'){ funKeepCite(obj[arr[index]],index+1); }else{ obj[arr[index]] = 'test' } }` – NC LI Aug 15 '17 at 08:11
0

I know this is not the best way to do it but as for your case, and "you already know the object's structure"

function setInnerObjVal will change the value of all the innermost object in obj.

let obj = {
  a: {
    b: {
      c: {
        d: {
          e: 'nonono'
        }
      }
    }
  }
  //try uncommenting the below codes
  /*,
  x: {
    y: {
      z: {
        val: 'maybe?'
      }
    }
  }*/
};

function setInnerObjVal(obj1, newVal, callback) {
  for (var i in obj1) {
    if (typeof obj1[i] == 'object') {
      setInnerObjVal(obj1[i], newVal, callback);
    } else {
      obj1[i] = newVal;
      if (typeof callback === 'function')
        callback();
      return;
    }
  }
}

//implement a callback to be called when the function is done.
//just in case your object is way way way deeper and you need to wait for the update to finish
var myCallback = function() {
  console.log(obj);
  //or do something else.
}

setInnerObjVal(obj, 'yesyesyes', myCallback);
//console.log(obj); //this will still log the oldvalue 'nonono' in case obj has a very deep object.

NOTE:

This function will change ALL objects under obj. (try uncommenting the values x,y,z,val)

xGeo
  • 2,149
  • 2
  • 18
  • 39
  • ok,your code also can work,but result in the end.not keep the oldvalue, in the end ` console.log(obj)` , this will change value,it will log 'yesyesyes',that`s result~~ – NC LI Aug 16 '17 at 03:48
  • as I have said, this will miss the timing if you have an object with very deep innermost node, like 1000 levels or something. so, the best way is to have a callback function which will be called by the recursion itself after it is finished. as in my example, of course it will still log 'yesyesyes' since `obj` the recursion is completed in a very short time. – xGeo Aug 16 '17 at 07:47