将knockout对象转换为纯JavaScript对象时的无限循环

Byr*_*ahl 5 knockout.js

文档中给出了Folliwing说明,我有以下视图模型:

var newContactViewModel = function () {
    var self = this;

    self.Name = ko.observable();
    self.Address = ko.observable();
    self.City = ko.observable();
    self.State = ko.observable();
    self.PostalCode = ko.observable();

    self.Save = function () {
        $.ajax({
            type: "POST",
            url: "/contact",
            data: ko.toJS(self), //infinite loop here
            success: state.OnSaved
        });
    };
};
Run Code Online (Sandbox Code Playgroud)

self.Save调用该方法时,会发生无限循环.Chrome实际上将错误报告为:

未捕获RangeError:超出最大调用堆栈大小

如果我使用ko.mapping.toJS(self)而不是ko.toJS(self),那么我会得到一个稍微更具启发性的错误,但没有真正的错误"消息":

无限循环错误

如果我换掉ko.toJS(self)类似的东西{ Name: self.Name(), Address: self.Address() /* etc */ },那么一切正常.似乎它正在尝试转换Save方法并重新调用该方法.

在KnockoutJS中有一个错误,或者在我如何使用它时会出现问题.我更喜欢后者.思考?

Jef*_*ado 14

我发现了代码的问题. ko.toJS保留对象中的函数,以便它能够很好地映射它.但是,jquery将调用数据对象上的所有函数来尝试获取值.这反过来导致无限循环.

您需要将Save函数标记为不映射.不幸的是,该toJS功能似乎无法做到这一点.它将保留对象的所有成员.幸运的是,映射插件允许您这样做.

要排除成员,请将ignore选项设置为包含的数组,'Save'Save在映射时忽略该成员.

var data = ko.mapping.toJS(self, {
    ignore: ['Save']
});
Run Code Online (Sandbox Code Playgroud)

如果您没有使用映射插件,则始终可以选择Save从JS对象中删除该函数.

self.Save = function () {
    $.ajax({
        type: "POST",
        url: "/contact",
        data: self.ToData(),
        success: state.OnSaved
    });
};
self.ToData = function () {
    var data = ko.toJS(self);
    delete data.Save; // remove functions
    delete data.ToData;
    return data;
};
Run Code Online (Sandbox Code Playgroud)

另一方面,我建议不要尝试使用视图模型实例作为调用的数据.我会明确地创建数据对象.当然它有可能很长,但这种方法很可能总能奏效.

self.ToData = function () {
    return ko.toJS({
        Name: self.Name,
        Address: self.Address,
        City: self.City,
        State: self.State,
        PostalCode: self.PostalCode
    });
};
Run Code Online (Sandbox Code Playgroud)