1

如果我有这样的刺痛,"AppNamespace.SomeObject.ClassName"并且我知道该字符串代表和实际的构造函数,那么在语句中使用它的最佳/推荐方法是var foo = new AppNamespace.SomeObject.ClassName什么?

我可以做:

var s = "AppNamespace.SomeObject.ClassName"
var foo = new (eval(s))

或类似的东西:

var parts = "AppNamespace.SomeObject.ClassName".split(".")
var foo = new (window[parts[0]][parts[1]][parts[2]])

但我想知道是否有更好的解决方案不涉及eval或不必拆分字符串并循环遍历其部分。有没有人有任何想法?如果不是,基于我提出的两种解决方案,每种解决方案的优缺点是什么?

4

2 回答 2

3

eval是邪恶的。使用循环选项。

循环选项的好处是对象是通过引用传递的。所以:

function getObjectFromString(str) {
    var parts = str.split("."), curr = window, last = parts.pop(), p;
    while( p = parts.shift()) curr = curr[p];
    return curr[last];
}

此函数返回目标对象,在您的示例中是您正在寻找的构造函数。

var s = "AppNamespace.SomeObject.ClassName";
var foo = new (getObjectFromString(s));
于 2012-04-07T01:49:23.123 回答
2

你可以做...

var obj = new ('AppNamespace.SomeObject.ClassName'
                .split('.')
                .reduce(function(object, key) {
                            return object[key];
                        }, window));

js小提琴

在较旧的浏览器上,您可以 shim reduce()

此代码按句点 () 拆分字符串,.然后从左到右遍历每个字符串,从window作为起始对象开始(如果不是,则更改它)并获取每个子属性,直到它到达最右边(ClassName在您的例子)。

实例化这个new (...)对象。

你可以把它写成一个可重用的函数......

var getObjectByString = function(string, baseObject, delimiter) {
    // Only checks for string primitives, but that's OK for this example.
    if (typeof string !== 'string') {
        throw new TypeError('First argument is required and must be a string.');
    }

    baseObject = baseObject || window;
    delimiter = delimiter || '.';

    return string
            .split(delimiter)
            .reduce(function(object, key) {
                      return object[key];
                    }, baseObject));
};
于 2012-04-07T01:53:41.233 回答