【问题标题】:TypeScript - Namespace/Scope variable updates [duplicate]TypeScript - 命名空间/范围变量更新 [重复]
【发布时间】:2023-03-28 17:48:01
【问题描述】:

我正在从本地 JSON 文件中获取一些设置。函数内部的console.log 正确记录了对象,但是函数返回undefined 之后的第二个,所以变量没有被更新?

另外,在testNameSpace 内,this 返回window,为什么?

namespace testNameSpace {

    let settings: any;

    function dtJSONLoad() {
        let xobj = new XMLHttpRequest();
        xobj.overrideMimeType("application/json");
        xobj.open('GET', './js/file.json', true);
        xobj.onreadystatechange = function () {
            if (xobj.readyState == 4) {
                let response = xobj.responseText;
                settings = JSON.parse(response);
                console.log(settings);
            }
        };
        xobj.send(null);
    }

    dtJSONLoad();
    console.log(settings);

}

控制台日志“未定义”

控制台日志返回对象'

【问题讨论】:

  • 看起来你是对的,它与异步有关。设置为 false 它会正确更新。

标签: javascript json typescript


【解决方案1】:

您面临着 SO 中被问到的两个最常见的问题(至少是带有 TypeScript 标记的问题)。

首先是您正在执行异步操作,因此当您执行此操作时:

dtJSONLoad();
console.log(settings);

console.log 部分正在执行之前 dtJSONLoad 完成,因此settings 变量未定义。
您的第二个 console.log 发生在异步操作完成时,这就是您看到该值的原因。

第二期是this的范围:
您正在为 xobj.onreadystatechange 属性分配一个函数,此函数未绑定到当前的 this,因此当它执行时,this 正在引用 Window 对象。
您有两种选择:

(1) 使用arrow function 保存this 的当前范围:

xobj.onreadystatechange =  () => {
    // ...
};

(2)使用Function.prototype.bind函数:

xobj.onreadystatechange =  function () {
    // ...
}.bind(this);

编辑

命名空间没有this,这是因为它是如何被编译成javascript的。
例如,这个:

namespace mynamespace {
    console.log(this); // Error: 'this' cannot be referenced in a module or namespace body
}

编译成:

var mynamespace;
(function (mynamespace) {
    console.log(this);
})(mynamespace || (mynamespace = {}));

相当于做:

function fn() {
    console.log(this);
}

在这两种情况下,this 都引用了Window 对象。

如果你这样做:

namespace mynamespace {
    export function fn() {
        console.log(this);
    }
}

mynamespace.fn();

它将打印:Object {},这是正确的,这是因为 fn 函数位于 mynamespace 内部。
并且js结果是这样的:

var mynamespace;
(function (mynamespace) {
    function fn() {
        console.log(this);
    }
    mynamespace.fn = fn;
})(mynamespace || (mynamespace = {}));

【讨论】:

  • 好吧,我明白你的意思了。当我在console.log(this);namespace testNameSpace 时,它也会返回window,这是为什么呢?
  • 检查我修改后的答案
【解决方案2】:

第一次记录时数据不存在。

第二次是在回调中,当数据到达时,第一次是请求开始后的第二次。

【讨论】:

  • 我明白你在说什么,但事实并非如此。如果我在函数后注释掉 console.log,则对象返回。如果我注释掉函数内部的那个,则只返回未定义的。不过,我不明白他们为什么要按这个顺序登录。
  • 这正是我要说的@PaulRedmond。请在您的日志中添加一些字符串以识别它们。
猜你喜欢
  • 1970-01-01
  • 2016-01-03
  • 2018-06-29
  • 1970-01-01
  • 1970-01-01
  • 2014-04-09
  • 2020-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多