从可观察数组中获取对象

Get object out of observable array

本文关键字:获取 取对象 数组 观察      更新时间:2023-09-26

为什么在这段代码中m是"未定义的":

currentViewModel = ko.mapping.fromJS(viewModel);
currentViewModel.getReport = function(reportId) {
    for(var i=0;i<currentViewModel.availableReports().length;i++) {
        if(currentViewModel.availableReports()[i].id == reportId) {
            var m = currentViewModel.availableReports()[i];
            return currentViewModel.availableReports()[i];
        }
    }
}

我将getReport((称为onclick事件,我想将报告对象发送到一个视图(模态(,我可以在可用的报告中执行foreach,它就在那里。 当我运行调试器时,它会遍历数组并找到正确的数组。 但是为什么我不能把它从阵列中拉出来呢? "m"保持未定义,函数返回未定义。

我在这里错过了什么?

编辑:这里有一个后续问题:敲除.js可以等到点击后再绑定吗?

你只需要将if(currentViewModel.availableReports()[i].id ...更改为if(currentViewModel.availableReports()[i].id() ...,因为在映射后id将成为可观察的,即函数。

更新的代码:

currentViewModel = ko.mapping.fromJS(viewModel);
currentViewModel.getReport = function(reportId) {
    for (var i = 0; i < currentViewModel.availableReports().length; i++) {
        if (currentViewModel.availableReports()[i].id() == reportId) {
            var m = currentViewModel.availableReports()[i];
            return currentViewModel.availableReports()[i];
        }
    }
}

演示 - 小提琴。

我将在这里重复@NikolayErmakov答案中的解决方案,但想添加两件事以获得更完整的答案。你以:

m保持未定义,函数返回undefined

我在这里错过了什么?

您缺少两件事:

  1. if内第一个语句的var m位被提升到当前作用域的顶部(函数的顶部(。这就是为什么调试器可以告诉你m是什么,即使你永远不会到达它所在的代码行。
  2. 如果函数调用到达函数的末尾(就像您一样,因为您永远不会进入if(而没有看到显式return语句,它将返回undefined

为了更好地理解这一点,你应该这样解释你的函数:

currentViewModel.getReport = function(reportId) {
  var m;
  for (var i = 0; i < currentViewModel.availableReports().length; i++) {
    if (currentViewModel.availableReports()[i].id == reportId) {
      m = currentViewModel.availableReports()[i];
      return currentViewModel.availableReports()[i];
    }
  }
  return undefined;
}

有些人(例如Douglas Crockford(确实建议将var语句放在函数的顶部,尽管这在某种程度上是一个风格问题。我认为很多人不会在函数结束时显式返回undefined,尽管在您的情况下,我可能会明确说明这种情况并返回null(甚至抛出错误(。

正如承诺的那样,我将重复实际的解决方案,因为我同意另一个答案:

  • 您需要调用id作为函数来获取其值(因为mapping插件将映射到observable() s。

另外:

  • 我只会检索一次数组
  • 我建议使用===而不是==

这是我的 v0.5 版本:

currentViewModel.getReport = function(reportId) {
    var m = null, reports = currentViewModel.availableReports();
    for (var i = 0; i < reports.length; i++) {
        if (reports[i].id() === reportId) {
            m = reports[i];
            return m;
        }
    }
    return m;
}

但是我会将其优化到此v1.0:

currentViewModel.getReport = function(reportId) {
    var reports = currentViewModel.availableReports();
    for (var i = 0; i < reports.length; i++) {
        if (reports[i].id() === reportId) {
            return reports[i];
        }
    }
    return null;
}

为了完整起见,下面是另一个在数组上使用filter的版本:

currentViewModel.getReport = function(reportId) {
  var reports = currentViewModel.availableReports().filter(function(r) { return r.id() === reportId; });
  return reports.length >= 1 ? reports[0] : null;
}