在 Javascript 中动态修改或生成代码
Posted
技术标签:
【中文标题】在 Javascript 中动态修改或生成代码【英文标题】:Dynamic modify or generate code in Javascript 【发布时间】:2020-03-08 19:25:06 【问题描述】:我正在对一些表格数据进行多重排序。我想动态修改 AngularJS 站点中指定排序优先顺序的代码行。 (我只是在修改数组的结构,因为 AngularJS 会观察绑定数据的变化并在 html 显示中动态地反映它们。)
对于多重排序,我使用thenBy.js。本质上,您创建一个以 firstBy(comparativeFunction) 开头的变量,然后您可以根据需要添加任意数量的 thenBy(comparativeFunction)。
我会根据需要动态添加和删除排序比较器。这是我从这个简单的两级多排序开始的地方:
// I want to modify and append to this line
var s = firstBy( (a, b) => a["Status"].localeCompare(b["Status"]) )
.thenBy( (a, b) => parseFloat(a["#"]) - parseFloat(b["#"]) );
它最初会根据“状态”属性中的数据对行进行排序,然后根据 ID 编号的“#”进行子排序。
我想知道的是如何在上面的行中动态添加更多代码。例如,假设我想添加一个三级排序,比如“唯一 ID”。我可以这样对行进行硬编码:
var s = firstBy( (a, b) => a["Status"].localeCompare(b["Status"]) )
.thenBy( (a, b) => parseFloat(a["#"]) - parseFloat(b["#"]) )
.thenBy( (a, b) => parseFloat(a["Unique ID"]) - parseFloat(b["Unique ID"]) );
我只是不确定如何以编程方式将更多 'thenBy()' 方法附加到这一行。我应该生成一个字符串并通过 eval() 运行它吗?有没有更好(更安全)的方法?
这是目前的节目:
self.dataSource = [
"#": "1", "Unique ID": "100130", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 1", "Status": "Available",
"#": "2", "Unique ID": "100131", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 2", "Status": "Available",
"#": "3", "Unique ID": "100132", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 3", "Status": "Available",
"#": "4", "Unique ID": "100133", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 4", "Status": "Available",
"#": "5", "Unique ID": "100134", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 5", "Status": "Checked Out",
"#": "6", "Unique ID": "100135", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 6", "Status": "Checked Out",
"#": "7", "Unique ID": "100136", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 7", "Status": "Checked Out",
"#": "8", "Unique ID": "100137", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 8", "Status": "Checked Out",
"#": "9", "Unique ID": "100138", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 1 - Box 1 - Position 1", "Status": "Available",
"#": "10", "Unique ID": "100139", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 2 - Box 1 - Position 1", "Status": "Available",
"#": "11", "Unique ID": "100140", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 2 - Box 1 - Position 2", "Status": "Available",
"#": "12", "Unique ID": "100141", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 2 - Box 1 - Position 3", "Status": "Lost",
"#": "13", "Unique ID": "100142", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 2 - Box 1 - Position 4", "Status": "Lost",
"#": "14", "Unique ID": "100143", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 3 - Box 1 - Position 1", "Status": "Available",
"#": "15", "Unique ID": "100144", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 3 - Box 1 - Position 2", "Status": "Available",
"#": "16", "Unique ID": "100145", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 4 - Box 1 - Position 1", "Status": "Checked Out",
"#": "17", "Unique ID": "100146", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 4 - Box 1 - Position 2", "Status": "Available",
"#": "18", "Unique ID": "100147", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 4 - Box 1 - Position 3", "Status": "Available",
"#": "19", "Unique ID": "100148", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 4 - Box 1 - Position 4", "Status": "Checked Out",
"#": "20", "Unique ID": "100149", "Name": "Book", "Section": "Paraguay", "Position": "Shelf 1 - Rack 5 - Box 1 - Position 1", "Status": "Available"
];
var self = this;
self.multiSortDict = ;
self.addSort = function(sortName, sortComparatorFunction)
self.multiSortDict[sortName] = sortComparatorFunction;
// Example code to add a bunch of sorting methods
self.addSort("Status",(a, b) => a["Status"].localeCompare(b["Status"]));
self.addSort("#", (a, b) => parseFloat(a["#"]) - parseFloat(b["#"]));
self.addSort("Name",(a, b) => a["Name"].localeCompare(b["Name"]));
self.addSort("Unique ID", (a, b) => parseFloat(a["Unique ID"]) - parseFloat(b["Unique ID"]));
self.addSort("Position",(a, b) => a["Position"].localeCompare(b["Position"]));
self.rebuildMultiSort = function (multiSortDict)
var sortList = Object.values(multiSortDict);
var sortMethod = firstBy( sortList[0] ); // Grab the first entry to set the 'firstBy()' method
for (var i = 1; i < sortList.length; i++) // Starting at second position
// I want to dynamically modify this line, being able to append as many 'thenBy()' statements as necessary
// remove the semicolon from the previous sortMethod assignment
// append the new 'thenBy()' to assignment
sortMethod +=
.thenBy(value);
return sortMethod;
使用上面的例子,理想情况下我会得到一个类似这样的代码行:
var s = firstBy( (a, b) => a["Status"].localeCompare(b["Status"]) )
.thenBy( (a, b) => parseFloat(a["#"]) - parseFloat(b["#"]) )
.thenBy( "Name",(a, b) => a["Name"].localeCompare(b["Name"]) )
.thenBy( (a, b) => parseFloat(a["Unique ID"]) - parseFloat(b["Unique ID"]) )
.thenBy( "Position",(a, b) => a["Position"].localeCompare(b["Position"]) )
有什么建议吗?
【问题讨论】:
【参考方案1】:在几乎所有情况下,都有比使用evil
更好的做事方式。
我建议查找比较函数,例如
const ordersLookup =
Status: (a, b) => a["Status"].localeCompare(b["Status"]),
"#": (a, b) => parseFloat(a["#"]) - parseFloat(b["#"]),
Name: (a, b) => a["Name"].localeCompare(b["Name"]),
// ...
然后当你决定要排序时:
let order = ["Name", "Status"];
并从查找中选择适当的条目,并减少链:
let s = order.reduce((a, e) => a.thenBy(ordersLookup[e]), firstBy(() => 0));
或
let orderFunctions = order.map(e => ordersLookup[e]);
let [firstInOrder, *restInOrder] = orderFunctions;
let s = restInOrder.reduce((a, e) => a.thenBy(e), firstBy(firstInOrder));
(最终结果应该相同,性能和可读性略有不同)。
无需生成代码。
另外,请注意 thenBy.js 知道如何处理按属性排序,因此您不需要自己编写大部分函数。 firstBy("Name").thenBy("#")
应该开箱即用。
【讨论】:
谢谢。这个例子在我修改后起作用了。这似乎正在做我正在寻找的工作!以上是关于在 Javascript 中动态修改或生成代码的主要内容,如果未能解决你的问题,请参考以下文章
使用 JavaScript 或 PHP 动态生成 CSS 网格