JavaScript Nested Functions cross referencing - javascript

I have a nested function that needs a return type of the previously declared function to use it as a function argument . I don't know if my structure is correct or can support this .
would be grateful for some advice on how to call it
var myObject = {
funct1 : (function (){..... return funct1; })(),
funct2 : (function (funct1){..... return func2; })(funct1)
};
So the question is how would I call that funct1 argument correctly in the second function
Do I use the myObject.Funct1 or is there another method of calling that object internally ...
Im currently getting a error
Cannot read property 'funct1' of undefined

I don't think there is a way to do this by declaring an object literal since the keys of the object can't be used during the object creation.
You can get the same functionality by doing this, though:
const myObject = (() => {
const func1 = () => 'result of func1';
const func2 = () => func1() + ' and func2';
return { func1, func2 }
})();
console.log(myObject.func2()); // result of func1 and func2

Related

How can I "recursively" stringify a javascript function which calls other scoped functions?

Because javascript functions are not serializable, in order to pass them into new contexts sometimes (albeit rarely) it can be useful to stringify them then re-evaluate them later like:
const foo = () => { // do something }
const fooText = foo.toString()
// later... in new context & scope
const fooFunc = new Function(' return (' + fooText + ').apply(null, arguments)')
fooFunc() // works!
However, if foo references another function bar, the scope is not stringified, so if bar is not defined in the new context, the evaluated foo function will throw an error when called.
I'm wondering if there is a way to stringify a function recursively?
That is, not only stringifying the parent function, but also stringifying the contents of the child functions called from the parent.
For Example:
let bar = () => { alert(1) }
let foo = () => { bar() }
// what toString does
let fooString = foo.toString()
console.log(fooString) // "() => { bar() }"
// what we want
let recursiveFooString = foo.recursiveToString()
console.log(recursiveFooString) // "() => { alert(1) }"
Let me know if you have any ideas on how to accomplish something like a "recursiveToString"
The only good way to do this is to start from a parent scope that encloses all functions foo eventually references. For example, with your foo and bar, if you want to pass foo into another context such that bar is callable as well, pass a function that declares both foo and bar, and returns foo. For example:
const makeFoo = () => {
let bar = () => { alert(1) }
let foo = () => { bar() }
return foo;
};
const makeFooStr = makeFoo.toString();
// ...
const makeFooFunc = new Function(' return (' + makeFooStr + ').apply(null, arguments)');
const foo = makeFooFunc();
foo();
Implementing this sort of thing well does require premeditated design like above (unfortunately). You can't really include all ancestor LexicalEnvironments (the internal map of variable names to values in a given scope) when stringifying.
I'm wondering if there is a way to stringify a function recursively?
I think we can fairly simply demonstrate that this is impossible in general.
Let's think about these two function
const greet = (greeting) => (name) => `${greeting} ${name}`
const sayHi = greet ('Hi')
sayHi ('Jane') //=> "Hi Jane"
While with your foo and bar example, we could possibly imagine something that examined the body of the function and used everything available in the current scope to do your extended stringify function based on parsing the function and knowing what local variables are actually used. (I'm guessing that this would be impossible too, for reasons related to Rice's Theorem, but we can certainly imagine it.)
But here, note that
sayHi.toString() //=> "(name) => `${greeting} ${name}`"
and so sayHi depends on a free variable that's not stored in our current scope, namely, greeting. We simply have not stored the "Hi" used to create that function anywhere except in the closure scope of sayHi, which is not exposed anywhere.
So even this simple function could not be reliably serialized; there seems little hope for anything more complex.
What I ended up rolling with was inspired by #CertainPerformance's answer.
The trick is to build a function which defines all the child callee functions. Then you have everything you need to stringify the parent function.
Note: to allow for imported callee functions from other files, I decided to programmatically build a string with the callee definitions rather than defining them originally in the same scope.
The code:
// original function definitions (could be in another file)
let bar = () => { alert(1) }
let foo = () => { bar() }
const allCallees = [ bar, foo ]
// build string of callee definitions
const calleeDefinitions = allCallees.reduce(
(definitionsString, callee) => {
return `${definitionsString} \n const ${callee.name} = ${callee.toString()};`;
},
"",
);
// wrap the definitions in a function that calls foo
const fooString = `() => { ${calleeDefinitions} \n return foo(); \n }`;
console.log(fooString);
/**
* fooString looks like this:
* `() => {
* const bar = () => { alert(1) };
* const foo = () => { bar() };
* return foo();
* }`
**/
// in new context & scope
const evaluatedFoo = new Function(' return (' + fooString + ').apply(null, arguments)');
// works as expected
evaluatedFoo();

Call a function starting only with the function name as a string (ES6 syntax)

I'm doing a weird thing where I get the name of a function, and call the function with that name, like this:
function myFunc(){
//do somethng
};
var myFuncName = 'myFunc';
window[myFuncName](); // Expected result.
...which works, but now I've defined the func using ES6 const naming, window[myFuncName] is undefined:
const myFunc = () => {
//do somethng
};
var myFuncName = 'myFunc';
window[myFuncName](); // window[myFuncName] is not a function.
Does anyone know how to call an ES6 function when you have only it's name as a string? I'm working in a browser Web Extension but think this is a general JavaScript problem. Thanks!
It'd only be possible with eval, which shouldn't be used:
eval(myFuncName + '()');
Instead, change your code so that the function is put onto an object (even if it's not the window), then use ordinary bracket notation to look up the property value (just like you're doing with window, except with fns instead), and call the retrieved function:
const fns = {
myFunc() {
console.log('do something');
}
};
const myFuncName = 'myFunc';
fns[myFuncName]();
If you want to more closely imitate const for the property on the object, use Object.defineProperty to make sure the function property can't be deleted nor reassigned, via configurable: false:
'use strict';
const fns = {};
Object.defineProperty(fns, 'myFunc', {
configurable: false,
value: () => {
console.log('do something');
}
});
const myFuncName = 'myFunc';
fns[myFuncName]();
// can't reassign property:
fns.myFunc = 'foo';

How can I get the arguments for function that I pass as a parameter to another function?

I'm trying to access arguments from the function that is being passed as a parameter to make sure to pass those through, however I'm getting the error:
TypeError: 'caller', 'callee', and 'arguments' properties may not be accessed on strict mode functions or the arguments objects for calls to them
How can I get the arguments for func so that I can pass the message through when calling it?
UPDATE: maybe a better question is why can't I log func.arguments?
function a(func){
console.log(func.arguments)
return function(){
func.apply(null, func.arguments);
}
}
function log(message){
console.log(message)
}
a(log.bind('hello'))()
It can be done but its not pretty. you have to return an object with the parameters you want from the function you are passing
function a(func){
console.log(func.arguments)
//you dont actually need this since you have already called the function before passing
//return function(){
// func.apply(null, func.arguments);
//}
}
function log(message){
console.log(message);
return {
arguments : arguments //store the arguments and return them
};
}
//you not actually passing the function here (the way you have it written)
//you are calling it and returning its value
//we return { arguments: arguments } so the "a" function can retrieve its properties.
a(log("hello"));
I guess what you're trying to do is to intercept a function with a "logging" function.
If so, there is a different approach, using ES6 rest params --
let withLog = func => (...args) => {
console.log(...args);
return func(...args);
};
let add = (x, y) => x + y;
withLog(add)(2, 3); // outputs '2 3', returns 5

Why pass an undefined javascript function parameter?

So I'm learning Javascript and I see this code:
var apple = {//... an object with some properties};
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple});
Where someMethod and a_property_of_apple are valid methods and properties.
My question pertains to the argument, b, of the anonymous function which is not declared or defined anywhere else:
function (b) {return ...
What is going on here? What is b and why is it being used?
Apologies in advance for the basic nature of the question. If someone just wants to drop some focused terms on me to read up on that would be great short of an explanation.
The anonymous function is a callback function being passed to the apple.method() invocation.
apple.method() will invoke that anonymous function at some point during it's execution, ( or pass it to another function ). Whenever it's invoked it will be invoked with an argument that will be available inside the callback. You could call it b, or response, or whatever you want (logical names are best) and be able to use it within the anonymous function.
You should read about Callback functions over at MDN.
EDIT: I will explain the parts to you
var apple = {} This is the definition of an object
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple}); is defining that fruit is equal to the return value of the invocation of apple.someMethod(...)
apple.someMethod(function (b) {return b.a_property_of_apple}); is the invocation of apple.someMethod with function (b) {return b.a_property_of_apple} as the only argument.
The b argument in the anonymous function function (b) {return b.a_property_of_apple} will be passed to it's invocation within the apple.someMethod.
Here is an example snippet.
// define apple
var apple = {
// define method
someMethod: function( callback ) {
var obj = {
a_property_of_apple: "Eat me!" // this will be returned
}
// return the invocation of callback with obj as argument
return callback(obj);
}
}
var fruit = apple.someMethod(function (b) {return b.a_property_of_apple});
console.log(fruit);
EDIT: Ok, going to use something slightly less abstract as an example.
// notice employees being passed to this function
// that is called an argument and is usable inside the function
var orginization = function( employees ) {
// this will take the empoyees argument and assign it to this.employees
// or set this.employees to an empty array if there is no employees argument
this.employees = employees || [ ];
// this is a method ( a method is a function on an object )
// this function takes 3 arguments
this.addEmployee = function( employee ) {
// we use the 3 arguments to push a new object with title, name, and salary
// properties provided by the function arguments
this.employees.push( employee );
}
// this method returns the value stored in this.employees
this.getEmployees = function() {
return this.employees;
}
}
// this is a variable an array of employees only containing 1 employee
// i will use it in the creation of my new orginization
var employess = [
{
title: "CEO",
name: "Enola",
salary: "$$$$$$$"
}
];
// i use the new to create learningInc from originization( employees )
// originization is a constructor function which creates an object
// with methods and properties found on the constructor
var learningInc = new orginization( employess );
// console.log learningInc.getEmployees() an you will see still only the CEO
// works here
console.log( "before newHire: ", learningInc.getEmployees() );
// lets make a newHire
var newHire = {
title: "Peon",
name: "Sadly McFrownFace",
salary: "$"
};
// add the newHire to the employess of learningInc wth out getEmployees() method
learningInc.addEmployee( newHire );
// log the new value of learningInc.getEmployees and you see we now have 2 employees
console.log( "after newHire: ", learningInc.getEmployees() );
Ok now notice this line var learningInc = new orginization( employess );
The employees variable I'm passing to this function as an argument is used in this function var orginization = function( employees ) { ... }.
Hope this help.
My question pertains to the parameter, b, of the anonymous function which is not declared or defined anywhere else: What is going on here?
What is b and why is it being used?
Why you say it is not declared? It is declared right there. Consider this simple JavaScript function:
function doSomething(a, b){
//do something here;
}
In this code, we are creating a function, naming it "doSomething", and declaring two parameters for it a and b. This is how we declare function parameters in JavaScript. Now your example:
function (b) {return ...
is exactly the same, except we didn't give this function a name, which means it is an anonymous function. That's the only difference, but its parameter b is declared right there like any standard function. So there is nothing special going here, it's a standard function parameter and used as such.
There are a couple concepts at work here
Function declarations vs function expressions; you can use function as an operator to define a function, and assign the function to an identifier and pass it around like any normal object
Callbacks; you can pass a function CB into another function A to be called by A (as defined by A)
Passing something without an identifier
Function Declaration
// declare function
function foo(argFoo) {
console.log('foo', argFoo);
}
// invoke function
foo('was declared'); // "foo" "was declared"
Function Expression
// express function
var bar = function (argBar) {
console.log('bar', argBar);
};
// invoke function
bar('was expressed'); // "bar" "was expressed"
Callbacks
function fizz(callback) {
console.log('first I fizz');
callback();
}
function buzz() {
console.log('then I buzz');
}
fizz(buzz);
// "first I fizz"
// "then I buzz"
Passing without an Identifier,
Basically, defining things in-place
// say we have some fn fizzbuzz
function fizzbuzz(foo) {
console.log(foo);
}
// we could pre-define what we want to pass to it
var i = 1;
fizzbuzz(i); // 1
// or we could pass directly
fizzbuzz(1); // 1
// with anything we like
fizzbuzz({some: 'object'}); // {some: "object"}
// even a function
fizzbuzz(function () {}); // function () {}
Maybe if I break down what is happening into more readable code, you can see what is happening.
someMethod is a method that take a function as an argument. This is more easily seen when broken down like below.
It's up to someMethod to determine what they do with that function. In this example, I am executing the function being passed into someMethod and passing it my this context.
var apple = {
name: 'Apple',
someMethod: function(func) {
return func(this);
}
};
function getName (b) {
return b.name;
};
const name = apple.someMethod(getName); // Apple
To your question: b is defined as the first argument to your anonymous function. This is more clearly expressed when the code is broken out above. But you could also express it like this:
const name = apple.someMethod(function(x) { return x.name; }); // Apple
or like this using ES6:
const name = apple.someMethod(x => x.name); // Apple

How Come public method is not printing in a IIFE?

Shouldn't hello be printed in the console because of the return statement? The code is immediately invoked because of the () at the end so why isn't it printing?
var Module = (function () {
var privateMethod = function () {
// private
};
var someMethod = function () {
// public
console.log('hello');
};
var anotherMethod = function () {
// public
};
return {
someMethod: someMethod,
anotherMethod: anotherMethod
};
})();
return {
someMethod: someMethod, // just a function reference
anotherMethod: anotherMethod // again a function reference
};
So, you're not calling the function. You're just returning the function reference attached to a property of an object. Try to use comma operator here, which evaluates to the right most statement, whilst executing someMethod() function.
return {
someMethod: someMethod(), someMethod, // first getting called and someMethod ref is passed to the property
anotherMethod: anotherMethod
};
It's because of the var keyword on the top infront of Module.
f you do the following in the console:
var a = 5 // a is set to 5 yet undefined is shown in the console.
If you were to take off the var keyword:
a = 5 // a is again set to 5 yet 5 is shown in the console.
But in your real code you would want to use the var keyword.
So simply put it's just the console's way of outputting like that, idk why.
Enlighting more,
function itseld is object of Function (see https://msdn.microsoft.com/en-us/library/ie/x844tc74%28v=vs.94%29.aspx)
So Basically you are adding a reference to object of type Function, which is not IIFE.

Categories