I have functions in JavaScript that need to check that the function running it is, indeed, the correct function (ex, needs the function something.stuff.morestuff.coolFunction to have called it or it wont run).
I've tried getting Function.caller, but this only returns the function itself, and no way to determine which objects it is inside of.
Given the following setup:
function helloWorld(){
if(/* the exact path to the calling function */ === 'greetings.happy.classic.sayhello'){
console.log('Hello World');
}else{
console.log(/* the path from earlier */ + ' not allowed.');
}
}
greetings = {
happy: {
classic: {
sayHello: function(){ helloWorld(); }
sayBye: function(){ helloWorld(); }
}
},
angry: {
sayHello: function(){ helloWorld(); }
},
simple: [
function(){ helloWorld(); }
]
}
function sayWords(){
helloWorld();
}
What I'm trying to accomplish would look like this:
greetings.happy.classic.sayHello(); // => Hello World!
greetings.happy.classic.sayBye(); // => greetings.happy.classic.sayBye not allowed.
greetings.angry.sayHello(); // => greetings.angry.sayHello not allowed.
greetings.simple[0](); // => greetings.simple[0] not allowed.
sayWords(); // => sayWords not allowed.
helloWorld(); // => null not allowed.
// not sure what would come out of this, so i put null on that one
Here's the question in one neat little package:
How would I find the exact object path (i.e. greeting.happy.classic.sayHello) of the calling function? Function.caller.name just returns the name of the function, which is not enough. I need the full tree of the calling function's location.
This feels like a complex issue, so thank all for your help.
Well, you seem to be trying to find out parent's reference in the child object. This is not possible. Check out this post Javascript Object get parent
I think you could use new Error().stack to analyse where the call comes from.
Hopefully you're aware that any preprocessor/uglyfier/bundler is more than likely to break your approach ...
Related
I have a parent function with a single parameter.
I want to use this parameter in the naming of a couple child functions.
Can this be done?
function A(red) {
function redBall() {
stuff
}
function redHat() {
stuff
}
}
This is a more specific example of what I am trying to create.
I would run this function many times, which is why I need the child functions to have unique names based on the parameter provided.
function name(parameter) {
let parameterThis = '"' + parameter + 'This"';
let parameterThat = '"' + parameter + 'That"';
let $button = '$(".button.' + parameter + '")';
function parameterEnter() {
document.getElementById(parameterThis).style.opacity = "1";
document.getElementById(parameterThat).style.display = "block";
}
function parameterLeave() {
document.getElementById(parameterThis).style.opacity = "0";
document.getElementById(parameterThat).style.display = "none";
}
$button.hover(parameterEnter,parameterLeave);
}
TLDR: renaming functions isn't what you really want.
You don't need to make your functions named differently for it to work. That's not how programming is supposed to work. Instead, try to generalize what you're trying to do, so that it can be applied to whatever you pass in. Like, if you need it to do different things in certain cases, add another parameter to the function. Or, if you need unique things to happen for each element, make your function take enter/leave callback functions as arguments. Even if you did programmatically set the function names, you'd have a hard time calling them anyways, because you wouldn't know what they were called.
You could do something like this :
functionA (boolean condition)
{
if (condition)
fonctionB();
else
fonctionC();
}
functionB()
{
// Stuff
}
functionC()
{
// Stuff
}
If what you intend to do is to actually declare a function or another depending of a parameter, I don't think that's possible. But I don't really get why you would want to do that, and perhaps we could help you better if you were more accurate on that matter.
You can try like this, maybe simpler than passing arguments?
var foo = function() {
this.a = function () {
console.log('A function');
}
this.b = function() {
console.log('B function');
}
return this;
}
Then call function you want like this for example
foo().a();
EDIT:
I missunderstood your code, If I understand correctly now, you want to pass purely a string and then call function with such name immediately?
Well, you can do it using eval() but many people advise to stay away from using it, anywhere here it is:
function foo(whatFunction) {
function a() {
console.log('a function');
}
function b() {
console.log('b function')
}
eval(whatFunction)();
}
So then call it foo('b') for example
Seems like the answer to my actual question is no, judging by how everyone has responded.
I'll have to keep thinking on it and find another way to simplify my code.
There is a certain syntax that is baffling me and i see it with the map function and also with the observable in typescript/Angular (Angular 5). I have two methods:
This one is in a component:
logout() {
this.authService.logout().subscribe(
result => {
this.router.navigate(['/login']);
}
);
}
And this is in the related service:
logout(): Observable<any> {
return this.http.post('/api/auth/logout', { }).map(
response => {
this._token = null;
//more unrelated code...
return true
}
);
}
The part that is confusing me in both of these cases is this:
thing => {
//code
}
What is this? The code above works. but I see that have both 'result' and 'response' for thing. Can 'thing' be anything at all or is it defined somewhere?
Also, I looked up the map function in javascript at w3schools (because I've never had a use for it) and it shows in the example that the first parameter is supposed to be a function which gets applied to each element of the array that it is associated with but "thing => {}" is not a function so this is super confusing.
Note, that I have worded my question in such a way as to get to the underlying misunderstanding rather than focusing on my specific problem, however solving my specific problem may help illustrate my misunderstanding.
The problem with the code above is that while it works it does not know what to do when the api endpoint returns a 500 error. I am trying to determine how to catch the error so that I can do something with that on the front end.
Thing can be whatever you want to name it. Result, data, response, etc. Doesn't matter. What you're basically doing is creating a variable for the result emitted from your subscription. The subscription takes in a function() and inside that function, you pass the variable name that you want to be used for the success result. And really, here, using result is meaningless, since nothing is ever done with it. If you aren't going to do anything with the response, its better to just say:
logout() {
this.authService.logout().subscribe(() => {
this.router.navigate(['/login']);
});
}
To catch errors, you only need to pass a comma after the last curly, like so:
logout() {
this.authService.logout().subscribe(() => {
this.router.navigate(['/login']);
}, err => {
// Do something with error here
});
}
As for map, here is an example
var array1 = [1, 4, 9, 16];
const map1 = array1.map(x => x * 2);
It basically takes every variable in the array and performs that map method, meaning it takes each value and does whatever the function says to do, in this case, multiply it by 2. Think of it as a sort of transformation. In that example, it's basically being used to manipulate the response before sending it back to the subscription.
I'm currently in the process of converting our Backbone application to ES6 syntax like e.g. this:
action: function(e){},
Becomes
action(e) {}
However, now I'm having this code:
throttleEvent: _.throttle(function(e) {
//do stuff
}, 500);
}
And I can't seem to find how to convert this to valid syntax.
I tried
throttleEvent _.throttle((e) => {
//do stuff
}, 500);
}
And
throttleEvent() {
return _.throttle((e) => {
//do stuff
}, 500);
}
But these all failed to work.
Help converting this to the valid syntax would be appreciated.
Well I'm not quite sure if the short syntax is applicable for your example.
Lets have a look at your start
action: function(e){},
you have an object, that object has a property called "action" and that property holds a function that later then can be called by obj.action().
Now to your example
throttleEvent: _.throttle(function(e) {}
Again you have an object, that has a property called throttleEvent. But the main difference is the value. The value is the return Value of the function _.throttle().
Taking from the documentation (https://lodash.com/docs/4.17.4#throttle)
Creates a throttled function that only invokes func at most once per every wait milliseconds
So your property actually holds the function that you got returned from the library. That explains why your second approach does not work. Because in this version every time you call the object property, you create a new throttle function.
(And to your first solution I think this is invalid syntax)
I think the best approach if you really want to use the short syntax is, assigning the throttle function to a variable before and then use it
For example something like this
const throttleFunction = _.throttle((event) => {
//do stuff
}, 500);
const obj = {
throttleEvent(event): any {
return throttleFunction(event);
},
};
But then it is to decide whether the ES6 syntax makes sense in this case or if you just stick with your original version
throttleEvent: _.throttle(function(e) {
//do stuff
}, 500)
Just because there is a different syntax available, does not mean you always have to use the new one. In some cases the "old one" makes actually more sense
try this syntax:
_.throttle(() => //Do stuff, 5000)
EDIT:
Everything is working as I expected. It was just an error calling the template method. I mistyped a () so I was trying template.method instead of template().method;
Anyway, if somebody would like to explain me if this is a valid design pattern or if I should go in a different way I will be definitively very grateful.
I read about the module pattern and I'm trying to implement it in some of my projects. The problem is that, in my opinion, I'm twisting it too much.
I'm inspired by the google apps script style where many objects returns other objects with methods and so on and they pass arguments.
something like
object.method(var).otherMethod();
What I want to achieve is a method that receives a parameter, sets an internal variable to that parameter and then returns an object with methods that uses that variable. Here is a minified version of the code that does not work:
var H_UI =(function (window) {
var selectedTemplate,
compileTemplate = function(){},
parseTemplateFields = function(){};
//template subModule. Collect: collects the template fields and returns a JSON representation.
var template = function(templateString){
if(templateString) selectedTemplate = templateString;
return {
getHtml:function(){ return compileTemplate( parseTemplateFields( selectedTemplate ) ) } ,
collect:function(){
.. operating over selectedTemplate ...
return JSON.stringify(result)}
} };
return {
template:template
};
})(window);
If I remove the line :
if(templateString) selectedTemplate = templateString;
and replace selectedTemplate with the parameter templateString in the methods of the returned object it works as expected. I know that I cant create a set() method in the returned object and use it like this
H_UI.template().set(var)
But I find it ugly. Anyway I think that I'm messing things up.
What is the best way to construct this?
If you want H_UI.template() creates a new object every time you call template() on it, your solution does not work. Because the variable selectedTemplate is created only once when the immediate function is called.
However if your intent is this your solution works fine. (variable selectedTemplate is shared for all calls to template()).
But if you want to every call to template creates a new object. Please tell me to write my idea
Is this a valid design pattern or if I should go in a different way
Yes, enabling chaining is definitely a valid design pattern.
However, if your template() method returns a new object, that object and its methods should only depend on itself (including the local variables and parameters of the template call), but not on anything else like the parent object that template was called on.
So either remove that "global" selectedTemplate thing:
var H_UI = (function () {
function compileTemplate(){}
function parseTemplateFields(){}
// make a template
function template(templateString) {
return {
getHtml: function(){
return compileTemplate(parseTemplateFields(templateString));
},
collect: function(){
// .. operating over templateString ...
return JSON.stringify(result)
}
}
}
return {template:template};
})();
or make only one module with with a global selectedTemplate, a setter for it, and global methods:
var H_UI = (function () {
var selectedTemplate;
function compileTemplate(){}
function parseTemplateFields(){}
return {
template: function(templateString){
if (templateString)
selectedTemplate = templateString;
return this; // for chaining
},
getHtml: function(){
return compileTemplate(parseTemplateFields(selectedTemplate));
},
collect: function(){
// .. operating over selectedTemplate ...
return JSON.stringify(result)}
}
};
})();
The difference is striking when we make two templates with that method:
var templ1 = H_UI.template("a"),
templ2 = H_UI.template("b");
What would you expect them to do? In a functional design, templ1 must not use "b". With the first snippet we have this, and templ1 != templ2. However, if .template() is a mere setter, and every call affects the whole instance (like in the second snippet), we have templ1 == H_UI and templ2 == H_UI.
I want to write my own function in JavaScript which takes a callback method as a parameter and executes it after the completion, I don't know how to invoke a method in my method which is passed as an argument. Like Reflection.
example code
function myfunction(param1, callbackfunction)
{
//do processing here
//how to invoke callbackfunction at this point?
}
//this is the function call to myfunction
myfunction("hello", function(){
//call back method implementation here
});
You can just call it as a normal function:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction();
}
The only extra thing is to mention context. If you want to be able to use the this keyword within your callback, you'll have to assign it. This is frequently desirable behaviour. For instance:
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction.call(param1);
}
In the callback, you can now access param1 as this. See Function.call.
I too came into same scenario where I have to call the function sent as parameter to another function.
I Tried
mainfunction('callThisFunction');
First Approach
function mainFuntion(functionName)
{
functionName();
}
But ends up in errors. So I tried
Second Approach
functionName.call().
Still no use. So I tried
Third Approach
this[functionName]();
which worked like a champ. So This is to just add one more way of calling. May be there may be problem with my First and Second approaches, but instead googling more and spending time I went for Third Approach.
function myfunction(param1, callbackfunction)
{
//do processing here
callbackfunction(); // or if you want scoped call, callbackfunction.call(scope)
}
object[functionName]();
object: refers to the name of the object.
functionName: is a variable whose value we will use to call a function.
by putting the variable used to refer to the function name inside the [] and the () outside the bracket we can dynamically call the object's function using the variable. Dot notation does not work because it thinks that 'functionName' is the actual name of the function and not the value that 'functionName' holds. This drove me crazy for a little bit, until I came across this site. I am glad stackoverflow.com exists <3
All the examples here seem to show how to declare it, but not how to use it. I think that's also why #Kiran had so many issues.
The trick is to declare the function which uses a callback:
function doThisFirst(someParameter, myCallbackFunction) {
// Do stuff first
alert('Doing stuff...');
// Now call the function passed in
myCallbackFunction(someParameter);
}
The someParameter bit can be omitted if not required.
You can then use the callback as follows:
doThisFirst(1, myOtherFunction1);
doThisFirst(2, myOtherFunction2);
function myOtherFunction1(inputParam) {
alert('myOtherFunction1: ' + inputParam);
}
function myOtherFunction2(inputParam) {
alert('myOtherFunction2: ' + inputParam);
}
Note how the callback function is passed in and declared without quotes or brackets.
If you use doThisFirst(1, 'myOtherFunction1'); it will fail.
If you use doThisFirst(1, myOtherFunction3()); (I know there's no parameter input in this case) then it will call myOtherFunction3 first so you get unintended side effects.
Another way is to declare your function as anonymous function and save it in a variable:
var aFunction = function () {
};
After that you can pass aFunction as argument myfunction and call it normally.
function myfunction(callbackfunction) {
callbackfunction();
}
myfunction(aFunction);
However, as other answers have pointed out, is not necessary, since you can directly use the function name. I will keep the answer as is, because of the discussion that follows in the comments.
I will do something like this
var callbackfunction = function(param1, param2){
console.log(param1 + ' ' + param2)
}
myfunction = function(_function, _params){
_function(_params['firstParam'], _params['secondParam']);
}
Into the main code block, It is possible pass parameters
myfunction(callbackfunction, {firstParam: 'hello', secondParam: 'good bye'});
callbackfunction = () => {}
callbackfunction2(){
}
function myfunction1(callbackfunction) {
callbackfunction();
}
//Exe
myfunction1(callbackfunction);
myfunction1(callbackfunction2.bind(this));
Super basic implementation for my use case based on some excellent answers and resources above:
/** Returns the name of type member in a type-safe manner. **(UNTESTED)** e.g.:
*
* ```typescript
* nameof<Apple>(apple => apple.colour); // Returns 'colour'
* nameof<Apple>(x => x.colour); // Returns 'colour'
* ```
*/
export function nameof<T>(func?: (obj: T) => any): string {
const lambda = ' => ';
const funcStr = func.toString();
const indexOfLambda = funcStr.indexOf(lambda);
const member = funcStr.replace(funcStr.substring(0, indexOfLambda) + '.', '').replace(funcStr.substring(0, indexOfLambda) + lambda, '');
return member;
}