Cast int to enum in javascript - javascript

How do you efficiently cast an int to enum in javascript?
Say I have this enum
enuTable = // Table enum
{
enuUnknown: 0,
enuPerson: 1,
enuItem: 2,
enuSalary: 3,
enuTax: 4,
enuZip: 5,
enuAddress: 6,
enuLocation: 7,
enuTasks: 8,
};
In part of the code I get a return value from an AJAX call that is a number corresponding to one of the above tables.
I can write a switch transforming the value, however is there a more efficient (briefer) way of casting an int to enum? One reason is, I don't want to constantly have to change the switch, in case I change the enum. I guess I could use an array with the enum names and construct an identifier to index into the enum, however again, I would need to change the array every time the enum is changed. I guess what I am looking for is a transparent method, that doesn't require beforehand knowledge of the enum.

Like this
var keys = Object.keys(enuTable).sort(function(a, b){
return enuTable[a] - enuTable[b];
}); //sorting is required since the order of keys is not guaranteed.
var getEnum = function(ordinal) {
return keys[ordinal];
}
UPD: Is some ordinal values are absent you can use
var keys = Object.keys(enuTable).reduce(function(acc, key) {
return acc[enuTable[key]] = key, acc;
}, {});

One option would be something like the following:
function toTableName(i) {
for(var p in enuTable) {
if(enuTable.hasOwnProperty(p) && enuTable[p] === i) {
return p;
}
}
throw new Error('that\'s no table...');
}

First of all, JavaScript doesn't have enumerations like C# has built-in.
Thus, I believe that if you receive an AJAX numeric-based identifier and you want to code a switch statement, you don't need to cast to Number in JavaScript, because your switch will compare your pseudo-enumeration property value:
switch(ajaxNumber) {
case enuTable.enuPerson:
break;
}
If you're looking for obtaining the enumeration value label (for example enuPerson) the following code should be enough (check out a working sample in jsFiddle):
// We're going to implement a basic enumeration prototype to generalize
// what you're looking for so you may re-use this code anywhere!
function Enum(valueMap) {
// We store the enumeration object
this._valueMap = valueMap;
this._valueToLabelMap = {};
var that = this;
// This will create an inverse map: values to labels
Object.keys(valueMap).forEach(function (label) {
that._valueToLabelMap[valueMap[label]] = label;
});
}
Enum.prototype = {
// Getting the whole label is as simple as accessing
// the inverse map where values are the object properties!
getLabel: function (value) {
if (this._valueToLabelMap.hasOwnProperty(value)) {
return this._valueToLabelMap[value];
} else {
throw Error("Enum instance has no defined '" + value + "' value");
}
}
};
var enuTable = new Enum({
enuUnknown: 0,
enuPerson: 1,
enuItem: 2,
enuSalary: 3,
enuTax: 4,
enuZip: 5,
enuAddress: 6,
enuLocation: 7,
enuTasks: 8,
});
// Now, if we provide a number, the fancy Enum prototype will handle it
// so you're going to get the whole enumeration value label!
var taxLabel = enuTable.getLabel(45);

I love Yury Tarabanko's solution, but it took me some time to understand what it does (including reading and understanding about reduce(). I can't comment on you #YuryTarabanko, but how did you come up with this?
The solution I whould come up with, is this one. You can access it the same as Yury's solution (keys[ajaxResponseNumber]). I tested it with jsPerf and this is faster in Firefox, but that's not relevant in this case.
var keys = {};
for (var x in enuTable) {
if (enuTable.hasOwnProperty(x)) { keys[enuTable[x]] = x; }
}

Related

JavaScript Constructor Function Methods

I am wondering why I need the PhoneNumberFormatter.prototype.slice method below.
Why can't I just use slice(3,6).join('') inside my other methods without needing to add PhoneNumberFormatter.prototype.slice method? When the interpreter doesn't find the method on the PhoneNumberFormatter object, wouldn't it just look up the prototype chain to find slice and join on the Array prototype?
function PhoneNumberFormatter(numbers) {
this.numbers = numbers;
}
PhoneNumberFormatter.prototype.render = function() {
var string = '';
string += this.parenthesize(this.getAreaCode());
string += ' ';
string += this.getExchangeCode();
string += '-';
string += this.getLineNumber();
return string;
};
PhoneNumberFormatter.prototype.getAreaCode = function() {
return this.slice(0, 3);
};
PhoneNumberFormatter.prototype.getExchangeCode = function() {
return this.slice(3, 6);
};
PhoneNumberFormatter.prototype.getLineNumber = function() {
return this.slice(6)
};
PhoneNumberFormatter.prototype.parenthesize = function(string) {
return '(' + string + ')';
};
// why do I need the following method?
PhoneNumberFormatter.prototype.slice = function(start, end) {
return this.numbers.slice(start, end).join('');
};
var phoneNumberOne = new PhoneNumberFormatter([6, 5, 0, 8, 3, 5, 9, 1, 7, 2]);
phoneNumberOne.render()
I guess it was created to make the code cleaner and prevents code duplication.
As the use of the slice keyword in two different places seems to confuse you I'll explain briefly the differences.
In your prototype methods (e.g. getAreaCode, getExchangeCode, ...), the keyword this represents a PhoneNumberFormatter object. When you call this.slice() (in the methods), you are calling the slice method of this object hence the one created in your code.
But in your slice method (the one in your code), you are calling this.numbers.slice(). Here you call the slice method on an array (this.numbers). You are using the native array method slice.
You could write your methods like so and remove the slice method created in your code:
PhoneNumberFormatter.prototype.getAreaCode = function() {
return this.numbers.slice(0, 3).join('');
};
I think the main confusion you seem to have is the name of the method slice. This leads you to believe that it is the array method, but in fact it is not.
The slice method mentioned in your code is the slice method of the PhoneNumberFormatter, not the one of the array.
Because of this, the interpreter could never find the slice method in the prototype chain, because the prototype of the PhoneNumberFormatter would be object, and just calling slice would rather throw an error that the method is undefined.
The this.slice method refers to PhoneNumberFormatter.prototype.slice and this one will refer to it's own numbers property and will then call the slice method on the numbers Array.
Maybe it is simply easier to rename the code like:
function PhoneNumberFormatter( numberArr ) {
this.numbers = numberArr.slice(); // copy numbers
}
PhoneNumberFormatter.prototype.getAreaCode = function() {
return this.take(0, 3);
};
PhoneNumberFormatter.prototype.take = function() {
return Array.prototype.splice.apply( this.numbers, arguments ).join('');
};
var formatter = new PhoneNumberFormatter([0,1,2,3,4,5,6,7,8,9]);
console.log(formatter.getAreaCode());
Which maybe makes it more clear to you, that the take method is simply a utility method simplifying your code, cause be honest, why would you want to repeat for 5 different methods the slice and join part, and then take a potential risk of copying an error 5 times, or in case you need to change something, need to make the same change 5 times

lambda like matching on json object for javascript backbone?

not a front end SME....is there a javascript or backbone(_) equivalent of this java 8 lambda instead of looping over a JSON array and matching on "type"? :
{
"things": [
{
"type": "THE_OTHER_THING"
},
{
"type": "MY_THING"
}
]
}
.
thing theThing = things.stream().filter(x -> x.getType() == ThingType.MY_THING).findFirst().orElse(null);
Assuming you are looking to iterate through an array and only return objects with a given type, I would suggest the following:
For single or little use, you could simply create the function that asserts the type of your choice:
function isThing(jsonObject) {
return jsonObject.type === "THIS_THING";
}
Or to avoid hard coding:
var THING_TYPE = "THIS_THING";
function isThing(jsonObject) {
return jsonObject.type === THING_TYPE;
}
Then you can apply this function to an array using its filter method.
var filteredList = completeList.filter(isThing);
filter, as described on MDN Array.prototype.filter, takes a function as an argument and applies it to every element within the array. If the function returns true, the element is added to a new array. Once the passed function has been applied to each element, the filter function returns the new array.
The above choice may be practical if you are simply looking for one or two types. However, if you have many types for which you might want filters, you should consider abstracting this away slightly, like so:
function createFilterWithType(desiredType) {
// will return true if jsonObject is of desired type
var typeAsserter = function (jsonObject) {
return jsonObject.type === desiredType;
}
return typeAsserter;
}
// Create functions that assert if object is given type
var isThisThingType = createFilterWithType("THIS_THING");
var isOtherThingType = createFilterWithType("OTHER_THING");
// Data
var completeList = [
{type:"THIS_THING", id:0},
{type:"OTHER_THING", id:1}
];
// Data filtered by applying asserters to completeList
var thingTypeList = completeList.filter(isThisThingType);
// returns [{type:"THIS_THING", id:0}]
var otherTypeList = completeList.filter(isOtherThingType);
// returns [{type:"OTHER_THING", id:1}]
Alternatively, you can create the asserters and apply in a single step:
var thingTypeList = completeList.filter(createFilterWithType("THIS_THING"));
var otherTypeList = completeList.filter(createFilterWithType("OTHER_THING"));
Though you remove a few lines by doing so, you lose in performance as each invocation of filter requires the creation of the anonymous assertion function. Worse still, compacting your code this way can make it far more difficult to reason about.

Dynamically assigning properties to a JavaScript object (trie)

I'm trying to implement a variation of a trie in JavaScript. Basically, it's an efficient data storage object in which the characters in keys are not repeated. In other words, if I have the keys "abe" and "ann," only one instance of the shared letter "a" should appear:
{
a: {
b: {
e: {
0: 'lincoln'
}
},
n: {
n: {
0: 'mcgee'
}
}
}
}
Here is the desired implementation and a few usage examples:
function Trie () {
// The top level of the trie.
var root = {};
return {
write: function (key, value) {
},
read: function (key) {
}
};
}
// Sample usage
var trie = new Trie();
trie.write('abe', 'lincoln');
trie.write('ann', 'mcgee');
trie.read('abe'); // returns 'lincoln'
trie.read('ann'); // returns 'mcgee'
I've run into a blocker with respect to the write method. Given a string key such as "abe," I need to assign a property to root['a']['b']['e']. I can't find a way to assign a value to an object property several layers deep when the number of keys and the values of the keys are unknown.
The only solution that comes to mind is, I think, a bad one: placing the path to the value into a string and using eval. For example: eval("root['a']['b']['e'] = 'lincoln'");
Is there a better solution for dynamically assigning the values? (I realize that this is a bit of complicated problem, so I'm happy to clarify by providing extra information.)
a very naive approach (given the requirements,though i would write a different implementation)
given a string of keys and a pointer to the root,and a value to assign;
function write(root,path,value){
var a = path.split(''); // 'abc'->['a','b','c']
var pointer = root;
var i=0;
while(i<a.length-1){
if(pointer[a[i]] == undefined){
pointer[a[i]]={};
}
pointer = pointer[a[i]];
i++;
}
pointer[a[i]]=value;
return root;
}
EDIT : i'm assuming all the keys exist on their respective object. I added a if condition in case some keys are not defined.
EDIT:2 split corrected, correcting a little bug right now ;)
EDIT:3 should work now.
usage : write({},'abc',1) // yields {a:{b:{c:1}}}
what you're looking for is a double array trie.
you can do a github search for that, but the two main libraries listed are:
doublearray, from the documentation:
var doublearray = require('./doublearray.js');
var words = [
{ k: 'a', v: 1 },
{ k: 'abc', v: 2 },
];
var trie = doublearray.builder().build(words);
trie.contain('a'); // -> true
trie.lookup('abc'); // -> 2
or datrie

JavaScript, overwrite object without losing reference

Application
I am working on a simple web application that is built on top of AngularJS. The application should be able to work offline as well as online. When the user is offline, the changes to the data is stored locally. Therefore, the id's that is used within this application in offline mode is only temporary id's, they get replaced when uploaded to the server
Problem
The data that are used in the application consists of complex objects (with relations/references to other objects). When i am saving to the server, i wanted the views to get updated with the new "real" id's.
However, since JavaScript works with objects as references im not able to do what i want to: $scope.data = newdata
This is not overwriting $scope.data but creates a new object. The old reference to the old data is still there.
Simplified example
var x = {id: 1, name: "myObject"}
var c = x // c = {id: 1, name: "myObject"}
x = {id: 2, name: "myNewObject"}
// c = {id: 1, name: "myObject"}
As you can see, c is still a reference to the old object. In practice, this causes that my view isn't updated with new data since it's still bound to the old data.
What i need to is to overwrite the properties of, in this example, x. I need to do this recursively since my real objects are complex, however it shouldn't enter any circular references, since this will probably cause stack overflow. If i am overwriting a with b and a has properties that b hasn't got, those properties should be removed.
What i need
I need some sort of function that overwrites all properties in a (old object) with the properties in b (new object). All properties that exists in a but not in b should be removed.
If your environment supports ECMAScript 2015, you can use Object.assign():
'use strict'
let one = { a: 1, b: 2, c: 3 };
let two = { b: 20, c: 30, d: 40 };
let three = Object.assign({}, one, two);
console.log(three);
// will output: Object {a: 1, b: 20, c: 30, d: 40}
(let is the new locally scoped version of var in ECMAScript 2015) more...
So in the case of your simple example:
var x = { id: 1, name: "myObject" };
Object.assign(x, { id: 2, name: "myNewObject" });
console.log(x);
// will output: Object {id: 2, name: "myNewObject"}
Using the "extend" method which is available in underscore and jquery:
//Clear all the 'old' properties from the object
for (prop in old_object) {delete old_object[prop]}
//Insert the new ones
$.extend(old_object, new_object)
I found a solution after some thinking. It's probably not the most efficient solution, but it does the job for me. The time complexity could probably be better, and all suggestions of improvement are welcome. First parameter is the object to be extended, the second the one to extend with. The third is supposed to be a boolean, indicating whether the properties in a that doesn't exist in b should be removed or not.
function extend(_a,_b,remove){
remove = remove === undefined ? false : remove;
var a_traversed = [],
b_traversed = [];
function _extend(a,b) {
if (a_traversed.indexOf(a) == -1 && b_traversed.indexOf(b) == -1){
a_traversed.push(a);
b_traversed.push(b);
if (a instanceof Array){
for (var i = 0; i < b.length; i++) {
if (a[i]){ // If element exists, keep going recursive so we don't lose the references
a[i] = _extend(a[i],b[i]);
} else {
a[i] = b[i]; // Object doesn't exist, no reference to lose
}
}
if (remove && b.length < a.length) { // Do we have fewer elements in the new object?
a.splice(b.length, a.length - b.length);
}
}
else if (a instanceof Object){
for (var x in b) {
if (a.hasOwnProperty(x)) {
a[x] = _extend(a[x], b[x]);
} else {
a[x] = b[x];
}
}
if (remove) for (var x in a) {
if (!b.hasOwnProperty(x)) {
delete a[x];
}
}
}
else{
return b;
}
return a;
}
}
_extend(_a,_b);
}
I'm adding an answer, even though everyone has explained both why and solutions.
The reason I'm adding answer, is because I've searched for this answer a few times over the years and always basically come to the same 2/3 SO questions. I put the solutions in the too-hard-basket, because the code I've been working with has many modules all following similar design patterns; it's just been too much work to try and resolve what boiled down to the same issue you were having.
What I've learned, and hopefully it holds some value for others out there now that I've actually re-factored our codebase to avoid this issue (sometimes maybe its unavoidable, but sometimes it definitely is), is to avoid using 'static private variables' to reference Objects.
This can probably be more genericised, but take for example:
var G = {
'someKey' : {
'foo' : 'bar'
}
};
G.MySingletonClass = (function () {
var _private_static_data = G.someKey; // referencing an Object
return {
/**
* a method that returns the value of _private_static_data
*
* #method log
**/
log: function () {
return _private_static_data;
} // eom - log()
}; // end of return block
}()); // end of Class
console.log(G.MySingletonClass.log());
G.someKey = {
'baz':'fubar'
};
console.log(G.MySingletonClass.log());
http://jsfiddle.net/goxdebfh/1/
As you can see, same problem experienced by the Questioner. In my case, and this use of private static variables referencing Objects was everywhere, all I needed to do was directly lookup G.someKey; instead of storing it as a convenience variable for my Class. The end result (though lengthier as a result of inconvenience) works very well:
var G = {
'someKey' : {
'foo' : 'bar'
}
};
G.MySingletonClass = (function () {
return {
/**
* a method that returns the value of _private_static_data
*
* #method log
**/
log: function () {
return G.someKey;
} // eom - log()
}; // end of return block
}()); // end of Class
console.log(G.MySingletonClass.log());
G.someKey = {
'baz':'fubar'
};
console.log(G.MySingletonClass.log());
http://jsfiddle.net/vv2d7juy/1/
So yeah, maybe nothing new given the question has been solved, but I felt compelled to share that because I was even lead to believe that the first example was the correct way to do things. Maybe in some cases it is, it definitely didn't turn out to be.
Hopefully that helps someone, somewhere!

Check if array[4][3][7][3] is defined

When there is a single dimension array, it is easy to check whether it is defined, by either simple calling arr[6] which will return undefined if such property does not exist or calling typeof arr[6] === undefined.
The problem is, that in my case I have arr[5][1][6][2][5][3][7], where arr[5] can be non existent, or arr[5][1], etc. Which will naturally trigger error: TypeError: Cannot read property [..] One solution is to write many IF statements. However, is there any better solution, that'd simple allow me to check whether arr[5][1][6][2][5][3][7] is defined?
I can't think of anything better than:
var defined = false;
try {
defined = !!arr[5][1][6][2][5][3][7]
} catch(e)
{
// nothing
}
But seriously bad design.
Since this seemed like an interesting problem, I wrote this function to solve it in a nice an non-exceptional way :)
var deepCheck = function(arr, indexes) {
var level = arr;
while(indexes.length) {
var v = indexes.shift()
if(!level[v]) {
return false;
}
level = level[v];
}
return true;
};
Now say you have this:
arr[foo][bar][baz];
You would check it using...
deepCheck(arr, [foo, bar, baz]);
Maybe I should point out that I do kind of agree that if you indeed have very very long arrays like that, it does sound like a design issue.
By using a try/catch block you can check if the element can be accessed.
var x;
try {
x = arr[5][1][6][2][5][3][7];
} catch(TypeError)
{
// the element cannot be accessed
x = undefined;
}
Then it's easy enough to check if 'x' is defined or not using an if statement.
A pragmatic approach would be to break this problem down into its component parts; look at what data is known and the tools you have at hand.
So, what do we know - well we know the keys that we want to inspect, in the case of checking if arr[5][1][6][2][5][3][7] is defined. Now ask yourself, what tools do we have in JavaScript? To check if an Array index is defined we can compare against null, ie:
if (array[index] === null) {
return false
}
If we were to try and write this code, one of the first things that should come to mind is to simply walk through each key, in order: eg:
if (array[5] === null) {
return false;
} else if (array[5][1] === null) {
return false
} ...snip...
// Good news, it's defined!
return true
Obviously this approach can be improved, it requires a tonne of duplicated code to be written out, it's inflexible and not reusable. If you ever find yourself doing the same thing over and over, you probably have a good candidate for a loop construct. In order for a loop you need a variant, something that will change with each repetition - in the example above the variant is the right most element of the nested array we are inspecting. First, let's start by listing our variants out:
var variants = [ 5, 1, 6, 2, 5, 3, 7 ];
for (var i = 0; i < variants.length; i++) {
console.log("variant: " + variants[i]);
}
Where, do we go from here? Well things get a bit harder, you need to understand how Arrays are passed by reference in JavaScript and exploit that in the loop body; ultimately you may end up with something like this:
function arrayDimensionsExist(source, dimensions) {
var currentDepth = source;
for (var i = 0; i < dimensions.length; i++) {
var key = dimensions[i];
if (currentDepth[key] === null) {
return false;
} else {
currentDepth = source[key];
}
}
return true;
}
Put the code accessing it between try and catch. If it works, it works, if not you get a nice exception and you can react accordingly.
As a side note, I shudder to think of what prompted you to design your system like that...
There's no solution built-in to the language, but you could handle it with a function like this:
var verifyIndexes = function(target) {
var current = target;
for (i = 1; i < arguments.length; i++) {
if (arguments[i] in current) {
current = current[arguments[i]];
} else {
return false;
}
}
return true;
}
var myArray = [[[1, 2, 3], 4], 5];
console.log(verifyIndexes(myArray, 0)); // true
console.log(verifyIndexes(myArray, 0, 0, 0)); // true
console.log(verifyIndexes(myArray, 0, 0, 3)); // false
console.log(verifyIndexes(myArray, 0, 1)); // true
console.log(verifyIndexes(myArray, 0, 2)); // false

Categories

Resources