injecting a custom named function into the js Function constructor - javascript

I am trying to pass a custom function named callpaul() into the scope of the Function constructor so that the function can be called inside the scope of Function. According to the MDN docs it seems like this should work, what am I doing wrong?
let fil={}
let trans={val:"fil.res=[1,2].join('&')"}
console.log(`WORKS------`)
Function('fil', '"use strict";return (' + trans.val + ')')(fil);
console.log({fil})
console.log(`FAILS-----`)
trans={val:"fil.res=callpaul('a')"}
Function('callpaul','fil', '"use strict";return (' + trans.val + ')')(`function callpaul (p){return 'hi'+p}`,fil);
console.log({fil})

You are not using the Function constructor correctly - the first arguments will be the names of the parameters within the newly created argumented. I have renamed some variables to make it more understandable (the first param is the function being passed it, and the second param is where the result is stored into) and it now works.
console.log(`FAILS-----`) //now actually works
trans={val:"output.res=passedFunction('a')"}
//Define the new function and store it in newfunc
let newfunc = Function('passedFunction','output', '"use strict";return (' + trans.val + ')');
//Call the new function, passing in your callpaul function to be called, and fil to hold the result
newfunc( function callpaul (p){return 'hi'+p;}, fil) );
console.log({fil});

Related

How to locally change options object property without redefining it globally

I'm trying to understand the proper ways to keep options object properties the same on the global scope while changing them locally inside other functions.
What I'm trying to accomplish is this: I have one function that all the others use that accepts specific parameter names. So, I need each of the initial functions that use this shared function to be able to redefine the options object property value and then execute the shared function using the shared parameter name but with its unique property value.
The example below demonstrates my issue. In the example, all of the functions (as shown via console.log) produce the correct value except for the final function. Part of the problem is that cat() and dog() are redefining the value of options.x globally instead of locally. I was hoping that I could use let to change the parameters locally and then pass it to mouse(), but using let options.x = 3; let x = options.x; produces an error.
I've heard that I can return/redefine the global scoped options.x value after the function runs to set it back, but I would prefer to never change the global parameter values in the global scope if possible. That way I don't run the risk of functions accidentally using each other's uniquely defined parameters.
var options = {x: 10}
console.log(options.x + ' original options object');
cat(options);
function cat() {
options.x = 3;
x = options.x;
console.log(x + ' cat = 3'); // this should equal 3
mouse(x);
}
dog(options);
function dog() {
options.x = 7;
x = options.x;
console.log(x + ' dog = 7'); // this should equal 7
mouse(x);
}
// SHARED FUNCTION
function mouse() {
console.log(x + ' mouse = cat() and/or dog()'); // I want this to equal 3 for cat() and 7 for dog() just as it is with x defined inside cat() and dog().
}
console.log(options.x + ' final global scope check = 10'); // I want this to remain 10, not 3. But the changes in cat() are poluting the global definition of options.x.
The code below simply eliminates the options object and seems to work easily. Maybe I should simply avoid using the object at all to avoid these issues?
var param = 1;
console.log(param + ' param should = 1');
cat();
function cat() {
var param = 3;
console.log(param + ' param should = 3');
mouse(param);
}
dog();
function dog() {
var param = 7;
console.log(param + ' param should = 7');
mouse(param);
}
// SHARED FUNCTION
function mouse(param) {
console.log(param + ' should log as whatever value the other functions sent');
}
console.log(param + ' param global check');
The problem is that you are reassigning the object options every time, since the objects are reference types. Even if you would do something like this in your function: newOptions = options you would still reference your old options object and any changes on the "new" newOptions object would also change the options object.
However if you want to get the exact same object and change it without affecting the other one you must clone it. You can achieve this in JavaScript with Object.create() method. You can read more about it here.
So your entire code would then look like this:
var options = {x: 10}
console.log(options.x + ' original options object');
cat(options);
function cat(options) {
newOptions = Object.create(options);
newOptions.x = 3;
x = newOptions.x;
console.log(x + ' cat = 3'); // this should equal 3
mouse(x);
}
dog(options);
function dog(options) {
newOptions = Object.create(options);
newOptions.x = 7;
x = newOptions.x;
console.log(x + ' dog = 7'); // this should equal 7
mouse(x);
}
// SHARED FUNCTION
function mouse(x) {
console.log(x + ' mouse = cat() and/or dog()'); // I want this to equal 3 for cat() and 7 for dog() just as it is with x defined inside cat() and dog().
}
console.log(options.x + ' final global scope check = 10'); // I want this to remain 10, not 3. But the changes in cat() are poluting the global definition of options.x.

Getting value of a variable the moment the function is declared?

Let's say I declare a function and use it as a handler for an event on an object.
Let's say that it needs to access a variable who's value will change before the event is called.
How do I provide to the function the value of the variable the moment the function is declared?
For example:
var I_Like_to_Change_Frequently = "...";
some_DOM_object.addEventListener( "some_arbitrary_event_to_fire_later", function I_Need_the_Current_Value(){
alert( "at the time I was defined, 'I_Like_to_Change_Frequently' was " + I_Like_to_Change_Frequently)
})
var I_Like_to_Change_Frequently = undefined //doesn't really matter. The point is it changes
EDIT: This codeblock is repeated multiple times in a for loop where some_DOM_object is different each iteration. Every iteration I_Like_to_Change_Frequently changes as well.
A couple options:
1) Move your code into a function. The function parameter will be a new binding, and thus will be "locked in" to that value
function createListener(domObject, val) {
domObject.addEventListener("some_arbitrary_event_to_fire_later", function () {
alert("at the time i was defined, I_Like_to_Change_Frequently was " + val;
});
}
var I_Like_to_Change_Frequently = "...";
createListener(some_DOM_object, I_Like_to_Change_Frequently);
var I_Like_to_Change_Frequently = undefined
2) Do it inline with an IIFE
var I_Like_to_Change_Frequently = "...";
(function (val) {
some_DOM_object.addEventListener( "some_arbitrary_event_to_fire_later",
function (){
alert( "at the time I was defined, 'I_Like_to_Change_Frequently' was " + val)
})
})(I_Like_to_Change_Frequently);
var I_Like_to_Change_Frequently = undefined
Using Function.prototype.bind():
You can also make use of the javascript bind() function to define the scope of the function.
This way, the variable value at the time of creation of the function can be retained.
some_DOM_object.addEventListener( "some_arbitrary_event_to_fire_later", (function I_Need_the_Current_Value(){
alert( "at the time I was defined, 'I_Like_to_Change_Frequently' was " + this.variableAtTheTimeOfCreation)
}).bind({variableAtTheTimeOfCreation: I_Like_to_Change_Frequently}));
Breakdown:
In this example, we bind the function to a scope object {variableAtTheTimeOfCreation: I_Like_to_Change_Frequently}.
When the handler executes, it's this will be the scope object we defined and bound to it (which was at creation).
More on Function.prototype.bind() on MDN

Whats going on in this bit of JS code?

I'm watching an Angular JS tutorial that keeps using variations of this code snippet without explaining it.
(function(param, undefined){
//Normal function definition in here
...
}(bar.foo = bar.foo || {}));
So I get most if this. I recognize the following a self-executing function used to encapsulate bits of javascript to avoid scope pollution.
(function(param, undefined){
//Normal function definition in here
...
});
But I don't understand the syntax of having parentheses after a function definition.
Edit
I understand what is going on inside the parentheses.
What I don't understand is the syntax of having parentheses after a function definition: function(...){...}(...);
It is a self-executing function that expects parameters. bar.foo is the parameter that is sent to it (will be param in use of the function).
If bar.foo does not have a value prior to the execution of the function, it is set to {}, otherwise, it is set to itself, and then it is passed in.
(function(param1, param2, param3) {
var ele = document.getElementById("result");
ele.innerHTML += "param1: " + param1;
ele.innerHTML += "<br />";
ele.innerHTML += "param2: " + param2;
ele.innerHTML += "<br />";
ele.innerHTML += "param3: " + param3;
ele.innerHTML += "<br />";
param3 = param3 || "bananas";
ele.innerHTML += "param3 after change: " + param3;
})("apples", "oranges");
<div id="result"></div>
The function is being triggered with (bar.foo = bar.foo || {}) as the argument. If bar.foo exists, then the function will take bar.foo as the argument. If it is undefined (which is falsey), then it will take in {} as the argument. I hope this helps!
Placing parentheses after the function declaration initiates a call to it immediately. It's the same as doing this:
var fn = function () { ... };
fn();
Because the return value of a function declaration is the function object, and when you apply parentheses to a function object, you call it. And, as always, the stuff inside those parentheses are the parameters to the function.
If bar.foo is defined, use that -- but if it isnt, use this empty object ({})
Edit - to fit new clarification
Its placement means that before executing the function, it will handle the bar.foo assignment; like setting a default.

Javascript bind to object

function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
var func = john.says;
func();
I tried this example when I do this I get the following message undefined rocks! instead of Ruby rocks!.
can u explain why is that.
Function Execution Context and the this Keyword
JavaScript functions have an execution context at invocation time such that the this keyword is bound to the object they are invoked from. If you call john.says() the execution context of the function would have a this keyword that points to john. If you instead assign a global variable func to the method says found on the object john you have changed the execution context to the global object. When you invoke the func function, this dereferences to window (or undefined*) and since window.skill is undefined, says will coerce that value into a string to concatenate it with the string ' rocks!'.
How to guarantee execution context using bind
You can instead bind a copy of the function to an object (effectively locking it's context reference):
var func = john.says.bind(john);
How to guarantee execution context using a closure
Alternately you can close over the relevant bits by using a closure in your constructor:
function Developer(skill){
var _this = this; // we keep a reference here
this.skill = skill;
this.says = function(){
alert(_this.skill + ' rocks!');
// when invoked _this refers to the context at construction
}
return this;
}
How to guarantee a value using a closure
You could just reference the skill value directly from the method and so not need the context at all:
function Developer(skill){
// because skill is defined in this context, says will refer to this context
// to get the value of the skill variable.
this.says = function(){
alert(skill + ' rocks!');
}
}
How to guarantee an execution context at invocation time using call and apply
The final options are to to invoke the method with the context you want at invocation time:
func.call(john /*, optional arguments... */);
func.apply(john /*, optional arguments as an array */);
How to use prototypes to allow the dynamic execution context to set the right this
If we want to reuse a method between object instances or types but have the right execution context when invoked we can use the prototype property.
function Developer(skill){
this.skill = skill;
this.says();
}
Developer.prototype.says = function(){
alert(this.skill + ' rocks!');
}
var john = new Developer("Ruby"); // alert("Ruby rocks!")
var tony = new Developer("JavaScript"); // alert("JavaScript rocks!")
More reading:
Specification for execution contexts: http://ecma-international.org/ecma-262/5.1/#sec-10.3
MDN Docs about this: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FOperators%2Fthis
* "use strict" activates a special strict mode representing the future of JavaScript. This special strict executing environment will not resolve to the global object when a context has not been set, instead resolving this to the appropriately scoped value undefined.
Let's illustrate what is happening, by actually returning the object:
function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
return this; //this is basically { skill: skill, says: function() {} }
}
var john = new Developer('Ruby');
var func = john.says; // all it knows is the function() part, has no knowledge of skill
func(); //undefined rocks!
Ok, so why are we getting undefined? Well, once we rip out the function, it no longer has context - it doesn't know what this is. If we were to do:
func.apply(john);
Then we are passing in John as the this parameter. A workaround, it to pass the value in to the function when we create it:
function Developer(skill) {
this.skill = skill;
this.says = function(skill) { //<--calling this function
return function() { //<--returning this function
alert(skill + ' rocks!');
};
}(this.skill); //<--passing in the value here
return this;
}
When you call a function, this will refer to the object on which the function was called.
When you say
var func = john.says;
you are just getting the function object (it doesn't remember the object on which it is defined).
When you invoke the function, like this
func();
there is no current object, on which func is invoked. So, by default, JavaScript assigns the global object(window object in browser) as this. Since, skill is not defined in the global object, undefined is returned.
Note: In Strict mode, this will be undefined, if there is no current object.
That is why we have to explicitly bind the object to the function, like this
func.bind(john)();
Function.prototype.bind will return a new function, which is bound to john. So, when you invoke this this will refer john.
Because func() only has the function and not any other related info.(this.skill)
The context is lost. this referred to the john when the says() is called.
But now, when you call func() this refers to the window. Therefore this.skills will return undefined unless you have a global variable of the same name.
the fastest way to keep the above pattern is to bind this direct to the method this.says = function () { ... }.bind(this);:
function Developer(skill) {
this.skill = skill;
this.says = function () {
alert(this.skill + ' rocks!');
}.bind(this);
}
var john = new Developer('Ruby');
var func = john.says;
func(); // Ruby rocks!
try this
function Developer(skill) {
this.skill = skill;
this.says = function() {
alert(this.skill + ' rocks!');
}
}
var john = new Developer('Ruby');
john.says();
working demo
http://jsfiddle.net/ZENtL/

Javascript calling function inside function

I am trying to get the function in a function with argument inside the child function
function firstF (){
this.childF1 = function($argument){
// do something + $argument
}
this.childF2 = function($argument2){
// do something + $argument2
}
}
//Declare a new firstF
var firstFunction = new firstF();
firstFunction.childF1
how do i declare the $argument here?
You do it like this:
var firstFunction = new firstF();
firstFunction.childF1(arghere)
childF1 is a property of your firstF object and that property is a function. So, you call it like a function with parens and you pass the arguments in the parens. You must call it on an already created object of type firstF, not on the firstF function itself.

Categories