Issue
I am playing with AngularJS constants. I am observing that I am able to change the value of the constant
s I use. That doesn't make sense. Why I am able to change the value of a constant?
I am creating the constant like this:
var app = angular.module('app', []);
app.constant('Type', {
PNG: 'png',
GIF: 'gif'
});
app.constant('serialId', 'aRandomId');
Even if I create the constant using angular.value
, I am still able to change it.
To change the value of constant I am doing this in my controller:
app.controller('MainController', [
'$scope',
'Type',
'serialId',
'$timeout',
function ($scope, Type, serialId, $timeout) {
$scope.data = {
type: Type,
serialId: serialId,
};
$timeout(function () {
Type.PNG = 'this is changed';
serialId = 'new Serial Id';
console.log(serialId);
}, 1000);
},
]);
But the definition of "constant" is that what I get is constant. It is something whose value does not change and has a fixed value. MDN says that once you declare the constant you cannot change it if constant is not an object.
For example:
const x=10;
x=20; //will throw an error.
const obj={};
obj.a='ab'; //will not throw an error.
But in case of AngularJS constants, nothing prevents me from changing the value. It does not even notify that the value is changed. But their documentation does not talk about changing the value of constants.
TL;DR: If we can change the value of an AngularJS constant like a plain JavaScript variable then why do they are called constants?
Here's a fiddle to demonstrate.
Solution
There's a difference between:
- Value types (strings, booleans, etc); and
- Reference types (references to objects, arrays, etc);
A variable can be of either type.
Constant variables are called "constants" because you cannot change their content: you cannot set a new value or reference, respectively.
Put differently, for reference types being constant means you cannot change that variable so that it'll reference something else. As you noted, you can change the contents of whatever object a reference variable points to.
If you want to make an object itself "constant", you can use Object.freeze
:
var app = angular.module('app', [])
.constant('Type', Object.freeze({ PNG: 'png', GIF: 'gif' }))
.constant('SerialId', 'asdfgh12345')
.controller('myController', ['$timeout', 'Type', 'SerialId', MyController]);
function MyController($timeout, Type, SerialId) {
var vm = this;
// This .data property nor its properties are constant or frozen...
vm.data = {
type: Type,
serialId: SerialId
};
$timeout(function() {
Type.PNG = 'this is changed in timeout';
SerialId = 'changed serial id in timeout';
}, 1000);
$timeout(function() {
var el = document.getElementById('x');
var injector = angular.element(el).injector();
vm.secondData = {
type: injector.get('Type'),
serialId: injector.get('SerialId')
}
}, 2000);
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.js"></script>
<div ng-app="app" ng-controller="myController as vm" id="x">
<pre>{{ vm | json }}</pre>
</div>
Note that Object.freeze
does not do so recursively, you'd need a function/library for that.
Note also that I snuck in some comments about SerialId
. First up, realize that there's three different things named "SerialId
":
- An angular constant names "
SerialId
"; - A function argument named "
SerialId
"; - The third item (string) in the dependencies array, "
SerialId
";
When the controller constructor function is run, the function argument will be filled with the value from the constant. The function argument could've been named Foo
as well, by the way. You should consider that argument to be a local non-constant variable with the same value as the constant has.
Answered By - Jeroen
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.