Javascript 递归是如何在这个代码段中发生的?
查看调用堆栈并观察,现在当我按下F10时,“Watch”中的行值变为“object object”,正因为如此,所有事情都发生了,我直到现在才理解流程,之后发生了什么并不清楚。现在转到wards,为什么即使我在第8行提供了一个断点,代码也不在第8行停止 这就是问题所在 我试图理解这个代码片段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(".");
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);