Call a function according to its string name [duplicate] - javascript

This question already has answers here:
How to execute a JavaScript function when I have its name as a string
(36 answers)
Closed last year.
I have a code which would be very repetitive, which according to the name of the string of an array executes one function or another.
I give an example of a code as I could do it.
// I use underscore in NodeJS
_.each(refresh, (value, key) => {
if(key === 'station') {
station.add({ id: value });
} else if(key === 'concentrator') {
concentrator.add({ id: value });
} else if....
});
It is possible to run the function according to your string to avoid so much checking with IF, etc.
[key].add({ id: value });
I have been watching several hours on the internet about the use of call, apply, etc; but I do not understand how it works well, perhaps because my knowledge of Javascript is not advanced.
Thanks !

Creating an anonymous function on an object is the best approach. As you can use the key to call the method.
Here is an example in code pen:
https://codepen.io/liam-hamblin/pen/KKyapNP
The code above takes in the key used to assign the function and does not require any checks. However, it is always the best approach to check that the key exists before calling.
const operations = {};
operations.add = (obj) => {
document.write("add - ");
document.write(JSON.stringify(obj));
}
operations.subtract = (obj) => {
document.write("subtract - ");
document.write(JSON.stringify(obj));
}
const input = prompt("Enter Function Name, type either subtract or add");
if (operations[input]) {
operations[input]({id:1});
} else {
document.write("no matching method")
}

Related

JavaScript - get a property from an object or throw error if undefined [duplicate]

This question already has answers here:
if (key in object) or if(object.hasOwnProperty(key)
(9 answers)
Closed 4 years ago.
I was wondering if there was a standard library or external library (eg lodash) function that essentially does following:
function f(options) {
const x = options.x;
if (x === null || x === undefined) throw new Error('x is required option');
...
}
I have searched various key words in the lodash documentation but have yet to find something like this.
To check if a property exists, you can just write if(x in options)... Libraries exist to make tedious or difficult operations simple, This is such a simple operation that no library is needed and you'd be unlikely to find it added to a library.
While .hasOwnProperty() can work, it will only test for properties attached directly to the object in quesiton, while the in approach tests for inherited properties as well.
But, be careful about throwing errors. It's not generally something that you want to do for performance reasons. It's better to return a code or message.
var options = {
foo:42,
bar:"doesn't matter"
};
function propTest(propName, obj){
// Instead of throwing an error, return a value that indicates success or not
return (propName in obj) ? true : false;
}
console.log(propTest("foo", options));
console.log(propTest("bar", options));
console.log(propTest("baz", options));
You can write a function that iterates through an objects keys and looks for undefined ones
function CheckObjectProperties(obj)
{
for (var key in obj)
{
if(!obj[key])
{
throw new Error('Object has one or more undefined members');
}
}
}
or if you wanna check if an unknown object you can do something along the line of this. This approach is much more dynamic and reusable :D
function CheckObjectForProperties(obj, arraryOfStringProperties)
{
for(let i = 0; i < arraryOfStringProperties.length; i++)
{
let key = arraryOfStringProperties[i];
if(!obj[key])
{
throw new Error('Member not Found in Given Object.');
}
}
}
let myObject = {
x : 1,
y : 2,
z : undefined
}
let requiredProperties = ['x', 'y', 'z'];
CheckObjectForProperties(myObject, requiredProperties);

How to detect that a multi-level object has an undefined or null property? [duplicate]

This question already has answers here:
Test for existence of nested JavaScript object key
(64 answers)
Closed 6 years ago.
In many places in my code, I have checks similar to the one below. It's very verbose, and ugly. Is there is better way? FYI, I'm using Lodash in all my projects, so I have access to that powerful library.
if (myAssessments[orderId].report &&
myAssessments[orderId].report[categoryProductCode] &&
myAssessments[orderId].report[categoryProductCode].categories &&
myAssessments[orderId].report[categoryProductCode].categories[comment.categoryId]) {
// Do something related to
// myAssessments[orderId].report[categoryProductCode].categories[comment.categoryId]
}
Since you use lodash, you might use the has method:
_.has(obj,[orderId, 'report', categoryProductCode, 'categories', comment.categoryId])
https://lodash.com/docs/4.16.6#has
Or the get method to get the value of the object path: https://lodash.com/docs/4.16.6#get
Not elegant way but you can wrap in try catch
var result;
try{
result = myAssessments[orderId].report[categoryProductCode].categories[comment.categoryId]
}catch{}
if (result){
// do it
}
Use the built-in isset function:
if (isset(myAssessments[orderId].report) &&
isset(myAssessments[orderId].report[categoryProductCode]) &&
isset(myAssessments[orderId].report[categoryProductCode].categories) &&
isset(myAssessments[orderId].report[categoryProductCode].categories[comment.categoryId)]) {
You could use an array with all properties to check and iterate until all properties have been checked.
function checkProperties(object, keys) {
return keys.every(function (key) {
if (key in object) {
object = object[key];
return true;
}
});
}
// usage
if (checkProperties(myAssessments, [orderId, 'report', categoryProductCode, 'categories', comment.categoryId])) {
// Do something related to
// myAssessments[orderId].report[categoryProductCode].categories[comment.categoryId]
}
I have this genric function
function chckForKeyPresence(data, arr, checkLength){
var currData = data;
for(var i=0; i<arr.length; i++){
if(!currData.hasOwnProperty(arr[i]))
return false;
currData = currData[arr[i]];
}
if(checkLength)
if(currData.length==0)
return false;
return true;
}
Here 1st argument is the main data, 2nd argument is the array of properties you need to check and the third argument will check the length of the last element that it is 0 or not, it will check only if the third argument is true.
You can use it like:
if(!chckForKeyPresence(data, ["results", "tweets"], true)){
// error
return;
}

Return object in array with specific property [duplicate]

This question already has answers here:
Find object by id in an array of JavaScript objects
(36 answers)
Closed 4 months ago.
I'm fairly new with writing my own JS functions, and I'm struggling with this one.
I want to run through an array of objects, find an object that matches a particular ID, and then return that object.
So far this is what I have:
var findTeam = function() {
$scope.extraTeamData.forEach(team) {
if(team.team_id === $scope.whichTeam) { return team }
}
$scope.thisTeam = team;
};
$scope.teamDetails is my array, and the $scope.whichTeam variable holds the correct ID which I am checking against.
Ultimately I want to be able to assign the object that results from the function to the $scope.thisTeam variable, so I can call its properties in the view.
Any help would be appreciated.
Thanks.
You could use Array#some which ends the iteration if found
var findTeam = function() {
$scope.extraTeamData.some(function (team) {
if (team.team_id === $scope.whichTeam) {
$scope.thisTeam = team;
return true;
}
});
};
Move your $scope.thisTeam = team; to within the if check.
var findTeam = function() {
$scope.teamDetails.forEach(team) {
if(team.team_id === $scope.whichTeam) {
$scope.thisTeam = team;
}
}
};
$scope.team = $scope.teamDetails.filter(function (team) {
return team.team_id === $scope.whichTeam;
})[0];
You need to use filter method of array. It creates new array elements that match given predicate (function that return boolean value). Then you simply take first value.
You can also use find, but it is not implemented in every browser yet.
It would look something like this:
$scope.team = $scope.teamDetails.find(function (team) {
return team.team_id === $scope.whichTeam;
});

javascript mystery - how functions get access to outside variables [duplicate]

This question already has answers here:
How do JavaScript closures work?
(86 answers)
Closed 7 years ago.
I am kind of new to javascript and trying to understand some non trivial - at least so i hope :) things.
my question is general, but i have a specific example which can help me ask my question and help you understand what i mean.
the example:
function updateBookmark(bookmark){
var index = _.findIndex($scope.bookmarks, function(b){
return b.id == bookmark.id;
});
return index;
}
obviously the findIndex function is declared somewhere (in our case - lodash.js)
and it gets two parameters (at least two visible parameters: a data set, and a function)
first question:
in this example, what is b? how does b gets its value? i understand b is each of the data set's objects, but i mean - what is going behind the scenes here so b will be what it is??
second question:
the author chose to pass an anonymous function which equals b.id with bookmark.id,
i understand that he can use bookmark.id where he is using it, but how does findIndex has access to this bookmark?!
this function as i concluded earlier is declared somewhere else, does it get all the variables in the scope some how?
what is going on here?
Thanks in advance to responders and sorry for the messy question...
Jim.
If you rewrite some things, it becomes easier to understand.
Starting with the last portion:
// Q: "How does `findIndex`have access to `bookmark`"
_.findIndex(bookmarks, function (b) { });
// A: "It doesn't."
var bookmark = { id: 1 };
var bookmarks = [ /* ... */ ];
function compareWithBookmark( test ) {
return test.id === bookmark.id;
}
_.findIndex(bookmarks, compareWithBookmark);
As you can see, findIndex doesn't actually have any access to bookmark.
Rather, it has access to a function which it can pass a value to test, and that function will return whether that test passed or failed.
Under the covers of .findIndex or [].map or [].filter, they're all just taking a function, making a loop, passing each element into the function one at a time, and doing something with the return value.
function findIndex (array, test) {
var index = -1;
var i = 0;
var l = array.length;
var el;
var result;
for (; i < l; i += 1) {
el = array[i]; // <-- how `b` got its value
result = test(el, i, array); // <-- test(b)
if (!!result) {
index = i;
break;
}
}
return index;
}
The different functions would do different things with the results (map returns a new array which contains each result, filter returns an array where only !!result tests passed, et cetera), but all of them do this inner-looping.
This is also a pretty gross simplification of the looping structure and considerations, but it's exactly what's driving your expected behaviour.
Edit
Here is a full usage of the function I just defined, plus the array, plus the object I'm checking.
var bookmarks = [
{ id: 2 },
{ id: 3 },
{ id: 6 },
{ id: 14 }
];
var bookmark = { id: 3 };
function compareBookmarkIdTest (el) {
return el.id === bookmark.id;
}
var index = findIndex(bookmarks, compareBookmarkIdTest);
index; // 1
Hope that helps.

How do you access an object within an object from an argument in Javascript? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Accessing nested JavaScript objects with string key
I have the function
function _get(name) {
return plugin._optionsObj[name] !== undefined ?
plugin._optionsObj[name] : plugin._defaults[name];
}
I would like to be able to have objects inside of my _defaults object, but then I don't know how to retrieve them but using just one set of square brackets.
i.e.
plugin._defaults = {
val1: 1,
val2: 2,
obj1: {
someVal: 3
}
}
Is it possible to access 'someVal' from the function I have above? I tried passing 'obj1.someVal' for the argument and it didn't work. Ideas?
Edit: I have found a solution and I posted it below as an answer. I've written a very nice little function to do go through the nested values with a string and I didn't have to change my function much to implement it. I hope this helps anyone in a similar situation.
I suspect that you won't always have a one-level nested object to access, so the cleaner way to do this is to use a function that traverses an object based on a string path. Here's one that is coded as a mixin for Underscore. You can then just use it like so:
_.deep(plugin._defaults, 'obj1.someVal');
This thread also has some non-Underscore alternatives.
Pass multiple arguments, and iterate over the arguments object.
function _get(/* name1, name2, namen */) {
var item = plugin._optionsObj,
defItem = plugin._defaults;
for (var i = 0; i < arguments.length; i++) {
item = item[arguments[i]];
defItem = defItem[arguments[i]];
if (item == null || defItem == null)
break;
}
return item == null ? defItem : item;
}
var opt = _get("obj1", "someVal")
I found a solution for this problem, at least one that will accommodate myself, and I'd like to share it in case it can help someone else with this problem. My biggest difficulty is that I did not know the depth of the nested value so I wanted to find a solution that would work for deeply nested objects and without requiring to redesign anything.
/* Retrieve the nested object value by using a string.
The string should be formatted by separating the properties with a period.
#param obj object to pass to the function
propertyStr string containing properties separated by periods
#return nested object value. Note: may also return an object */
function _nestedObjVal(obj, propertyStr) {
var properties = propertyStr.split('.');
if (properties.length > 1) {
var otherProperties = propertyStr.slice(properties[0].length+1); //separate the other properties
return _nestedObjVal(obj[properties[0]], otherProperties); //continue until there are no more periods in the string
} else {
return obj[propertyStr];
}
}
function _get(name) {
if (name.indexOf('.') !== -1) {
//name contains nested object
var userDefined = _nestedObjVal(plugin._optionsObj, name);
return userDefined !== undefined ? userDefined : _nestedObjVal(plugin._defaults, name);
} else {
return plugin._optionsObj[name] !== undefined ?
plugin._optionsObj[name] : plugin._defaults[name];
}
}
To retrieve objects inside of your _defaults object you'll need to improve your _get function.
For example you may pass an array of strings (each string representing a propery name) to _get to allow access to deeply nested objects.

Categories