I want to house a variable in a function. This variable will change state depending on user interaction. For example:
function plan_state(current){
if (current != ''){
state = current;
}
else {
return state;
}
}
When the document loads I call plan_state('me'), and when certain things happen I may call plan_state('loved'). The problem occurs when I run a function and want to check the current state:
alert(plan_state());
I get undefined back, but the value should be 'me' as I previously set this value on document load.
What am I doing wrong?
The function isn't stateful because the state variable is declared inside the function and therefore only exists for the lifetime of the function call. An easy solution would be to declare the variable globally, outside the function. This is bad bad bad bad.
A better approach is to use the module pattern. This is an essential pattern to learn if you're serious about javascript development. It enables state by means of internal (private variables) and exposes a number of methods or functions for changing or getting the state (like object oriented programming)
var stateModule = (function () {
var state; // Private Variable
var pub = {};// public object - returned at end of module
pub.changeState = function (newstate) {
state = newstate;
};
pub.getState = function() {
return state;
}
return pub; // expose externally
}());
so stateModule.changeState("newstate"); sets the state
and var theState = stateModule.getState(); gets the state
I believe the scope of your variable is too "low"; by defining the variable within the function, either as a parameter or explicitly as a var, it is only accessible within the function. In order to achieve what you're after, you can either implement the variable outside the scope of the function, at a more global evel (not recommened really).
However, after re-reading your question, it's slightly miss-leading. Would you not want to return state regardless of the current? I think you might be after something like so:
var state;
function plan_state(current)
{
if (current != '' && current != state)
{
state = current;
}
return state;
}
Alternative object structure:
function StateManager(state)
{
this.state = state;
this.getState = function(current)
{
if (current != '' && current != this.state)
{
this.state = current;
}
return this.state;
}
}
// usage
var myStateManager = new StateManager("initial state here");
var theState = myStateManager.getState("some other state");
Related
I'm trying to move from procedural to object-oriented JavaScript and I'm coming up against an issue I'm sure there's an answer to, but I can't work it out.
Currently, each of my methods checks the state of a property, and then performs an action based on that state. What I'd rather do is update the state and those methods execute as a result of the state change. Is that possible, or am I missing the point?
Here's what I have currently:
class ClassExample {
constructor({state = false} = {}) {
this.state = state;
...
}
aMethod() {
if(this.state) {
//Do something
this.state = false;
} else {
//Do something else
this.state = true;
}
}
bMethod() {
if(this.state) {
//Do something
this.state = false;
} else {
//Do something else
this.state = true;
}
}
}
And:
const myObject = new ClassExample();
myObject.aMethod();
myObject.bMethod();
Given both methods are checking the same property, it's resulting in a lot of redundant if statements. Is there a better way to organise this class to achieve the same result?
I'd suggest you use an event driven system based on the EventEmitter() object built into node.js.
To keep track of state changes, you can define a setter for your state variables so that any time someone sets a new state, then your setter function will get called and it can then trigger an event that indicates the state changed. Meanwhile, anyone in your object out outside your object can register an event listener for state changes.
Here's a short example:
const EventEmitter = require('events');
class ClassExample extends EventEmitter {
constructor(state = 0) {
super();
// declare private state variable
let internalState = state;
// define setter and getter for private state variable
Object.defineProperty(this, "state", {
get: function() {
return internalState;
},
set: function(val) {
if (internalState !== val) {
internalState = val;
// send out notification
this.emit("stateChanged", val);
}
}
});
}
}
let e = new ClassExample(1);
console.log(e.state);
e.on("stateChanged", function(newVal) {
console.log("state has changed to ", newVal);
});
e.state = 3;
console.log(e.state);
I'm going through Immutable.js's source code and there's an ownerID field that I don't understand.
Here's the source for Map.asMutable() and Map.asImmutable(): https://github.com/facebook/immutable-js/blob/master/src/Map.js#L171
It seems like the only difference between a mutable and an immutable object are their ownerIDs. What is an ownerID and what is it used for?
If you track back the property:
L#14:
import { DELETE, SHIFT, SIZE, MASK, NOT_SET, CHANGE_LENGTH, DID_ALTER, OwnerID,
MakeRef, SetRef, arrCopy } from './TrieUtils'
in src/TrieUtils.js :
L#36:
// A function which returns a value representing an "owner" for transient writes
// to tries. The return value will only ever equal itself, and will not equal
// the return of any subsequent call of this function.
export function OwnerID() {}
It is some property they create like hash to represent a virtual owner.
It is used to ensure mutability in asMutable returned instances. When asMutable is invoked, it ensures an __ownerId and returns the current instance back -
asMutable() {
return this.__ownerID ? this : this.__ensureOwner(new OwnerID());
}
Then any supported mutating operations return the current instance back, instead of creating a new instance with the changes (which is key for immutability).
E.g., here's how the "clear" method operates based on the presence of __ownerId -
clear() {
if (this.size === 0) {
return this;
}
if (this.__ownerID) {
this.size = 0;
this._root = null;
this.__hash = undefined;
this.__altered = true;
return this;
}
return emptyMap();
}
Notice that when this.__ownerID is present, the method returns the current instance (thereby mutating itself). But when it is absent, it returns a new map for ensuring immutability.
From the source code:
// A function which returns a value representing an "owner" for transient writes
// to tries. The return value will only ever equal itself, and will not equal
// the return of any subsequent call of this function.
function OwnerID() {}
My understanding of the above is that the this.__ownerID field is used to compare objects. A Map being compared against itself will have the same ownerID, while a Map being compared against another Map will see two different ownerIDs.
You can see an example of this usage a little farther down in the file in question:
__ensureOwner(ownerID) {
if (ownerID === this.__ownerID) {
return this;
}
if (!ownerID) {
this.__ownerID = ownerID;
this.__altered = false;
return this;
}
return makeMap(this.size, this._root, ownerID, this.__hash);
}
In fact, searching the entire repo, you'll see that this function is common across data types, with each type having a slightly modified version to return a correct new version of that type.
I'm quite new to Angular and am trying to understand how everything works. I've been poking around and couldn't find any information on how to do this. So, I've got a service that defines
this.totalCount = 0;
In my controller, my get request retrieves some emails and then executes a function called addMessage for each message it retrieves. The addMessage function is in my service.
The function in my service looks like this:
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
}
Basically, I am trying to increment this.totalCount each time this function is executed so that it will update and then can be displayed in the view. I have it displaying in the view currently, however its number always remains 0.
I've tried the following:
1.
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
this.totalCount++;
}
2.
var count = this.totalcount
this.addMessage = function (messageObj) {
this.messagesList.push(messageObj);
count++; //and then attempted to display this value in the view but with no luck
}
Any tips would be greatly appreciated.
try this:
var that = this;
this.addMessage = function (messageObj) {
that.messagesList.push(messageObj);
}
I assume that you're binding the var this way in your controller and your view
Service :
this.totalCount = 0;
this.totalCount++;
Controller :
$scope.totalCount = service.totalCount;
view :
{{totalCount}}
And if you're actually doing it like this, you should face this kind of trouble.
The main problem is that totalCount is a primitive var and doing this.totalCount++ will break the reference. If you want to keep some var you should bind it as a sub-object.
This way :
Service :
this.utils = {};
this.utils.totalCount = 0;
this.utils.totalCount++;
Controller :
//This is the most important part. You bind an object. Then even if you loose the totalCount reference, your object will keep its own reference.
$scope.myServiceUtils = service.utils;
View :
{{myServiceUtils.totalCount}}
Actually in service (it's a matter of taste) i prefer a lot to use the object syntax instead of this (as "this" can be confusing)
This way :
var service = {};
service.utils.totalCount = 0;
service.addItem = function(){
...
}
return service;
Hope that was your issue.
You pass argument to another function which has different scope than your service. It is trick with assigning current object to variable, which is visible from function.
var that = this;
this.addMessage = function (messageObj) {
that.messagesList.push(messageObj);
that.totalCount++;
}
Should work.
So you assign that variable with current object, which is visible in inner function scope.
In a function addMessage body, this refers to function scope which is new, and there is no compiler error, but messagesList is a null object and totalCount is incremented, but after program leave function, it's not visible in service, because it is in a function scope which isn't assigned to any variable.
To update service variable as it changes in your controller, use $watch.
$scope.$watch(function() {
return messagesService.totalCount;
}, function(new,old){
$scope.totalmessagecount = messagesService.totalCount;
});
First parameter of $watch if function which return observed for change element. Another is standard function to perform operation after update.
Im trying to store the stats of 'this' in my javscript object so that later on in my application I can return 'this' to a previous state. I thought I could accomplish using a closure but so far I haven't successful. My idea was to do something like this
function SavedFeature() {
var self = this;
this.savedItem;
this.storeState = function() {
this.savedItem = storeClosure();
}
function storeClosure() {
var closure = self;
return function() {
return closure;
};
};
//other things the user can change...
}
so later on in my application if I needed to return to the point when I called storeState I could just do
//return the object I put in my closure
var backToNormal = savedFeature.savedItem();
that doesn't work though because any changes to my savedFeature object after I call storeState() are being reflected in the item im retrieving from called savedItem(). I'm guessing this is happening because closure is being set to a reference of self instead of copied to a new instance.
Is there anyway to store the state of my entire object in a closure like this or do I need to store this some other way.
The issue you are running into is that in js objects are passed by reference. This means that all changes performed on your object will apply to your obj.savedItem property.
Fix: Store a deep clone into obj.savedItem
this.storeState = function() {
this.savedItem = _.cloneDeep(this); // or _.clone(this, true);
}
cloneDeep is a lodash method, most js libs supply one of their own, e.g. jQuery's $.extend, etc.
You could easily roll your own deep clone function, look up the options on this thread.
A complete example with jQuery:
function SavedFeature() {
this.savedItem;
this.clone = function() {
return $.extend(true, {}, this);
},
this.storeState = function() {
this.savedItem = this.clone();
}
}
Doing it this way allows you adapt to different environments by changing your clone method as it is facading the used library method.
There are dozens of ways how to implement it. I will do just simple one. saving property.
Take into account if you want to save entire object you need to do deep copy of the object.
this is your feature:
function SavedFeature() {
this.savedItem = {'isNew': true};
this.stateMachine = new StateMachine();
}
this is some kind of state machine:
function StateMachine () {
var state = { 'isNew' : null};
function set(newState) {
state.isNew = newState.isNew;
}
function get() {
return state.isNew;
}
return {
get : get,
set : set
};
}
which, know how to store isNew property
and a working sample:
var savedFeature = new SavedFeature();
console.log(savedFeature.savedItem); // true by default
savedFeature.stateMachine.set(savedFeature.savedItem); // saving state.
savedFeature.savedItem.isNew = false; // modifying state
console.log(savedFeature.savedItem); // return false, because of statement above
var restoredState = savedFeature.stateMachine.get(); // restoring state
console.log(restoredState); // true
savedFeature.savedItem.isNew = restoredState.isNew;
console.log(savedFeature.savedItem); // true
you can adjust that code, and reach functionality whatever you need. hope that helps
I've got a state machine in JS which (to simplify) has an initial state that is only set before anything happens.
define(function() {
var state = 'initial',
exports = {};
exports.getState = function() {
return state;
};
exports.doSomething = function() {
state = 'newState';
};
return exports;
});
Because the state is permanent until the app is reloaded, after the first test the state will never be 'initial' again, and so I need a way to reset it.
Which is the least dirty way of doing this? Should I...
a) simply make state public but mark it as private with _?
define(function() {
var exports = {};
exports._state = 'initial'
exports.getState = function() {
return this.state;
};
exports.doSomething = function() {
this.state = 'newState';
};
return exports;
});
b) make the state writable via a function?
define(function() {
var state = 'initial',
exports = {};
exports.getState = function() {
return state;
};
exports.doSomething = function() {
state = 'newState';
};
if(window.xxTests) {
window.xxTests.Module = {
setState: function(newState) {
state = newState;
}
};
}
return exports;
});
(where xx is the app prefix and xxTests is defined only as part of the test runner)
or
c) do something else entirely I didn't think of?
Your thoughts and suggestions are appreciated.
General answer: The better way of testing a component without exposing private data is putting test code inside that component. Of course this becomes quite dirty if your language doesn't support this in a clean way (like D does).
In your case I suggest the second way (I mean your option b), because it doesn't expose private data unless explicitly needed (only during tests):
if(youAreDoingATest)
{
exports.reset=function() { state='initial'; };
}
There's not a lot of context on how you're running your tests.
Most test runners have beforeEach(), beforeAll(), afterEach(), and afterAll() methods that can be used for setup and tear-down that run as their names suggest.
To solve your specific problem I would not change your "state machine" code at but instead I would create a new state machine in the beforeEach() function so that each test gets the new function object with the state set to 'initial'.