Javascript 递归是如何在这个代码段中发生的?

Javascript 递归是如何在这个代码段中发生的?,javascript,object,recursion,Javascript,Object,Recursion,查看调用堆栈并观察,现在当我按下F10时,“Watch”中的行值变为“object object”,正因为如此,所有事情都发生了,我直到现在才理解流程,之后发生了什么并不清楚。现在转到wards,为什么即使我在第8行提供了一个断点,代码也不在第8行停止 这就是问题所在 我试图理解这个代码片段 function assign(obj, prop, value) { if (typeof prop === "string") prop = prop.split(".");

查看调用堆栈并观察,现在当我按下F10时,“Watch”中的行值变为“object object”,正因为如此,所有事情都发生了,我直到现在才理解流程,之后发生了什么并不清楚。现在转到wards,为什么即使我在第8行提供了一个断点,代码也不在第8行停止

这就是问题所在

我试图理解这个代码片段

function assign(obj, prop, value) {
    if (typeof prop === "string")
        prop = prop.split(".");

    if (prop.length > 1) {
        var e = prop.shift();
        assign(obj[e] =
                 Object.prototype.toString.call(obj[e]) === "[object Object]"
                 ? obj[e]
                 : {},
               prop,
               value);
    } else
        obj[prop[0]] = value;
}

var obj = {},
    propName = "foo.bar.foobar";

assign(obj, propName, "Value");
当函数不返回任何内容时,递归是如何发生的? 内部调用中的参数值如何作为最顶层调用堆栈(assign function)中的函数进行更改


谢谢大家的回答,但我的确切问题是,在这一行(第8行)中它是如何发生的。

Object.prototype.toString.call(obj[e])===“[Object Object]”
从来都不是真的。它总是
“[对象未定义]”

  • 开始时:

    obj:: {}
    prop:: 'foo.bar.foobar'
    
  • 在从内部函数(
    if
    )进行第一次调用之前:

  • 在从内部函数进行第二次调用之前(
    if
    ):

  • 最后一次执行时,由于
    prop.length
    为1(
    else
    -不再递归):


  • Javascript中的对象总是作为引用传递,请参考@Tiny Giant的注释。

    Object.prototype.toString.call(obj[e])===“[Object Object]”
    只是用一种非常丑陋的方式来表示“(如果)这个对象确实存在……”。我不会详细解释它是如何工作的,因为这不是一个好例子,您可能不理解它

    代码想要的是能够添加/编辑对象属性。例如:

    var person = {name: 'Liana', hair: {color:'red', style:'long'}};
    assing(person, 'name', 'George');
    
    ……等等。但是,如果要编辑嵌套属性(如头发颜色),该怎么办

    assign(人、'hair.color'、'brown')

    基本上,
    assign
    函数被调用两次:

    • assign(人,'hair.color',…)
    • 这检测到我们正在编辑
      头发
      中的嵌套属性(
      颜色
      ),并且 它确保
      头发
      确实存在于
      体内
    • 如果没有,它将创建
      person.hair
      (这就是丑陋的线条)
    • 然后调用
      assing(person.hair,'color','brown')

    我个人会这样写函数:

    function assign(object, prop, value) {
        prop = prop.split('.');
    
        if(prop.length > 1) {
            var first = prop.shift();
            prop = prop.join('.');
            if(typeof object[first] != 'object')
                object[first] = {};
            assign(object[first], prop, value);
        } else {
            object[prop] = value;
        }
    }
    
    递归是如何发生的,因为函数没有返回任何内容 ?

    递归不需要返回值。这里,条件
    prop.length>1
    将在将值设置为所需属性后停止递归

    如何将内部调用中参数的值更改为 最顶层调用堆栈(分配函数)中的函数是否已完成

    我不知道你在问什么。我想你是在问这条线路

    assign(obj[e] =
                     Object.prototype.toString.call(obj[e]) === "[object Object]"
                     ? obj[e]
                     : {},
                   prop,
                   value);
    

    此代码检查
    obj
    是否为对象。如果
    obj
    不是对象,则它将在递归调用本身中更改为对象。

    javascript中的对象是通过引用传递的,而不是通过值传递的。这意味着,当您将对象引用作为函数的参数传递时,函数的参数仍然引用同一个对象。使用调试器浏览代码可能会很有用。调试已经完成,你们能解释一下-object.prototype.toString.call(obj[e])值是如何实现的吗第一次“object object”,以及当最高调用堆栈中的函数开始返回时,为什么代码没有在函数的内部调用处停止,即使我在那里应用了断点?
    object.prototype.toString.call(obj[e])==“[object object]“
    在上述代码段的第一次运行中不应返回
    true
    。另一方面,我认为它也可以检查为
    typeof obj[e]==“object”
    ,即使不需要,如果这些函数返回结果对象以进行链接,效果会更好。你的代码片段很棒,我希望我能接受这个答案,但我的问题是关于我编写的代码的工作流程。@Promotion Nabid回答比我解释得更好。我写这段代码是因为我认为它可以帮助您理解原始代码的功能。(这实际上是同一件事,只是用一种更模糊的方式写的)如果我添加obj来观察它的值,它会像这样变化--------------obj={},然后{foobar:'value'},然后{bar:{foobar:'value'},然后{foobar:{foobar:'value'}}。}:(我不明白它是如何从{foobar:'Value'}变为{bar:{foobar:'Value'}}等等。没错。实际上,当递归调用返回时,watch中的obj也会更新!与其跟踪watch,不如将console.log()放在需要的地方打印obj。
    var person = {name: 'Liana', hair: {color:'red', style:'long'}};
    assing(person, 'name', 'George');
    
    function assign(object, prop, value) {
        prop = prop.split('.');
    
        if(prop.length > 1) {
            var first = prop.shift();
            prop = prop.join('.');
            if(typeof object[first] != 'object')
                object[first] = {};
            assign(object[first], prop, value);
        } else {
            object[prop] = value;
        }
    }
    
    assign(obj[e] =
                     Object.prototype.toString.call(obj[e]) === "[object Object]"
                     ? obj[e]
                     : {},
                   prop,
                   value);