【问题标题】:Returning nested object values based on function arguments根据函数参数返回嵌套对象值
【发布时间】:2013-11-19 22:05:22
【问题描述】:

我正在尝试完成一个练习,但有些东西没有点击。

问题来了:您能否用 JS(或 Coffescript 或任何实际有意义的语言)编写一个方法 getTranslation(lang, path) --> 字符串,其工作方式如下: 你有这个全局对象:

strings = {
    home: {
        intro: {
            en: 'Welcome',
            fr: 'Bienvenue'
        },
        content: {
            explanation: {
                en: 'This is an interesting exercise',
                fr: 'C\'est un exercice intéressant',
                de: 'Es ist eine interesante Übung'
            },
            contact: 'Contact',
            goodbye: {
                en: 'Goodbye',
                fr: 'Au revoir',
                es: 'Adios'
            }
        }
    }
}

getTranslation('home.intro', 'fr') // => 'Bienvenue'
getTranslation('home.content.contact', 'fr') // => 'Contact'
getTranslation('home.intro', 'es') // => 'Welcome'
getTranslation('home.content.goodbye') // => 'Goodbye'
getTranslation('unvalid.path','en') // => ''

所以第一个参数是一个字符串,它描述了通过点分隔的键的路径(不是假定的键中的点),第二个参数是语言,如果未提供或不存在,则回退到“en”(我们还假设在每个分支的末尾,要么存在“en”键,要么是单个字符串,如 home.content.contact)。

这是我到目前为止想出的答案,但我知道我做错了什么,因为没有返回任何内容。

function getTranslation (path, lang) {

    lang = lang || "en";

    var strings = {
        home: {
            intro: {
                en: 'Welcome',
                fr: 'Bienvenue'
        },
        content: {
            explanation: {
                en: 'This is an interesting exercise',
                fr: 'C\'est un exercice intéressant',
                de: 'Es ist eine interesante Übung'
            },
            contact: 'Contact',
            goodbye: {
                en: 'Goodbye',
                fr: 'Au revoir',
                es: 'Adios'
            }
        }
    }

    if (path == 'home.content.contact') {
        return strings.path;
    } else if (path == 'unvalid.path') {
        return '';
    } else {
        return strings.path.lang;
    }
}

getTranslation('home.intro', 'fr'); // => 'Bienvenue'
getTranslation('home.content.contact', 'fr'); // => 'Contact'
getTranslation('home.intro', 'es'); // => 'Welcome'
getTranslation('home.content.goodbye'); // => 'Goodbye'
getTranslation('unvalid.path','en'); // => ''

感谢任何愿意提供帮助的人。

【问题讨论】:

  • 有很多方法可以做到这一点。你似乎要走的路径很乏味,因为你必须将你的路径与字符串 json 中的每个路径进行比较。

标签: javascript function logic


【解决方案1】:

不确定它是否是最佳解决方案,但它可以满足您的所有需求。

function getTranslation(path, lang) {

    lang = lang || "en";
    strings = {
        home: {
            intro: {
                en: 'Welcome',
                fr: 'Bienvenue'
            },
            content: {
                explanation: {
                    en: 'This is an interesting exercise',
                    fr: 'C\'est un exercice intéressant',
                    de: 'Es ist eine interesante Übung'
                },
                contact: 'Contact',
                goodbye: {
                    en: 'Goodbye',
                    fr: 'Au revoir',
                    es: 'Adios'
                }
            }
        }
    }
    path = path.split(".");
    var result = strings;
    for(var i in path){
        result = result[path[i]];
        if(result == undefined){
            return '';
        }
    }
    return (result[lang]==undefined)?"":result[lang];
}

【讨论】:

  • 避免eval 并为无效路径返回空字符串的好答案。请注意,此代码实际上修复了原始代码中的几个语法错误。
【解决方案2】:
function getTranslation (path, lang) {

                lang = lang || "en";

                var strings = {
                    home: {
                        intro: {
                            en: 'Welcome',
                            fr: 'Bienvenue'
                    },
                    content: {
                        explanation: {
                            en: 'This is an interesting exercise',
                            fr: 'C\'est un exercice intéressant',
                            de: 'Es ist eine interesante Übung'
                        },
                        contact: 'Contact',
                        goodbye: {
                            en: 'Goodbye',
                            fr: 'Au revoir',
                            es: 'Adios'
                        }
                    }
                }
            };
            var string = eval('strings.' + path);
            return string[lang];
            }

不喜欢这个解决方案,因为我避免使用 evals,但它可以解决您的问题。试试你的函数调用。

jsfiddle

【讨论】:

  • 以 json 速记语法发送的路径。 eval 只是尝试根据保存 json 的字符串变量来评估您的路径。您更好的选择是从路径变量中解析信息,然后在 json 中引用您需要的对象。
【解决方案3】:

我认为您遇到的部分困难是您有一些想要运行的 JavaScript 代码,但它被困在一个字符串中。

我相信你说的

return strings.path.lang

您希望执行此操作(假设 path = 'home.intro'lang = 'fr':

return strings.home.intro.fr

不是这个:

return strings.'home.intro'.'fr'

您可以使用evalpath 评估为您想要的代码,但eval 可能会导致安全漏洞。

我会通过将path 字符串拆分为. 字符来解决此问题。

这是我编写的一个快速函数:

function getTranslation (path, lang, obj) {

    obj = obj || strings;
    lang = lang || "en";

    var dotIndex = path.indexOf('.');

    if(dotIndex === -1) {
    return obj[path][lang];
}
else
{
    var firstFromPath = path.substring(0, dotIndex);
    var restPath = path.substring(dotIndex + 1);
    return getTranslation(restPath, lang, obj[firstFromPath]);
}

这并不能满足您的所有需求,但希望对您有所帮助。

【讨论】:

    【解决方案4】:
    return strings.path;
    

    不会返回任何内容,因为您的字符串对象上没有“路径”属性。

    你想要:

    return strings[path];
    

    ...但这仅在您的属性位于对象内的 第一 嵌套级别时才有效。比如……

    strings['home'];
    

    会给你和对象喜欢

    {intro: {
        en: 'Welcome',
        fr: 'Bienvenue'
    }}
    

    但是,尝试按名称访问嵌套属性(如下所示)会返回 undefined:

    strings['home.intro']
    

    因此,您必须通过. 对路径字符串进行split,循环遍历结果数组,并分别按名称获取每个属性。

    我将把实现留给你,因为你提到这是一个练习,但如果你遇到困难,请随时提出问题。

    【讨论】: