" TypeError:对象不是函数"当使用击倒和微风时

时间:2014-12-30 22:10:20

标签: knockout.js breeze

问题

  

EntityManager.saveChanges时出现“ TypeError:对象不是函数 ”错误。在breeze向服务器发送任何内容之前出现错误。

     

当我读取(长)堆栈跟踪时,我发现错误是在名为InitializeEntityPrototype.prototype.getProperty的Breeze方法中抛出的。

您可能会遇到其他地方出现此错误;这恰好是我今天发现它的地方。

原因

请注意,我的应用程序使用Knockout(ko)。这意味着我的实体模型由微风“ko”模型适配器管理,该适配器期望 每个数据属性 ko.observable (an { {1}}或observable)。这意味着您的属性值实现为函数,而不是原始数据类型,数组或对象。

Breeze用可观察的属性初始化我的实体,所以我不必自己做。但是,当我在我的代码中设置实体模型时,由保留这些可观察对象。

ko编程中最常见的错误之一是设置属性而不是调用属性设置器。

observableArray

当我错误地将“foo”分配给todo.Description("foo"); // Correct ... call the ko.observable assignment function todo.Description = "foo"; // WRONG ... wipes out the observable function !!! 时,可观察功能就消失了...... Breeze也能够监控对该属性的更改。

我的数据绑定HTML控件似乎可以继续工作。 Knockout不必绑定到observable;它将很乐意绑定到原始数​​据值。但现在这变成了一次性只读绑定。该物业不再可观察。对属性的后续更改不会传播到屏幕。

换句话说,我的错误分配会导致UI行为出现无声错误。

但是当Breeze试图处理财产时,我的错误并不是沉默。 Breeze假定实体数据属性是ko函数。 Breeze ko模型适配器无需检查......它只是调用它所假定的功能。这是(内部)实体todo.Description实现:

getProperty

如果proto.getProperty = function (propertyName) { return this[propertyName](); }; 不是函数,你可以看到为什么会抛出异常。

可悲的是,对于我来说,错误可能会被抛到Breeze操作的深处。错误消息“对象不是函数”(或类似的东西)可能与任何事物有关。我不太可能建立连接。

这个S.O.问题是提醒我寻找这个特殊原因。

怎么办?

这显然是我的错。现在我必须找到我分配实体属性的位置而不是调用函数...并修复它。

我的搜索取决于知道属性名称。目前的错误消息没有告诉我名字。因此,我必须断开代码并捕获错误,因为它被抛出。

“简单”的权宜之计是使用this[propertyName]版本在 breeze.debug.js 中暂时修补此方法。

  1. 在编辑器中打开 breeze.debug.js
  2. 找到“try/catch
  3. 将其更改为:

    return this[propertyName]();
  4. 在开发者工具打开的情况下再次运行应用程序

  5. 它应该停在proto.getProperty = function(propertyName) { try { return this[propertyName](); } catch (err) { debugger; err.message = propertyName + ' is not a ko function; did you wipe it out by assignment?\n' + (err.message || ''); throw err; } } 行,在那里您将学习属性名称和所涉及的实体。

    Breeze应该提供更丰富的错误消息吗?

    如果Breeze为我写这个消息会很好。事实上,该团队正在考虑这样做。

    主要障碍是表现。 debuggergetProperty方法处于热门道路上。它们被调用很多,特别是在查询结果实现期间。 Breeze团队对这个敏感区域的额外逻辑持怀疑态度。我们不希望每个人都付出巨大的代价来捕捉开发者的错误,至少不是在生产(缩小的)Breeze库中。

    让我们给Breeze团队时间来解决这个问题。

1 个答案:

答案 0 :(得分:3)

您的问题写得很好,涉及到一个常见问题,并且对于搜索此特定问题的其他人可能会有所帮助。但是,它仍然可能要求意见

无论如何......

我和我的同事从您的情况“淘汰税”中解决了这个问题:您需要处理一些编程方面的不便,以换取使用优秀的MVVM库。当您data-bind="visible: !myObservable"并忘记将其作为获取值的函数执行时,会出现同一问题的不同实例。

回答这个问题:不,我不认为 Breeze 应该处理这个问题,至少不会有更丰富的错误信息。如果有的话,我认为如果您遇到问题,有三种不同的选择:

  1. 使用Typescript作为您自己的代码。如果DescriptionKnockoutObservable<string>,那么如果您为其分配常规字符串,编译器会抱怨。
  2. 在您自己的代码中或作为适当框架的补丁:使observables的属性为只读。 Along these lines。但是,this method依赖于浏览器支持...
  3. 切换到另一个没有此“税”的MVVM框架。 AFAIK例如Angular没有像Knockout那样的“功能”式设置;它使用常规属性。
  4. 但那只是我的2个cts - 阅读我自己的答案我觉得这个(“情况X应该由框架Y处理吗?”)是一个意见问题。