我刚刚遇到了这个精美的javascript电子表格代码,以前从未见过:http : //jsfiddle.net/ondras/hYfN3/
它使用名为getter对象的单元格引用作为DATA对象的属性,并使用“ with”对单元格值进行范围评估。
//elm.id is the cell reference, DATA is an object whose properties are these getter wrappers
Object.defineProperty(DATA, elm.id, {get:getter});
Run Code Online (Sandbox Code Playgroud)
魔术发生在吸气剂中:
//My comments but jsfiddle code from Ond?ej Žára's fiddle
//Cell value getter function..
var getter = function() {
var value = localStorage[elm.id] || ""; //Direct cell contents
if (value.charAt(0) == "=") { //Got a formula, work it out
//strip the '=' and evaluate recursively with this getter func
with (DATA) return eval(value.substring(1));
} else { // Else just send back the cell contents
return isNaN(parseFloat(value)) ? value : parseFloat(value);
}
};
Run Code Online (Sandbox Code Playgroud)
这是一件很美的事情,但是考虑到“ with”即将消失,我想知道是否有一种方法可以在不扩大DATA对象范围的情况下简洁地替换使用方法?
我会避免with并eval使用Function构造函数:
我过去做过类似的事情:
function compile(lexicalScope) {
const params = Object.keys(lexicalScope).join(',');
const values = Object.values(lexicalScope);
return function (expr) {
const compiledFn = new Function(params, '"use strict"; return ' + expr);
return compiledFn.apply(null, values);
};
}
const variables = {A1: 100, B1: 200};
const evaluator = compile(variables);
console.log(evaluator("A1 + B1")); // 300
console.log(evaluator("B1 * 100")); // 20000Run Code Online (Sandbox Code Playgroud)
基本上,我们传递一个将充当函数的词法范围的对象,我们提取属性名称并将它们传递给 Function 构造函数的第一个参数。
然后在构造函数的主体中,我喜欢首先将函数定义为严格的,因为默认情况下由 Function 构造函数创建的函数在草率模式下运行。
最后,我们只需返回表达式即可。然后,我们使用 执行动态函数apply。
编辑:我能够查看电子表格,并对我的方法进行了一些修改,以使其适用于此实现。
首先,该DATA对象的所有 getter 都是不可枚举的,这意味着Object.keys不返回任何属性,我不是使用所有可用的属性,而是解析表达式中可能出现的标识符,并将它们用作动态函数的可能参数:
function compile(expr) {
// possible parameters for dynamic function
const identifiers = [...new Set(expr.match(/[A-Z]+\d/g))]
const compiledFn = new Function(identifiers, '"use strict"; return ' + expr)
return function(context) {
// extract values
const values = identifiers.map(id => context[id])
return compiledFn(...values)
}
}
Run Code Online (Sandbox Code Playgroud)
这样,动态函数将仅接收表达式中实际使用的参数。
它是如何工作的 ?
该compile函数实际上是一个函数工厂,当我们用表达式调用它时,例如compile('A1+B2*C3'),它会动态生成一个函数,使用Function以下形式的构造函数:
function anonymous(A1,B2,C3) {
"use strict";
return A1+B2*C3
}
Run Code Online (Sandbox Code Playgroud)
该函数将被存储在函数闭包的作用域中compile。返回另一个函数,这个函数接收对象作为参数,属性存储在其中,具体取决于表达式中使用的标识符,它提取它们并使用它们来应用我们首先创建的动态函数。
您可以在此处查看一个工作示例。
如果我们记住该函数,则可以进一步优化compile。
如果您有兴趣,可以阅读这篇文章eval,了解使用与 之间的区别new Function。
| 归档时间: |
|
| 查看次数: |
89 次 |
| 最近记录: |