通过字符串名称访问命名空间的 javascript 对象,而不使用 eval

发布于 2024-10-17 10:13:51 字数 581 浏览 4 评论 0原文

我遇到了需要从服务器访问 javascript 对象的情况。服务器返回函数或对象的字符串名称,并且根据其他元数据,我将以不同的方式评估该对象。

最初我正在评估 (eval([string])),一切都很好。最近,为了安全起见,我正在更新函数以不使用 eval,并且遇到了命名空间对象/函数的问题。

具体来说,我尝试将 eval([name]) 替换为 window[name],以通过全局对象与 eval 中的方括号语法访问对象

但我遇到了命名空间对象的问题,例如:

var strObjName = 'namespace.serviceArea.function';
// if I do
var obj = eval(strObjName); // works

// but if I do
var obj = window[strObjName]; // doesn't work

任何人都可以想出一个好的解决方案来避免对命名空间字符串使用 eval 吗?

I ran into a situation where I need access to a javascript object from the server. The server returns the string name of the function or object and based on other metadata I will evaluate the object differently.

Originally I was evaluating (eval([string])) and everything was fine. Recently I was updating the function to not use eval for security peace of mind, and I ran into an issue with namespaced objects/functions.

Specifically I tried to replace an eval([name]) with a window[name] to access the object via the square bracket syntax from the global object vs eval.

But I ran into a problem with namespaced objects, for example:

var strObjName = 'namespace.serviceArea.function';
// if I do
var obj = eval(strObjName); // works

// but if I do
var obj = window[strObjName]; // doesn't work

Can anyone come up with a good solution to avoid the use of eval with namespaced strings?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

掐死时间 2024-10-24 10:13:51

您可以拆分 . 并依次解析每个属性。只要字符串中的属性名称都不包含 . 字符就可以了:

var strObjName = 'namespace.serviceArea.function';
var parts = strObjName.split(".");
for (var i = 0, len = parts.length, obj = window; i < len; ++i) {
    obj = obj[parts[i]];
}
alert(obj);

You could split on . and resolve each property in turn. This will be fine so long as none of the property names in the string contain a . character:

var strObjName = 'namespace.serviceArea.function';
var parts = strObjName.split(".");
for (var i = 0, len = parts.length, obj = window; i < len; ++i) {
    obj = obj[parts[i]];
}
alert(obj);
鲜血染红嫁衣 2024-10-24 10:13:51

只是想我会分享这个,因为我前几天做了这个。我什至没有意识到在JS中可以使用reduce!

function getByNameSpace(namespace, obj) {
    return namespace.split('.').reduce(function(a,b) {
            if(typeof a == 'object') return a[b];
            else return obj[a][b]; 
    });
}

希望有人觉得这有用..

Just thought I'd share this because I made this the other day. I didn't even realize reduce was available in JS!

function getByNameSpace(namespace, obj) {
    return namespace.split('.').reduce(function(a,b) {
            if(typeof a == 'object') return a[b];
            else return obj[a][b]; 
    });
}

Hope someone finds this useful..

携余温的黄昏 2024-10-24 10:13:51

我想出了这个:

function reval(str){
   var str=str.split("."),obj=window;
   for(var z=0;z<str.length;z++){
     obj=obj[str[z]];
   }
   return obj;
}
eval("window.this.that");
reval("this.that"); //would return the object
reval("this.that")(); //Would execute

I came up with this:

function reval(str){
   var str=str.split("."),obj=window;
   for(var z=0;z<str.length;z++){
     obj=obj[str[z]];
   }
   return obj;
}
eval("window.this.that");
reval("this.that"); //would return the object
reval("this.that")(); //Would execute
羁绊已千年 2024-10-24 10:13:51

我使用递归编写了不同的解决方案。我使用它来命名输入元素的名称属性。举个例子:

<input type="number" name="testGroup.person.age" />

假设我们将该输入的值设置为“25”。我们的代码中也有一个对象:

var data = {
    testGroup: {
        person: {
            name: null,
            age: null,
            salary: null
        }
    }
};

所以这里的目标是自动将输入元素中的值放入该数据结构中的正确位置。

我编写了这个小函数来根据您传递给它的任何命名空间数组创建一个嵌套对象:

var buildObject = function ( obj, namespaceArray, pos ) {
    var output = {};

    output[namespaceArray[pos]] = obj;

    if ( pos > 0 ) {
        output = buildObject(output, namespaceArray, pos-1);
    }

    return output;
};

它是如何工作的?它从 namespaceArray 的末尾开始数组,并创建一个具有一个属性的对象,其名称为 namespaceArray 中最后一个槽中的任何内容,其值为 obj。然后它会递归,将该对象包装在其他对象中,直到用完 namespaceArray 中的名称。 posnamespaceArray 数组的长度。您可以在第一个函数调用中计算出来,例如 if ( typeof(pos) === "undefined" ) pos = namespaceArray.length - 1 ,但是这样您就会有一个额外的每次函数递归时都要评估的语句。

首先,我们将 inputname 属性拆分为命名空间分隔符周围的数组,并获取输入的值:

var namespaceArray = inputElement.name.split("."),
    obj = inputElement.value;

// Usually you'll want to do some undefined checks and whatnot as well

然后我们只需调用函数并将结果分配给一些变量:

var myObj = buildObject(obj, namespaceArray, namespaceArray.length - 1);

myObj 现在看起来像这样:

{
    testGroup: {
        person: {
            age: 25
        }
    }
}

此时,我使用 jQuery 的扩展函数将该结构合并回原始数据对象:

data = $.extend(true, data, myObj);

但是,在无框架的 JavaScript 中合并两个对象并不是很难,并且有很多方法现有代码可以很好地完成工作。

我确信有更有效的方法可以完成此任务,但这种方法很好地满足了我的需求。

I have written a different solution, using recursion. I was using this to namespace the name attribute of input elements. Take, for example, the following:

<input type="number" name="testGroup.person.age" />

And let's say we set the value of that input to "25". We also have an object in our code somewhere:

var data = {
    testGroup: {
        person: {
            name: null,
            age: null,
            salary: null
        }
    }
};

So the goal here is to automatically put the value in our input element into the correct position in that data structure.

I've written this little function to create a nested object based on whatever array of namespaces you pass to it:

var buildObject = function ( obj, namespaceArray, pos ) {
    var output = {};

    output[namespaceArray[pos]] = obj;

    if ( pos > 0 ) {
        output = buildObject(output, namespaceArray, pos-1);
    }

    return output;
};

How does it work? It starts at the end of the namespaceArray array, and creates an object with one property, the name of which is whatever is in the last slot in namespaceArray, and the value of which is obj. It then recurses, wrapping that object in additional objects until it runs out of names in namespaceArray. pos is the length of the namespaceArray array. You could just work it out in the first function call, something like if ( typeof(pos) === "undefined" ) pos = namespaceArray.length - 1, but then you'd have an extra statement to evaluate every time the function recursed.

First, we split the name attribute of the input into an array around the namespace separators and get the value of the input:

var namespaceArray = inputElement.name.split("."),
    obj = inputElement.value;

// Usually you'll want to do some undefined checks and whatnot as well

Then we just call our function and assign the result to some variable:

var myObj = buildObject(obj, namespaceArray, namespaceArray.length - 1);

myObj will now look like this:

{
    testGroup: {
        person: {
            age: 25
        }
    }
}

At this point I use jQuery's extend function to merge that structure back into the original data object:

data = $.extend(true, data, myObj);

However, merging two objects is not very difficult to do in framework-free JavaScript and there is plenty of existing code that gets the job done well.

I'm sure there are more efficient ways to get this done, but this method meets my needs well.

瑾兮 2024-10-24 10:13:51

我知道这个问题已经得到了提问者满意的回答,但我最近遇到了这个问题,但是写到了这个值。我想出了自己的静态类来处理基于字符串路径的读写。默认路径分隔符是 .,但您可以将其修改为任何内容,例如 /。该代码还带有注释,以防您想知道它是如何工作的。

(function(){
    var o = {}, c = window.Configure = {}, seperator = '.';

    c.write = function(p, d)
    {
        // Split the path to an array and assaign the object
        // to a local variable
        var ps = p.split(seperator), co = o;

        // Iterate over the paths, skipping the last one
        for(var i = 0; i < ps.length - 1; i++)
        {
            // Grab the next path's value, creating an empty 
            // object if it does not exist
            co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {};
        }

        // Assign the value to the object's last path
        co[ps[ps.length - 1]] = d;
    }

    c.read = function(p)
    {
        var ps = p.split(seperator), co = o;
        for(var i = 0; i < ps.length; i++)
        {
            co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {};
        }
        return co;
    }
})();

I know this has been answered satisfactory to the asker, but I recently had this issue, but with WRITING to the value. I came up with my own static class to handle reading and writing based on a string path. The default path separator is . but you can modify it to be anything, such as /. The code is also commented incase you wonder how it works.

(function(){
    var o = {}, c = window.Configure = {}, seperator = '.';

    c.write = function(p, d)
    {
        // Split the path to an array and assaign the object
        // to a local variable
        var ps = p.split(seperator), co = o;

        // Iterate over the paths, skipping the last one
        for(var i = 0; i < ps.length - 1; i++)
        {
            // Grab the next path's value, creating an empty 
            // object if it does not exist
            co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {};
        }

        // Assign the value to the object's last path
        co[ps[ps.length - 1]] = d;
    }

    c.read = function(p)
    {
        var ps = p.split(seperator), co = o;
        for(var i = 0; i < ps.length; i++)
        {
            co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {};
        }
        return co;
    }
})();
秉烛思 2024-10-24 10:13:51

我在pastebin上的示例:
http://pastebin.com/13xUnuyV

我喜欢你的代码,并且我使用 PHP 做了很多类似的事情。
但在这里,这很艰难,正如我所想......
所以我使用了答案@LordZardeck(https://stackoverflow.com/a/9338381/1181479)和@Alnitak(< a href="https://stackoverflow.com/a/6491621/1181479">https://stackoverflow.com/a/6491621/1181479)。

这是我所拥有的,只需使用它:

    var someObject = {
        'part1' : {
            'name': 'Part 1',
            'size': '20',
            'qty' : '50'
        },
        'part2' : {
            'name': 'Part 2',
            'size': '15',
            'qty' : '60'
        },
        'part3' : [
            {
                'name': 'Part 3A РУКУ!!!',
                'size': '10',
                'qty' : '20'
            }, {
                'name': 'Part 3B',
                'size': '5',
                'qty' : '20'
            }, {
                'name': 'Part 3C',
                'size': '7.5',
                'qty' : '20'
            }
        ]
    };

    //var o = {}, c = window.Configure = {}, seperator = '.';

    var c = function(){
        this.o = {};
        this.seperator = ".";
        this.set = function(obj){
            this.o = obj;
        }
        this.write = function(p, d) {
            p = p.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
            p = p.replace(/^\./, ''); // strip leading dot
            // Split the path to an array and assaign the object
            // to a local variable
            var ps = p.split(this.seperator), co = this.o;

            // Iterate over the paths, skipping the last one
            for(var i = 0; i < ps.length - 1; i++)
            {
                // Grab the next path's value, creating an empty 
                // object if it does not exist
                co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {};
            }

            // Assign the value to the object's last path
            co[ps[ps.length - 1]] = d;
        }
        this.read = function(p) {
            p = p.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
            p = p.replace(/^\./, ''); // strip leading dot
            var ps = p.split(this.seperator), co = this.o;
            /*
            for(var i = 0; i < ps.length; i++)
            {
                co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {};
            }
            */
            while (ps.length) {
                var n = ps.shift();
                if (n in co) {
                    co = co[n];
                } else {
                    return;
                }
            }
            return co;
        }

    };

    var n = new c();
    n.set(someObject);
    console.log('whas');
    console.log('n.read part.name', n.read('part1.name'));
    n.write('part3[0].name', "custom var");
    console.log('part1.name now changed');
    n.write('part1.name', "tmp");
    console.log('n.read part.name', n.read('part1.name'));
    console.log('----');
    console.log('before', someObject);
    console.log('someObject.part1.name', someObject.part1.name);
    console.log('someObject.part3[0].name', someObject.part3[0].name);

My sample on pastebin:
http://pastebin.com/13xUnuyV

i liked you code, and i did a lot of similar stuff using PHP.
But here that was tough as i though...
So i used answers @LordZardeck (https://stackoverflow.com/a/9338381/1181479) and @Alnitak (https://stackoverflow.com/a/6491621/1181479).

And here what i have, just use it:

    var someObject = {
        'part1' : {
            'name': 'Part 1',
            'size': '20',
            'qty' : '50'
        },
        'part2' : {
            'name': 'Part 2',
            'size': '15',
            'qty' : '60'
        },
        'part3' : [
            {
                'name': 'Part 3A РУКУ!!!',
                'size': '10',
                'qty' : '20'
            }, {
                'name': 'Part 3B',
                'size': '5',
                'qty' : '20'
            }, {
                'name': 'Part 3C',
                'size': '7.5',
                'qty' : '20'
            }
        ]
    };

    //var o = {}, c = window.Configure = {}, seperator = '.';

    var c = function(){
        this.o = {};
        this.seperator = ".";
        this.set = function(obj){
            this.o = obj;
        }
        this.write = function(p, d) {
            p = p.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
            p = p.replace(/^\./, ''); // strip leading dot
            // Split the path to an array and assaign the object
            // to a local variable
            var ps = p.split(this.seperator), co = this.o;

            // Iterate over the paths, skipping the last one
            for(var i = 0; i < ps.length - 1; i++)
            {
                // Grab the next path's value, creating an empty 
                // object if it does not exist
                co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {};
            }

            // Assign the value to the object's last path
            co[ps[ps.length - 1]] = d;
        }
        this.read = function(p) {
            p = p.replace(/\[(\w+)\]/g, '.$1'); // convert indexes to properties
            p = p.replace(/^\./, ''); // strip leading dot
            var ps = p.split(this.seperator), co = this.o;
            /*
            for(var i = 0; i < ps.length; i++)
            {
                co = (co[ps[i]])? co[ps[i]] : co[ps[i]] = {};
            }
            */
            while (ps.length) {
                var n = ps.shift();
                if (n in co) {
                    co = co[n];
                } else {
                    return;
                }
            }
            return co;
        }

    };

    var n = new c();
    n.set(someObject);
    console.log('whas');
    console.log('n.read part.name', n.read('part1.name'));
    n.write('part3[0].name', "custom var");
    console.log('part1.name now changed');
    n.write('part1.name', "tmp");
    console.log('n.read part.name', n.read('part1.name'));
    console.log('----');
    console.log('before', someObject);
    console.log('someObject.part1.name', someObject.part1.name);
    console.log('someObject.part3[0].name', someObject.part3[0].name);
各自安好 2024-10-24 10:13:51

可以使用函数式编程技术来做到这一点,例如

(function (s) {return s.split('.').reduce(function(p,n) { p[n] = p[n] || {}; return p[n];},window);})("some.cool.namespace");

可以将其分配给全局函数以供重用

window.ns = (function (s) {return s.split('.').reduce(function(p,n) { p[n] = p[n] || {}; return p[n];},window);})

然后我们可以执行以下操作

ns("some.cool").namespace = 5;

if (5 != ns("some.cool.namespace")) { throw "This error can never happen" }

It is possible to do this using functional programming techniques such as

(function (s) {return s.split('.').reduce(function(p,n) { p[n] = p[n] || {}; return p[n];},window);})("some.cool.namespace");

This can be assigned to a global function for re-use

window.ns = (function (s) {return s.split('.').reduce(function(p,n) { p[n] = p[n] || {}; return p[n];},window);})

Then we can do the following

ns("some.cool").namespace = 5;

if (5 != ns("some.cool.namespace")) { throw "This error can never happen" }
故事未完 2024-10-24 10:13:51

以下假设 strObjName 的各部分由 . 分隔,并从 window 开始循环,直到到达您想要的函数:

var strObjParts = strObjName.split('.');
var obj = window;
for(var i in strObjParts) {
  obj = obj[strObjParts[i]];
}

The following assumes that the parts of strObjName are separated by . and loops through starting at window until it gets down to the function you want:

var strObjParts = strObjName.split('.');
var obj = window;
for(var i in strObjParts) {
  obj = obj[strObjParts[i]];
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文