草庐IT

javascript - 迷你 javascript 电子表格系统中 'with' 的替代方案

coder 2025-03-12 原文

我刚刚遇到了这个我以前从未见过的优雅的 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});

魔术发生在 getter 中:

    //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); 
        }
    };

这是一件美丽的事情,但考虑到“with”即将过时,我想知道是否有一种方法可以在不扩大 DATA 对象范围的情况下简洁地替换用法?

最佳答案

我会避免 witheval 使用 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")); // 20000

基本上我们传递一个对象作为函数的词法范围,我们提取属性名称并将它们传递给 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)
  }
}

这样动态函数将只接收表达式中实际使用的参数。

它是如何工作的?

compile函数实际上是一个函数工厂,当我们用表达式调用它时,例如compile('A1+B2*C3'),它会使用具有以下形式的 Function 构造函数动态生成一个函数:

function anonymous(A1,B2,C3) {
  "use strict";
  return A1+B2*C3
} 

此函数将存储在compile 函数的闭包范围内。返回另一个函数,这个函数接收对象作为参数,属性存储在哪里,取决于表达式中使用的标识符,它提取它们并使用它们来应用我们首先创建的动态函数。

您可以看到一个工作示例 here .

如果我们内存 compile 函数,这可以进一步优化。

感兴趣的可以看this article关于使用 evalnew Function 之间的区别。

关于javascript - 迷你 javascript 电子表格系统中 'with' 的替代方案,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56224341/

有关javascript - 迷你 javascript 电子表格系统中 'with' 的替代方案的更多相关文章

  1. ruby-on-rails - rails : keeping DRY with ActiveRecord models that share similar complex attributes - 2

    这似乎应该有一个直截了当的答案,但在Google上花了很多时间,所以我找不到它。这可能是缺少正确关键字的情况。在我的RoR应用程序中,我有几个模型共享一种特定类型的字符串属性,该属性具有特殊验证和其他功能。我能想到的最接近的类似示例是表示URL的字符串。这会导致模型中出现大量重复(甚至单元测试中会出现更多重复),但我不确定如何让它更DRY。我能想到几个可能的方向...按照“validates_url_format_of”插件,但这只会让验证干给这个特殊的字符串它自己的模型,但这看起来很像重溶液为这个特殊的字符串创建一个ruby​​类,但是我如何得到ActiveRecord关联这个类模型

  2. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

    我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

  3. ruby-on-rails - 'compass watch' 是如何工作的/它是如何与 rails 一起使用的 - 2

    我在我的项目目录中完成了compasscreate.和compassinitrails。几个问题:我已将我的.sass文件放在public/stylesheets中。这是放置它们的正确位置吗?当我运行compasswatch时,它不会自动编译这些.sass文件。我必须手动指定文件:compasswatchpublic/stylesheets/myfile.sass等。如何让它自动运行?文件ie.css、print.css和screen.css已放在stylesheets/compiled。如何在编译后不让它们重新出现的情况下删除它们?我自己编译的.sass文件编译成compiled/t

  4. ruby-on-rails - Rails 3.2.1 中 ActionMailer 中的未定义方法 'default_content_type=' - 2

    我在我的项目中添加了一个系统来重置用户密码并通过电子邮件将密码发送给他,以防他忘记密码。昨天它运行良好(当我实现它时)。当我今天尝试启动服务器时,出现以下错误。=>BootingWEBrick=>Rails3.2.1applicationstartingindevelopmentonhttp://0.0.0.0:3000=>Callwith-dtodetach=>Ctrl-CtoshutdownserverExiting/Users/vinayshenoy/.rvm/gems/ruby-1.9.3-p0/gems/actionmailer-3.2.1/lib/action_mailer

  5. ruby-on-rails - Ruby on Rails with Haml - 如何从 erb 切换 - 2

    我正在从erb文件切换到HAML。我将hamlgem添加到我的系统中。我创建了app/views/layouts/application.html.haml文件。我应该只删除application.html.erb文件吗?此外,仍然有/public/index.html文件被呈现为默认页面。我想创建自己的默认index.html.haml页面。我应该把它放在哪里以及如何使系统呈现该文件而不是默认索引文件?谢谢! 最佳答案 是的,您可以删除任何已转换为HAML的View的ERB版本。至于你的另一个问题,删除public/index/h

  6. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  7. ruby - 主要 :Object when running build from sublime 的未定义方法 `require_relative' - 2

    我已经从我的命令行中获得了一切,所以我可以运行rubymyfile并且它可以正常工作。但是当我尝试从sublime中运行它时,我得到了undefinedmethod`require_relative'formain:Object有人知道我的sublime设置中缺少什么吗?我正在使用OSX并安装了rvm。 最佳答案 或者,您可以只使用“require”,它应该可以正常工作。我认为“require_relative”仅适用于ruby​​1.9+ 关于ruby-主要:Objectwhenrun

  8. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  9. ruby-on-rails - 新 Rails 项目 : 'bundle install' can't install rails in gemfile - 2

    我已经像这样安装了一个新的Rails项目:$railsnewsite它执行并到达:bundleinstall但是当它似乎尝试安装依赖项时我得到了这个错误Gem::Ext::BuildError:ERROR:Failedtobuildgemnativeextension./System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/rubyextconf.rbcheckingforlibkern/OSAtomic.h...yescreatingMakefilemake"DESTDIR="cleanmake"DESTDIR="

  10. ruby-on-rails - rspec should have_select ('cars' , :options => ['volvo' , 'saab' ] 不工作 - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion在首页我有:汽车:VolvoSaabMercedesAudistatic_pages_spec.rb中的测试代码:it"shouldhavetherightselect"dovisithome_pathit{shouldhave_select('cars',:options=>['volvo','saab','mercedes','audi'])}end响应是rspec./spec/request

随机推荐