如何使用代理来观察变量是否(不再)未定义
How to use Proxy to watch if a variable is (no longer) undefined
请原谅我的无能...
我正在尝试在全局 var 阶段不再未定义后使用 Proxy 执行一些代码。这是我天真的尝试:
```
var stage = undefined
let myObj;
let st = {
stage: stage,
}
let lr = {
get: function(obj:any, prop:any):LightRay{
myObj = new SomeObjThatNeedsStage(obj[prop]) // <= supposed to be non-undefined stage
return myObj
},
}
let p = new Proxy(st, lr)
// At this point I expect the lr handler to have been executed if the stage var has been instantiated by some external code that's out of my control.
```
显然,我误解了代理的工作原理,但我尝试了各种方案,但没有一个可行。将未定义的阶段作为目标传递给代理不起作用(出现 Cannot create proxy with a non-object as target or handler
错误)。在这种情况下如何使用 Proxy?为什么我不能observe
undefined stage with Proxy 直到它被实例化,然后执行回调?
仅供参考:
Stage var 是全局的,我无法控制它(它在某些时候由 create.js 实例化)。所有代码都从 UMD 模块执行。我正在使用打字稿(转译为 es5)。 Object.defineProperty() 在我的浏览器中可用。此外,阶段(类型 createjs.Stage)在实例化时确实包含不同类型的 setter/getter,这在使用打字稿时会产生问题。
更新答案
您说过您无法控制 stage
的设置方式。
观察变化是反模式和代码维护的噩梦。寻找任何其他可能的解决方案,例如使一个模块依赖于另一个模块,以便您知道它在模块运行之前已加载。
但是,你说没有别的办法,所以:
您不能为此使用代理,因为为了使其有效,代码设置 stage
必须通过代理进行设置,而不是直接设置。
您说过您无法控制 stage
的声明方式。这意味着您也不能为此使用 Object.defineProperty
,因为 var
创建的全局对象上的 属性 具有 configurable: false
.
如果绝对没有办法在您的模块和正在做的事情之间取得协调 stage
,您将不得不求助于计时器循环。这不是一个好主意,但可能是您唯一真正的选择:
var stop = Date.now() + 30000;
var timer = setInterval(function() {
if (typeof stage !== "undefined" || Date.now() > stop) {
clearInterval(timer);
timer = 0;
// Your code here, if `stage` is still undefined, you hit the timeout
}
}, 50); // 50ms interval or whatever you need
原回答
到目前为止这里最好的解决办法是:不要那样做。相反,使用带有 setter:
的对象
var stuff = {
_stage: undefined,
get stage() {
return _stage;
},
set stage(value) {
if (_stage === undefined && value !== undefined) {
_stage = value;
// Trigger your code here
}
}
};
然后让其他代码设置 stuff.stage
而不是设置 stage
.
如果你真的需要观察 stage
被其他东西定义时的变化,而 stage
是全局的,那么简单的解决方案是使用旧的 getter:
let myObj;
Object.defineProperty(window, 'stage1', {
set (value) {
myObj = new SomeObjThatNeedsStage(stage)
return value
}
})
在上面,确保你没有var stage = undefined
你不再需要它了。
请原谅我的无能... 我正在尝试在全局 var 阶段不再未定义后使用 Proxy 执行一些代码。这是我天真的尝试:
```
var stage = undefined
let myObj;
let st = {
stage: stage,
}
let lr = {
get: function(obj:any, prop:any):LightRay{
myObj = new SomeObjThatNeedsStage(obj[prop]) // <= supposed to be non-undefined stage
return myObj
},
}
let p = new Proxy(st, lr)
// At this point I expect the lr handler to have been executed if the stage var has been instantiated by some external code that's out of my control.
```
显然,我误解了代理的工作原理,但我尝试了各种方案,但没有一个可行。将未定义的阶段作为目标传递给代理不起作用(出现 Cannot create proxy with a non-object as target or handler
错误)。在这种情况下如何使用 Proxy?为什么我不能observe
undefined stage with Proxy 直到它被实例化,然后执行回调?
仅供参考:
Stage var 是全局的,我无法控制它(它在某些时候由 create.js 实例化)。所有代码都从 UMD 模块执行。我正在使用打字稿(转译为 es5)。 Object.defineProperty() 在我的浏览器中可用。此外,阶段(类型 createjs.Stage)在实例化时确实包含不同类型的 setter/getter,这在使用打字稿时会产生问题。
更新答案
您说过您无法控制 stage
的设置方式。
观察变化是反模式和代码维护的噩梦。寻找任何其他可能的解决方案,例如使一个模块依赖于另一个模块,以便您知道它在模块运行之前已加载。
但是,你说没有别的办法,所以:
您不能为此使用代理,因为为了使其有效,代码设置 stage
必须通过代理进行设置,而不是直接设置。
您说过您无法控制 stage
的声明方式。这意味着您也不能为此使用 Object.defineProperty
,因为 var
创建的全局对象上的 属性 具有 configurable: false
.
如果绝对没有办法在您的模块和正在做的事情之间取得协调 stage
,您将不得不求助于计时器循环。这不是一个好主意,但可能是您唯一真正的选择:
var stop = Date.now() + 30000;
var timer = setInterval(function() {
if (typeof stage !== "undefined" || Date.now() > stop) {
clearInterval(timer);
timer = 0;
// Your code here, if `stage` is still undefined, you hit the timeout
}
}, 50); // 50ms interval or whatever you need
原回答
到目前为止这里最好的解决办法是:不要那样做。相反,使用带有 setter:
的对象var stuff = {
_stage: undefined,
get stage() {
return _stage;
},
set stage(value) {
if (_stage === undefined && value !== undefined) {
_stage = value;
// Trigger your code here
}
}
};
然后让其他代码设置 stuff.stage
而不是设置 stage
.
如果你真的需要观察 stage
被其他东西定义时的变化,而 stage
是全局的,那么简单的解决方案是使用旧的 getter:
let myObj;
Object.defineProperty(window, 'stage1', {
set (value) {
myObj = new SomeObjThatNeedsStage(stage)
return value
}
})
在上面,确保你没有var stage = undefined
你不再需要它了。