使用 Aurelia 进行全局变量订阅
Global var subscription with Aurelia
我在 HTML 的脚本标签中初始化了一些全局变量:
<script>
count = 0;
window.count2 = 0;
var count3 = 0;
</script>
在app.js
,我订阅观察他们的变化:
let subscription = bindingEngine.propertyObserver(window, 'count')
.subscribe((newValue, oldValue) => console.log('Global count: ', newValue, oldValue));
let subscription2 = bindingEngine.propertyObserver(window, 'count2')
.subscribe((newValue, oldValue) => console.log('window.count2: ', newValue, oldValue));
let subscription3 = bindingEngine.propertyObserver(window, 'count3')
.subscribe((newValue, oldValue) => console.log('Global count3: ', newValue, oldValue));
然后我像这样更改值:
change() {
count++;
count2++;
count3++;
}
只有 count
&& count2
在控制台中被观察到:
Global count: 1 0
window.count2: 1 0
这里是GistRun
问题:为什么count3
观察不到?我认为3种初始化形式是等价的。
我试过你的例子并弄清楚哪里出了问题。然后我做了一些研究并了解了为什么。
所以,问题是您定义全局变量的三种方式实际上是 而非 等效的 (Difference between variable declaration syntaxes in Javascript (including global variables)?)。关键是不能从 window 对象中删除使用 var
声明的全局变量。这很重要。
你看,Aurelia 根本不使用脏检查。当它被告知观察一个对象上的 属性 时,它会将 属性 包装在一个 SetterObserver
对象中,这样 Aurelia 就可以知道 属性 的值何时发生变化.这避免了脏检查,而无需更改设置 属性 值的方式。
因此,Aurelia 将您创建的 属性 替换为包装器。它通过使用 Reflect.defineProperty
方法来实现。这是内置的 API (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/defineProperty)。但请记住,不能从 window 对象中删除全局变量。这也意味着 Reflect.defineProperty
无法重新定义 属性.
最后这意味着这是浏览器自身的限制API。
需要注意的是,这仅适用于严格模式(Aurelia 在其中运行)。我创建了一个显示此 here 的要点。如果你删除 "use strict" 行,浏览器可以让你做任何你想做的事并且它可以工作,但在严格模式下它会抛出一个错误。
我在 HTML 的脚本标签中初始化了一些全局变量:
<script>
count = 0;
window.count2 = 0;
var count3 = 0;
</script>
在app.js
,我订阅观察他们的变化:
let subscription = bindingEngine.propertyObserver(window, 'count')
.subscribe((newValue, oldValue) => console.log('Global count: ', newValue, oldValue));
let subscription2 = bindingEngine.propertyObserver(window, 'count2')
.subscribe((newValue, oldValue) => console.log('window.count2: ', newValue, oldValue));
let subscription3 = bindingEngine.propertyObserver(window, 'count3')
.subscribe((newValue, oldValue) => console.log('Global count3: ', newValue, oldValue));
然后我像这样更改值:
change() {
count++;
count2++;
count3++;
}
只有 count
&& count2
在控制台中被观察到:
Global count: 1 0
window.count2: 1 0
这里是GistRun
问题:为什么count3
观察不到?我认为3种初始化形式是等价的。
我试过你的例子并弄清楚哪里出了问题。然后我做了一些研究并了解了为什么。
所以,问题是您定义全局变量的三种方式实际上是 而非 等效的 (Difference between variable declaration syntaxes in Javascript (including global variables)?)。关键是不能从 window 对象中删除使用 var
声明的全局变量。这很重要。
你看,Aurelia 根本不使用脏检查。当它被告知观察一个对象上的 属性 时,它会将 属性 包装在一个 SetterObserver
对象中,这样 Aurelia 就可以知道 属性 的值何时发生变化.这避免了脏检查,而无需更改设置 属性 值的方式。
因此,Aurelia 将您创建的 属性 替换为包装器。它通过使用 Reflect.defineProperty
方法来实现。这是内置的 API (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/defineProperty)。但请记住,不能从 window 对象中删除全局变量。这也意味着 Reflect.defineProperty
无法重新定义 属性.
最后这意味着这是浏览器自身的限制API。
需要注意的是,这仅适用于严格模式(Aurelia 在其中运行)。我创建了一个显示此 here 的要点。如果你删除 "use strict" 行,浏览器可以让你做任何你想做的事并且它可以工作,但在严格模式下它会抛出一个错误。