Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/373.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何在严格模式下使用上下文计算自定义javascript表达式?_Javascript_Properties_Scope_This_Eval - Fatal编程技术网

如何在严格模式下使用上下文计算自定义javascript表达式?

如何在严格模式下使用上下文计算自定义javascript表达式?,javascript,properties,scope,this,eval,Javascript,Properties,Scope,This,Eval,更新 我为这个问题提出了一个简洁的解决方案,其行为类似于node的vm模块 var VM = function(o) { eval((function() { var src = ''; for (var prop in o) { if (o.hasOwnProperty(prop)) { src += 'var ' + prop + '=o[\'' + prop + '\'];';

更新

我为这个问题提出了一个简洁的解决方案,其行为类似于node的vm模块

var VM = function(o) {
    eval((function() {
        var src = '';
        for (var prop in o) {
            if (o.hasOwnProperty(prop)) {
                src += 'var ' + prop + '=o[\'' + prop + '\'];';
            }
        }
        return src;
    })());
    return function() {
        return eval(arguments[0]);
    }
}
然后可以这样使用:

var vm = new VM({ prop1: { prop2: 3 } });
console.assert(3 === vm('prop1.prop2'), 'Property access');
此解决方案仅使用标识符
参数
覆盖命名空间

感谢Ryan Wheale的创意

短版

使用javascript对象作为上下文评估自定义javascript表达式的最佳方法是什么

var context = { prop1: { prop2: 3 } }

console.assert(3 === evaluate('prop1.prop2', context), 'Simple expression')

console.assert(3 === evaluate('(function() {' +
                              ' console.log(prop1.prop2);' +
                              ' return prop1.prop2;' +
                              '})()', context), 'Complex expression')
在撰写本文时(2015年3月6日),它应在最新版本的node(0.12)和所有evergreen浏览器上运行

注意:大多数模板引擎都支持此功能。例如

长版本

我目前正在开发一个应用程序引擎,它的一个特点是它获取一段代码,并使用提供的对象对其求值,然后返回结果

例如,
engine.evaluate('prop1.prop2',{prop1:{prop2:3}})
应该返回
3

这可以通过以下方式轻松实现:

function(code, obj) {
    with (obj) {
        return eval(code);
    }
};
但是,已知将
一起使用是不好的做法,不会在ES5严格模式下运行

在使用查看
之前,我已经编写了一个替代解决方案:

function(code, obj) {
    return (function() {
        return eval(code);
    }).call(obj, code);
}
但是,此方法需要使用
this

如:
engine.evaluate('this.prop1.prop2',{prop1:{prop2:3})

最终用户不应使用任何“前缀”

引擎还必须能够计算字符串,如

'prop1.prop2 + 5'

以及那些包含来自所提供对象的函数调用的函数

因此,它不能仅依靠将
code
字符串拆分为属性名


这个问题的最佳解决方案是什么?

更新3:一旦我们弄清楚你真正想问什么,问题就很清楚了:你不会那样做。特别是在严格模式下

作为一种可行的替代方法,请参考require.js、common.js和其他允许您在浏览器中加载模块的库中的文档。基本上,主要区别在于您不执行
prop1.prop2
,而是执行
context.prop1.prop2

如果可以使用
context.prop1.prop2
,请参阅JSFIDLE:

更新:回答关于如何使用
prop1.prop2访问属性的原始问题

首先,您可以使用字典符号访问变量,即:

obj['prop1']['prop2'] === obj.prop1.prop2
给我几分钟时间,让我举一个例子,说明如何递归地进行

已更新:这应该有效(如下所示):


我不知道你所有的情况,但这应该给你一个领先的开始:

更新-我感到无聊:


按点拆分,然后逐个迭代和访问属性。我不能这样做,因为它必须计算不同类型的代码。请参阅。特别是,如果您要计算随机代码段,那么您可以使用eval或编写自己的解析器和计算引擎。eval可能更高效、更易于使用。询问如何访问属性,然后询问如何解析和计算最后一块文本是完全不同的问题。你花了大部分时间在这里设置的问题被你在最后附加的额外条件大大抵消了。关于如何访问属性,有一个很好的答案——但就最后一点而言,正如前面所说,您实际上是在问如何从头开始实现
eval
。您可以直接引用。;-)@RobG如果我先搜索它,我本来可以的,但我只是写了我的小版本:pI正在使用eval,但我也不能让用户使用
this
关键字。为eval做一个包装,它接受你的上下文(this)作为参数,并用你现在已经使用的
语句将要求值的每个字符串更改为
。不,它可以与
with
语句配合使用,但我不能使用它,因为代码应该在严格模式下运行。谢谢,这是一个很好的解决方案(对于POJO)。是否可以通过函数实现这一点?我知道
JSON.stringify
不会将函数转换为字符串。在较新的浏览器中,我甚至认为IE8支持
Function.prototype.toString
。您需要递归地迭代每个属性并分别处理每种类型的数据,而不是
JSON.stringify
。例如,假设
prop1
是一个日期对象,您希望生成的代码是
var prop1=new Date(JSON.stringify(obj[prop1])。如果它是一个函数,则希望代码呈现为
var prop1=obj[prop1].toString()-但这对您来说是一个有趣的项目;)我刚刚更新了我的答案。这是一个有趣的小项目。让我知道它是如何工作的。谢谢你的帮助。我已经用它创建了一个相当健壮的函数。
"use strict";

var obj = { prop1 : { prop2: 'a' } }

function evaluate(code, context) {
  var f = new Function('ctx', 'return ' + code);
  return f(context)
}

alert(evaluate('ctx.prop1.prop2', obj))

alert(evaluate(
'(function() {' +
'   console.log(ctx.prop1.prop2);' +
'   return ctx.prop1.prop2;' +
'}) ()', obj))
obj['prop1']['prop2'] === obj.prop1.prop2
 function jpath_(o, props) { 
    if (props.length == 1) 
         return o[props[0]];  
    return jpath_(o[props.shift()], props) 
 }

 function jpath(o, path) { 
    return jpath_(o, path.split('.')) 
 }

 console.log(jpath(obj, 'prop1.prop2'))
var engine = {
    evaluate: function(strInput, obj) {
        var fnBody = '';
        for(var prop in obj) {
            fnBody += "var " + prop + "=" + JSON.stringify(obj[prop]) + ";";
        }
        return (new Function(fnBody + 'return ' + strInput))();
    }
};
var engine = {
    toSourceString: function(obj, recursion) {
        var strout = "";

        recursion = recursion || 0;
        for(var prop in obj) {
            if (obj.hasOwnProperty(prop)) {
                strout += recursion ? "    " + prop + ": " : "var " + prop + " = ";
                switch (typeof obj[prop]) {
                    case "string":
                    case "number":
                    case "boolean":
                    case "undefined":
                        strout += JSON.stringify(obj[prop]);
                        break;

                    case "function":
                        // won't work in older browsers
                        strout += obj[prop].toString();
                        break;

                    case "object":
                        if (!obj[prop])
                            strout += JSON.stringify(obj[prop]);
                        else if (obj[prop] instanceof RegExp)
                            strout += obj[prop].toString();
                        else if (obj[prop] instanceof Date)
                            strout += "new Date(" + JSON.stringify(obj[prop]) + ")";
                        else if (obj[prop] instanceof Array)
                            strout += "Array.prototype.slice.call({\n "
                                + this.toSourceString(obj[prop], recursion + 1)
                                + "    length: " + obj[prop].length
                            + "\n })";
                        else
                            strout += "{\n "
                                + this.toSourceString(obj[prop], recursion + 1).replace(/\,\s*$/, '')
                            + "\n }";
                        break;
                }

                strout += recursion ? ",\n " : ";\n ";
            }
        }
        return strout;
    },
    evaluate: function(strInput, obj) {
        var str = this.toSourceString(obj);
        return (new Function(str + 'return ' + strInput))();
    }
};