【问题标题】:Wrapping a series of closures包装一系列闭包
【发布时间】:2019-07-09 20:16:12
【问题描述】:

我继承了一大块代码,其中包含大量 DataTable 渲染器数组。我想在前面的数据对象中插入一些额外的数据,而不重写所有渲染器,只重写实际受影响的渲染器。

columnDefs 字段生成为具有render 函数和其他字段(targetstype 等)的对象数组。我想动态重写它,让render 函数成为调用原始函数的包装器。我没有找到关闭原始函数的正确代码,因此我可以在通过的过程中调整数据并仍然调用该原始函数。

例如,给定一个 columnDefs 为:

var columnDefs = [
{
  "render": function (data, type, row) {
    return stuff(row[3]);
  },
  "targets": 2
},
{
  "render": function (data, type, row) {
    return stuff(row[0]);
  },
  "targets": 1
},
// etc.
]

我正在尝试做这样的事情:

var mapper = function (def) {
    (function (d, old_render) {
        d.render = (data, type, row) => {
            let extra_data = undefined;
            if (row.length > 1 && typeof (row[0]) == 'object') {
                extra_data = row[0];
                row = row.slice(1);
            }
            return old_render(data, type, row, extra_data);
        }
    })(def, def.render);
};
columnDefs.forEach(mapper);

在致电$("#my-datatable").DataTable({ ..., columnDefs: columnDefs, ... })之前。

目前的工作是调用新的渲染函数。但是,当调用 render 时,old_render 始终未定义,这当然会死。

为方便起见,完整的代码示例on JSFiddle,也在这里:

function stuff(x) {
  return "<b>" + x + "</b>";
}

var columnDefs = [
{
  "render": function (data, type, row) {
    return stuff(row[3]);
  },
  "targets": 2
},
{
  "render": function (data, type, row) {
    return stuff(row[0]);
  },
  "targets": 1
},
]

var dataSource = [{"a", "b", "c", "d", "e"}, {"f","g","h","i","j"}];
columnDefs.forEach(d => {
  d.render = function(old_render) {
    return (data, type, row) => {
      let extra_data = undefined;
      return old_render(data, type, row.map(, extra_data);
    };
  }(d.render);
});
var table = $("#my-table").DataTable({
processing: true,
data: dataSource,
columnDefs: columnDefs
});

而关联的 HTML 只是:

<link href="//cdn.datatables.net/1.10.19/css/jquery.dataTables.min.css" rel="stylesheet" type="text/css" />
<script src="https://cdn.datatables.net/1.10.19/js/jquery.dataTables.min.js"></script>

<p>
hello
</p>
<table id="my-table">
<thead>
  <tr>
    <th>1</th><th>2</th><th>3</th><th>4</th>
  </tr>
</thead>
</table>

更新... JSLint 正在工作,我只是不确定为什么它不在我更大的代码库中。回到绘图板,我想,找出原因。

【问题讨论】:

  • 您应该创建一个可运行的示例。看起来它应该可以工作并且 old_render 不应该是未定义的
  • 我真的不明白你想做什么,因为你似乎用第四个参数调用原始渲染函数,但那些渲染函数从不看那个参数......
  • @trincot 我稍后会添加第四个参数,到关心额外数据的渲染函数中,其余的将忽略它。首先是获取要调用的原始渲染函数。
  • 这很难解释。我确实想指出typeof 不足以确定数组的成员是对象。
  • 我试过你的代码,它调用old_render没有问题。

标签: javascript datatables monkeypatching


【解决方案1】:

这样的东西应该可以工作......

function newRender(oldRender, data, type, row) {
    let extra_data = undefined;
    if (row.length > 1 && typeof (row[0]) == 'object') {
        extra_data = row[0];
        row = row.slice(1);
    }
    return oldRender(data, type, row, extra_data);
}

var mapper = function (def) {
    def.render = newRender.bind(null, def.render);
};

columnDefs.forEach(mapper);

【讨论】:

  • 有什么区别?
  • 正如您所指出的,原始代码有效,我承认我认为我没有检查过,所以在功能上没有任何区别。我的错。但是,我的代码确实删除了不需要的附加自执行功能,因此删除了嵌套并且应该更快一些。
【解决方案2】:

事实证明,如果某些记录没有输入渲染,那么当然不能调用旧的渲染器。这里处理的列数足够大,我没有注意到其中一些没有渲染器。

var columnDefs = [
{
  "render": function (data, type, row) {
    return stuff(row[3]);
  },
  "targets": 2
},
{
  //"render": function (data, type, row) {
  //  return stuff(row[0]);
  //},
  "targets": 1
},
]

现在当代码到达这里的第二列时,没有渲染函数,所以当然是未定义的。通过使用if (d.render) {...} 包装映射器,可以避免该问题。

【讨论】:

    猜你喜欢
    • 2016-03-21
    • 2019-05-20
    • 2018-09-26
    • 1970-01-01
    • 2011-08-07
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    • 1970-01-01
    相关资源
    最近更新 更多