我可以在对象上下文中评估表达式吗?

Can I eval expression in object context?

本文关键字:表达式 评估 对象 上下文 我可以      更新时间:2023-09-26

美好的一天。我需要在某些对象上下文中评估表达式,但我找到的唯一解决方案是为每个对象函数创建存根:

 var c = {
    a : function () {
      return 'a';
    },
    b : function () {
      return 'b';
    }
  };
  function evalInObj(c, js) {
    function a() {
      return c.a();
    }
    function b() {
      return c.b();
    }
    return eval(js);
  };
  console.log(evalInObj(c, 'a() + b()'));

请告诉我正确的方法。我可以用原型来做吗?

  var C = function(id) {
    this.id = id;
  }
  C.prototype.a = function () {
    return 'a' + this.id;
  }
  C.prototype.b = function () {
    return 'b' + this.id;
  }
  function evalCtx(js) {
    console.log(this);  // C {id: 1}
    return eval(js);
  }
  var c1 = new C(1);
  evalCtx.call(c1, 'a() + b()'); // error: a is not defined

适用于仍在寻找问题(或类似)解决方案的后来者。我们可以动态创建匿名函数并在对象上下文中计算表达式,而不是使用 eval()

function evaluate(expression, context = {}) {
  try {
    // console.debug("[DEBUG] Dynamic anonymous function to be defined:'n%s", `function(${[...Object.keys(context)].join()}) {'n'use strict'; return (${expression})'n}`)
    const fun = Function(...Object.keys(context), `'use strict'; return (${expression})`)
    // console.debug("[DEBUG] Dynamically defined anonymous function:'n%o", fun)
    const result = fun(...Object.values(context))
    // console.debug("[DEBUG] Evaluation result: %o", result)
    return result
  } catch(error) {
    if(error.message === `Unexpected token ')'`) throw SyntaxError('Unexpected token, likely at the end of expression.')
    else throw error
  }
}

断言:

console.assert(evaluate('a===1 && b===2', {a: 1, b: 2}) === true)
console.assert(evaluate('a===1 && b===3', {a: 1, b: 2}) === false)
console.assert(evaluate('f()', {a: 1, f: ()=>11}) === 11)
(() =>
{
    // 'use strict';
    function run(expression, context = {})
    {
        return function ()
        {
            return eval(expression);
        }.call(context);
    }
    let context = {a:{b:'Bb'}};
    console.log(run('this', context));      // {a:{b:'Bb'}}
    console.log(run('this.a', context));    // {b:'Bb'}
    console.log(run('this.a.b', context));  // 'Bb'
    console.log(run('a.b', context));       // ReferenceError: a is not defined
})();

这种技术最显着的优点是它无需with关键字即可工作,

因此即使在strict模式下

+function()
{
    // jsut pollyfills for backward browsers...
    Object.prototype.keys || (Object.defineProperty(Object.prototype, 'keys', {value: function ()
        {
            var result = []; for (var key in this) result.push(key); return result;
        }}));
    Object.prototype.entries || (Object.defineProperty(Object.prototype, 'entries', {value: function ()
        {
            var result = []; for (var key in this) result.push([key, this[key]]); return result;
        }}));

    // here the magic...
    function run(expression, context)
    {
        var variables = {};
        (context instanceof Object) && context.entries().forEach(function(entry)
        {
            entry[0].match(/^[a-z_$][a-z0-9_$]*$/) && (variables[entry[0]] = entry[1]);
        });
        return (new Function('return function(' + variables.keys().join(', ') + ') { return ' + expression + '; }'))()// first get the synthetic function
               .apply(context, variables.entries().map(function(entry) { return entry[1]; }));
    }
    var output = run("a + '#' + b", {a: 'Aa', b: 'Bb', 0: 'Zero'});
    console.log(output); // Aa#Bb
}();
function runScript(ctx, js){ with(ctx){ return eval(js); }}

已关闭。谢谢大家