首页 > 解决方案 > Unlike Java, does an assignment operator in Javascript mean that all operations on the LHS are reflected for the RHS?

问题描述

This is in continuation to the answer posted for the question "Convert JavaScript dot notation object to nested object".

The code works like a charm but I'm unable to wrap my head around how!! So a few days later + a situation where my console.logs actually exceed my lines of code :P.. Here's my question:

Below code for JavaScript function:

function deepen(o) {
  var oo = {}, t, parts, part;
  for (var k in o) {
    t = oo;
    parts = k.split('.');
    var key = parts.pop();
    while (parts.length) {
      part = parts.shift();
      t = t[part] = t[part] || {};
    }
    t[key] = o[k]
  }
  return oo;
}

console.log(
  deepen({ 'ab.cd.e' : 'foo', 'ab.cd.f' : 'bar', 'ab.g' : 'foo2' })
);

It deepens a JSON object from :

{ 'ab.cd.e' : 'foo', 'ab.cd.f' : 'bar', 'ab.g' : 'foo2' }

Into a nested object :

{ab: {cd: {e:'foo', f:'bar'}, g:'foo2'}}

I get the part where for each key value pair, the logic pops the last element post splitting into an array by ".".

That becomes the key.

What I'm not understanding is the below.

1) The function is returning 'oo' but the operations are all on 't'. The only relationship is that t is being assigned the'empty object' "oo" at the beginning of every iteration on the flat JSON.

2) after the "while (parts.length)" loop, oo miraculously has the nested structure whereas t has one level below it. if oo is assigned to t, how is that possible?

3) I don't see the function being called recursively. How is 00 getting nested beyond the first element of the flat JSON?

标签: javascript

解决方案


我将首先用一些更好的名称重新定义函数,这样解释起来就容易多了。

function deepen(object) {
  var nestedObject = {}, cursor, nestingPath, nodeKey;

  for (var dotKey in object) {
    cursor = nestedObject;
    nestingPath = dotKey.split('.');
    var leafKey = nestingPath.pop();

    while (nestingPath.length) {
      nodeKey = nestingPath.shift();
      cursor = cursor[nodeKey] = cursor[nodeKey] || {};
    }
    cursor[leafKey] = object[dotKey];
  }

  return nestedObject;
}

我的猜测是不完全知道 while 循环是如何工作的。重要的是要知道,当两个变量引用同一个对象时,当你改变一个时,它们都会改变。它们是同一个对象,但您选择了两个句柄。

让我举个例子:

object = {};
cursor = object;

cursor.foo = "bar";

object; //=> {foo: "bar"}
cursor; //=> {foo: "bar"}

cursor.a = {};

object; //=> {foo: "bar", a: {}}
cursor; //=> {foo: "bar", a: {}}

cursor = cursor.a;

object; //=> {foo: "bar", a: {}}
cursor; //=> {}   <- this is ^

cursor.b = "c";

object; //=> {foo: "bar", a: {b: "c"}}
cursor; //=> {b: "c"}

while 循环主要基于此原则。这并不容易解释,但我希望上面能澄清一些事情。


另一件可能令人困惑的事情是这条线:

cursor = cursor[nodeKey] = cursor[nodeKey] || {};
// read as
cursor = (cursor[nodeKey] = (cursor[nodeKey] || {}));

这也可以写成:

if (!cursor[nodeKey]) cursor[nodeKey] = {};
cursor = cursor[nodeKey];

nodeKey如果属性不存在(虚假),这会将一个新对象分配给动态属性。然后cursor被赋值给嵌套对象里面,类似于我上面的例子cursor = cursor.a


推荐阅读