首页 > 解决方案 > 我制作了一个 JavaScript 对象,我无法从中进行迭代,甚至无法访问它的参数。我错过了什么?

问题描述

这是我在 Chrome 中登录时的对象:

{}
de: {path: "/assets/trads/de.json", trads: {…}}
en: {path: "/assets/trads/en.json", trads: {…}}
es: {path: "/assets/trads/es.json", trads: {…}}
fr: {path: "/assets/trads/fr.json", trads: {…}}
it: {path: "/assets/trads/it.json", trads: {…}}
nl: {path: "/assets/trads/nl.json", trads: {…}}
ru: {path: "/assets/trads/ru.json", trads: {…}}
__proto__: Object

这是我登录时的类型:

Object

如果我尝试:

console.log(obj.en);
console.log(obj['en']);
console.log(obj.length);

我得到:

undefined

如果我做:

Object.keys(obj).forEach(e => console.log(e));
for (let i in obj) { console.log(obj[i] }
for (let i in obj) { console.log(i) }

我什么都得不到。

我如何从 createTradsObjFrom() 制作对象(在客户端运行,获取包含某些内容翻译的 JSON 文件):

const getJson = path => {
  return new Promise((resolve, reject) => {
    $.getJSON(path, json => {
      if (!json) return reject(new Error('Error while trying to get json for assets trads.'));
      return resolve(json);
    });
  });
};

const createTradsObjFrom = (languages, tradsPaths) => {
  return new Promise((resolve, reject) => {
    try {
      const obj = {};
      languages.forEach(async (lang, index) => {
        const path = tradsPaths[index];
        obj[lang] = {
          path,
          trads: await getJson(path)
        };
      });
      console.log('obj : ', obj);
      return resolve(obj);
    }
    catch (err) {
      return reject(new Error(err));
    }
  });
};

const getTrads = currentLanguage => {
  return new Promise((resolve, reject) => {
    const tradsDir = "/assets/trads/";
    const languages = [
      "de",
      "en",
      "es",
      "fr",
      "it",
      "nl",
      "ru"
    ];
    const tradsPaths = languages.map(e => tradsDir + e + '.json');
    createTradsObjFrom(languages, tradsPaths)
    .then(trads => resolve(trads))
    .catch(err => reject(err));
  });
};

感谢您的帮助,我已经在这方面花费了太多时间。:)

标签: javascriptobject

解决方案


首先,您正在使用一种反模式为已经返回 promise/thenable 的调用创建 promise。例如$.getJSON返回一个可await直接使用的对象

const getJson = path => {
  return $.getJSON(path);
};

//or just change
trads: await getJson(path)
//to use $.getJSON directly
trads: await $.getJSON(path)

其次forEach(),不使用承诺,因此使其回调async无关紧要,因为它不会等待承诺解决。您需要使createTradsObjFrom自身异步并使用正常循环

const createTradsObjFrom = async (languages, tradsPaths) => {
  try {
    const obj = {};
    //set index,lang by destructuring
    for(let [index,lang] of languages.entries()){
      const path = tradsPaths[index];
      obj[lang] = {
        path,
        //just call $.getJSON directly unless needing extra work done
        trads: await $.getJSON(path)
      };
    }
    console.log('obj : ', obj);
    return obj;
  }
  catch (err) {
    //since async functions don't provide a reject method we 
    //need to throw an error to cause a rejection
    throw new Error("some error");
  }
};

现在你可以直接返回createTradsObjFrom()或调用你的 then's

const getTrads = currentLanguage => {
  //again don't need to make a new promise here as 
  //createTradsObjFrom will be returning one itself
  const tradsDir = "/assets/trads/";
  const languages = ["de","en","es","fr","it","nl","ru"];
  const tradsPaths = languages.map(e => tradsDir + e + '.json');
  return createTradsObjFrom(languages, tradsPaths);
};
getTrads().then(yourObj=>{
  console.log(yourObj);
  //you can now use your filled object
}).catch(err=>{
  console.log("Some error happened: ",err);
});

至于为什么您在控制台日志中看到该对象已填充,请参阅有关控制台如何在控制台中第一次扩展对象时评估对象的问答:Chrome 的 JavaScript 控制台是否懒于评估数组?


推荐阅读