【问题标题】:JavaScript stop referencing object after pass it to a functionJavaScript 在将对象传递给函数后停止引用它
【发布时间】:2013-05-08 04:20:29
【问题描述】:

我知道 JavaScript 通过引用传递对象,因此我在使用以下代码时遇到了很多麻烦:

function doGradeAssignmentContent(dtos) {
                    var x = 5;
                    var allPages = [];
                    var stage = new App.UI.PopUpDisplay.PopUpStageAssignmentGrader(null, that);// pass launch element
                    for(var i = 0; i < dtos[0].result.students.length; ++i) {
                        var pagesSet = [];
                        for(var j = 0; j < dtos[0].result.questions.length; ++j) {
                            var questionObject = jQuery.extend(true, {}, new Object());
                            questionObject = dtos[0].result.questions[j];
                            if(dtos[0].result.students[i].answers[j].assignmentQuestionId === questionObject.questionId) {// expected, if not here something is wrong
                                questionObject.answer = dtos[0].result.students[i].answers[j].studentAnswer;
                                questionObject.pointsReceived = dtos[0].result.students[i].answers[j].pointsReceived;
                            } else {
                                var theAnswer = findAssociatedStudentAnswer(questionObject.questionId, dtos[0].result.students[i].answers[j]);
                                if(theAnswer !== null) {
                                    questionObject.answer = theAnswer.studentAnswer;
                                    questionObject.pointsReceived = theAnswer.pointsReceived;
                                } else {
                                    alert("Unexpected error. Please refresh and try again.");
                                }
                            }
                            pagesSet[pagesSet.length] = new App.UI.PopUpDisplay.StageAssignmentGradingPages[dtos[0].result.questions[j].questionType.charAt(0).toUpperCase() + dtos[0].result.questions[j].questionType.slice(1) + "QuestionAssignmentGradingPage"](j + 1, questionObject);
                        }
                        var studentInfo = {};
                        studentInfo.avatar = dtos[0].result.students[i].avatar;
                        studentInfo.displayName = dtos[0].result.students[i].displayName;
                        stage.addPageSet(pagesSet, studentInfo);
                    }
                    stage.launch();
                }

首先让我向您展示结果(dtos)的样子,以便您更好地了解该函数是如何解析它的:

结果(dtos)是一个对象,看起来像:

  • dtos 数组
  • dtos[0],静态总是在这里
  • dtos[0].result,静态总是在这里
  • dtos[0].questions 数组
  • dtos[0].questions.index0 - indexN。这描述了我们的问题,每个问题都是一个对象
  • dtos[0].students 数组
  • dtos[0].students[0]-[n].answers 数组。每个学生数组/对象都有一个 Answers 数组。每个学生将在此答案数组中拥有与 dtos[0].questions 中的问题一样多的元素。每个元素都是一个对象

现在我们在这里做的是创建这个对象阶段。这里重要的是它有一个名为“this.studentsPages”的数组。该数组最终将包含与 dtos[0].students 中的学生一样多的条目。

所以我们遍历这个 for 循环,剖析 dtos 数组并创建 pagesSet 数组。 我的问题来了。在 for 循环的第一次迭代中,我创建了这个 questionObject 元素。我也试过只做 var questionObject = {},但你现在看到的只是试图解决我看到的问题,但它也没有工作。

所以在外部 for 循环的第一次迭代结束时,我调用了 stage.addPageSet,这就是这里发生的情况:

var pageObject = [];
            pageObject["questions"] = pageSet;
            pageObject["displayName"] = studentInfo.displayName;
            this.studentsPages[this.studentsPages.length] = pageObject;

            if(this.studentsPages.length === 1) {// first time only
                for(var i = 0; i < pageSet.length; ++i) {
                    this.addPage(pageSet[i]);
                }
            }

这里需要注意的重要一点是我将 pageObject 添加到 this.studentsPages 上,这是第一次调用之前的空数组。 pageObject 现在有 pageSet 以及更多信息。请记住,pageSet 是一个对象,因此通过引用传递。

在 for 循环的下一次迭代中,当我点击这一行时:

questionObject.answer = dtos[0].result.students[i].answers[j].studentAnswer;

出错了。这会更改 questionObject 的本地副本,但它也会更改传递给 addPageSet 并在第一次迭代中添加到 studentsPages 数组的 questionObjec 的副本。所以,如果我只有 2 个学生进来,那么当一切都说完之后,studentPages 包含 2 个相同的对象。这不应该是真的。

问题是 doGradeAssignmentContent 函数中的 questionObject 保留了对在前一次迭代中创建的 Object 的引用,然后在所有后续迭代中覆盖它。

我能做些什么来解决这个问题?

感谢您的帮助!

【问题讨论】:

  • 我一直在尝试,但没有成功。
  • 我尝试在创建 questionObject 时将 jQuery.extend 函数添加到主 for 循环中,并且我还尝试在 addPageSet 中使用 pageSet 参数执行相同的操作。我尝试克隆它并将克隆添加到this.studentsPages,但仍然存在同样的问题。有什么建议吗?

标签: javascript copy clone pass-by-reference pass-by-value


【解决方案1】:

如果没有仔细研究,我相信您需要更改以下内容:

// Before:
var questionObject = jQuery.extend(true, {}, new Object());
questionObject = dtos[0].result.questions[j];

// After:
var questionObject = jQuery.extend(true, {}, dtos[0].result.questions[j]);

如果代码中是否有其他实例需要应用它,我并没有仔细研究,但核心概念是利用 jQuery 的深层复制来生成您不希望保留引用的对象的副本到。

【讨论】:

  • 我不想要它的副本/做 questionObject 将复制对象。我只想要一个全新的副本,所有内容都为默认值。
  • 实际上,误读了正在发生的事情。我明白你现在在说什么了。会试一试。谢谢。
  • 效果很好。感谢您的解决方案!
猜你喜欢
  • 2011-12-07
  • 1970-01-01
  • 2012-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-04
  • 2017-08-20
相关资源
最近更新 更多