I am currently working a plugin with a settings variable that is fairly deep (3-4 levels in some places). Following the generally accepted jQuery Plugin pattern I have implemented a simple way for users to modify settings on the fly using the following notation:
$('#element').plugin('option', 'option_name', 'new_value');
Here is the code similar to what I am using now for the options method.
option: function (option, value) {
    if (typeof (option) === 'string') {
        if (value === undefined) return settings[option];
        if(typeof(value) === 'object')
            $.extend(true, settings[option], value);
        else
            settings[option] = value;
    }
    return this;
}
Now consider that I have a settings variable like so:
var settings = {
    opt: false,
    another: {
        deep: true
    }
 };
If I want to change the deep settings I have to use the following notation:
$('#element').plugin('option', 'another', { deep: false });
However, since in practice my settings can be 3-4 levels deep I feel the following notation would be more useful:
$('#element').plugin('option', 'another.deep', false);
However I'm not sure how feasible this is, nor how to go about doing it. As a first attempt I tried to "traverse" to the option in question and set it, but if I set my traversing variable it doesn't set what it references in the original settings variable.
option: function (option, value) {
    if (typeof (option) === 'string') {
        if (value === undefined) return settings[option];
        var levels = option.split('.'),
            opt = settings[levels[0]];
        for(var i = 1; i < levels.length; ++i)
            opt = opt[levels[i]];
        if(typeof(value) === 'object')
            $.extend(true, opt, value);
        else
            opt = value;
    }
    return this;
}
To say that another way: By setting opt after traversing, the setting it actually refers to in the settings variable is unchanged after this code runs.
I apologize for the long question, any help is appreciated. Thanks!
EDIT
As a second attempt I can do it using eval() like so:
option: function (option, value) {
    if (typeof (option) === 'string') {
        var levels = option.split('.'),
            last = levels[levels.length - 1];
        levels.length -= 1;
        if (value === undefined) return eval('settings.' + levels.join('.'))[last];
        if(typeof(value) === 'object')
            $.extend(true, eval('settings.' + levels.join('.'))[last], value);
        else 
            eval('settings.' + levels.join('.'))[last] = value;
    }
    return this;
}
But I really would like to see if anyone can show me a way to not use eval. Since it is a user input string I would rather not run eval() on it because it could be anything. Or let me know if I am being paranoid, and it shouldn't cause a problem at all.
The issue you're running into here comes down to the difference between variables pointing to Objects and variables for other types like Strings.  2 variables can point to the same Object, but not to the same String:
  var a = { foo: 'bar' };
  var b = 'bar';
  var a2 = a;
  var b2 = b;
  a2.foo = 'hello world';
  b2 = 'hello world';
  console.log(a.foo); // 'hello world'
  console.log(b); // 'bar'
Your traversal code works great until the last iteration of the loop, at which point opt is a variable containing the same value as deep inside the object settings.opt.another.  Instead, cut your loop short and use the last element of levels as a key, like
  var settings = {
    another: {
      deep: true
    }
  };
  var levels = 'another.deep'.split('.')
    , opt = settings;
  // leave the last element
  var i = levels.length-1;
  while(i--){
    opt = opt[levels.shift()];
  }
  // save the last element in the array and use it as a key
  var k = levels.shift();
  opt[k] = 'foobar'; // settings.another.deep is also 'foobar'
At this stage opt is a pointer to the same Object as settings.another and k is a String with the value 'deep'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With