qtuan
qtuan

Reputation: 687

Global var subscription with Aurelia

I have some global vars initialized in a script tag in HTML:

<script>
  count = 0;
  window.count2 = 0;
  var count3 = 0;
</script>

In app.js, I subscribe to observe their changes:

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));  

Then I change the values like this:

change() {
    count++;
    count2++;
    count3++;
}

only count && count2 are observerd in console:

Global count:  1 0
window.count2:  1 0

Here is GistRun

Question: why count3 cannot be observed? I thought 3 forms of initialization are equivalent.

Upvotes: 1

Views: 1071

Answers (1)

Ashley Grant
Ashley Grant

Reputation: 10887

I played around with your example and figured out where things are going wrong. Then I did some research and learned the why.

So, the thing is that the three ways you are defining a global variable actually are not equivalent (Difference between variable declaration syntaxes in Javascript (including global variables)?). The key thing is that a global variable declared using var cannot be deleted from the window object. This is important.

You see, Aurelia doesn't use dirty checking if at all possible. When it is told to observe a property on an object, it will wrap that property in a SetterObserver object that allows Aurelia to know when the property's value gets changed. This avoids dirty checking without you needing to change how you set property values.

So, Aurelia replaces the property you created with a wrapper. It does this by using the Reflect.defineProperty method. This is a built in API (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Reflect/defineProperty). But remember that global variables can't be deleted from the window object. This also means that Reflect.defineProperty cannot redefine the property.

In the end this means that it's a limitation of the browser's own APIs.

One caveat is that this only applies in strict mode (which Aurelia runs in). I've created a gist that shows this here. If you delete the "use strict" line, the browser lets you do whatever you want and it works, but in strict mode it throws an Error.

Upvotes: 7

Related Questions