This is the code :
i'm storing the function body inside each element of "resultArr"
, the problem is when i call the stored function _class[0]()i can't reach the exact i it's always 4 !
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push(function(){console.log('Is', nameArr[i], 'present?', i);});
}
return resultArrultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
i think it's obvious if i call any item of _class i.e _class[0]() the index will be 4 and the name will be "undefined"
So how wan i solve this problem, i saw some ppl use the apply native function, but i think it works only if we store the function name not the body of a given function
In this case, all the closures inside checkAttendanceFunc point to a reference of the i and nameArr variable.
When the loop is done, i's value is 4 for all the functions you generated, what you need is copying i each time you pass it to a closure.
There are several ways for you to achieve this:
Immediately call the function
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push(function(index){
return function(){
console.log('Is', nameArr[index], 'present?', index);
}
}(i));
}
return resultArr;
};
Here you're passing an argument fo the closure and you call it immediately. In this case, i is getting copied and the function has its own value named index.
Use another function that iterates on the array
In this case I'm using Array.forEach
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
nameArr.forEach(function (value, index){
resultArr.push(function() {
console.log('Is', value, 'present?', index);
});
});
return resultArr;
};
In this case the functions created recieve a copy of value and index, which means they will always point to the same values.
Still not sure I understand the intent of this code, but here's a working version that does what I think you're trying to do:
var students = ["alex", "brownex", "chris", "mack"];
var _class = students.map(function(name, i) {
return function() {
console.log('Is', name, 'present?', i);
};
});
See it in action here.
If you're really just looking for how to make it work with a for-loop, you could always capture it like this:
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push((function(idx) {
return function() {
console.log('Is', nameArr[idx], 'present?', idx);
};
})(i));
}
return resultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
Similarly, you can also use .bind():
var checkAttendanceFunc = function(nameArr) {
var resultArr = [];
for(var i = 0; i < nameArr.length; i++) {
resultArr.push((function(idx) {
console.log('Is', nameArr[idx], 'present?', idx);
}).bind(null, i));
}
return resultArr;
};
var _class = checkAttendanceFunc(["alex", "brownex", "chris", "mack"]);
Either way, I personally find the .map() solution much more elegant and readable.
I have an object which is initialized like
var x = function(){
var result = 5,
clear = function(){
result = 0;
};
return {
result: result,
clear: clear
}
}
I am later creating a new instance of x using var y = new x();
but when i try setting the value y.result = 5; and want to clear the result value to 0 I call y.clear();
However it is not resetting the y.result to 0... Not sure why?
Anything that i am doing wrong?
Within your function:
var x = function(){
var result = 5,
clear = function(){
result = 0;
The identifier result in this function has a closure to the variable result in the outer function (i.e. outer execution context).
};
return {
result: result,
That assigns the value of the variable named result to the object property named result.
clear: clear
}
}
So later when you call y.clear() you are setting the value of the variable held in the closure, which does not update the object property named result.
If you want x to be a constructor, then:
function X() {
this.result = 5;
this.clear = function() {
this.result = 0;
}
}
So now:
var y = new X();
y.clear();
console.log(y.result); // 0
Note that it is convention for constructors to have a name starting with a capital letter. You can learn more about how to use the new operator on MDN.
To leverage ECMAScript inheritance, put the clear function on the constructor's prototype so that all instances inherit the one method, rather than each having its own:
function X() {
this.result = 5;
}
X.prototype.clear = function() {
this.result = 0;
}
The problem is that numbers are referenced by value. Assigning value to result variable from clear function won't change value of result on new x instance.
There are several ways to go about this:
Store data on this, then modify it there inside constructor and method, I find it easier to understand and more readable. This is probably what you wanted to begin with:
function x () {
this.result = 5;
}
x.prototype.clear = function () {
this.result = 0;
}
var z = new x();
// z.result === 5
z.clear()
// z.result === 0;
Define getter and setter on returned object, so instance result would return\set closured variable:
function x () {
var result = 5;
function clear () {
result = 0;
}
var out = {
clear: clear
};
Object.defineProperty(out, "result", {
get: function () {
return result;
},
set: function (value) {
result = value;
}
});
return out;
}
var z = new x();
// z.result === 5
z.clear()
// z.result === 0;
z.result = 10
// z.result === 10;
z.clear()
// z.result === 0;
Variables created inside a function, cannot be accessed outside the function.
For example in:
function haha()
{
var a = 5;
}
a cannot be accessed outside haha().
And that is where a closure comes in handy:
function haha()
{
var a = 5;
return function hahainside(){ }
}
newfunction = hahainside();
Now, if I call newfunction(), it can access the "a" variable inside the haha().
Am I correct?
I am also wondering why:
<script>
function exclusive()
{
d = "Robert, Ryo, Yuri";
function returnfunction() { alert( d ); }
return returnfunction();
}
ryo = exclusive();
alert(7);
</script>
I am also just wondering why alert(7); does not display on my browser.
Here's what you need to know:
var a = 0;
function haha(){
a = 5; // when calling haha `a` is accessible to everything below where var is declared
return function(){
a = 10; // same as notes above
}
}
var newfunc = haha(); // `a` will become 5 where var is declared
newfunc(); // now `a` is 10 where var is declared
console.log(a); // works
Without having var a declared outside of haha:
function haha(){
var a = 5; // only available in `haha`
return function(){
a = 10; // nearly useless - only scoped to `haha`
}
}
var newfunc = haha(); // `a` will become 5 where var is declared
newfunc(); // now `a` is 10 where var is declared - can't access `a` where `newfunc` is called
console.log(a); // undefined
Maybe you want a Constructor:
function haha(arg){
var whatever = 'something'; // never accessible in a new instance from outside
this.a = arg;
this.hahaInside = function(val){
this.a = val;
}
}
var newfunc = new haha(20); // `newfunc.a` is now `20`
newfunc.a = 12; // `newfunc.a` is now `12`
newfunc.hahaInside(10); // newfunc.a is now 10
As an Object:
var haha = {
a: 5,
hahaInside: function(val){
this.a = val;
}
}
No private variables in an Object, and no Constructor arguments. You don't have to call a new instance as an Object, but you may want an new instance. To avoid writing the keyword this:
if(!Object.create){
Object.create = function(o){
function F(){}
F.prototype = o;
return new F;
}
}
var newfunc = Object.create(haha); // new 'newfunc` is a new instance of `haha`
Real use, no closure:
// assuming 3 radio buttons
var ary = ['a', 'b', 'c'], radioButtons = document.getElementsByName('radButs');
var resultVar = '';
for(var i=0,l=radioButtons.length; i<l; i++){
radioButtons[i].onclick = function(){
resultVar = ary[i];
}
}
// resultVar will always be `'c'` because by the time the click Event is called the loop has run all the through and the scope of `i` is global
A closure prevents a variable from being scoped higher. Global in this case:
// assuming 3 radio buttons
var ary = ['a', 'b', 'c'], radioButtons = document.getElementsByName('radButs');
var resultVar = '';
for(var i=0,l=radioButtons.length; i<l; i++){
(function(i){
radioButtons[i].onclick = function(){
resultVar = ary[i];
}
})(i);
}
// now `resultVar` will be `'a'`, `'b'`, or `'c'` respectively, depending on the radio button that you clicked because `i` becomes separately scoped at each step of the loop even by the time the click Event is called due to user action
You can also use use a closure to create a pseudo-static function like this:
var count = (function(){
var c = 0;
return function(){
return c++;
}
})();
Now every time you call count() it will do just that. The reason this works is because the self-executing function is invoked immediately, scoping var c within it, and returning an unexecuted function that increases c where it was last scoped.
Wrox Profesionnal Javascript p188
I don't understand this part at line 8 where the anonymous function already have an argument of num, but how can (i) is copied into the argument num. Normally a function would stop at the closing bracket }, adding (i) doesn't make sense for me.
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = function(num){
return function(){
return num;
};
}(i);
}
return result;
}
This is short hand for calling the function and passing it the parameter i. It's like doing this:
function createFunctions(){
var result = new Array();
for (var i=0; i < 10; i++){
result[i] = myFunction(i);
}
return result;
}
function myFunction(num){
return function(){
return num;
}
}
Thinking of myFunction as the anonymous function my help you understand what's going on, so instead of myFunction(i) you have function(num){...}(i);
It's a closure and a self executing function. i is being "saved" in the scope of the returned function.
var test = "ONE";
var scoped = function () {
alert(test);
}
var saved_scoped = (function (value) {
return function () {
alert(value);
}
})(test);
test = "NOT ONE!";
scoped(); // alerts NOT ONE!
saved_scoped(); // alerts ONE
So you execute the function with the (i) immediately. Then return a function with the i value saved.
I need to create a function with variable number of parameters using new Function() constructor. Something like this:
args = ['a', 'b'];
body = 'return(a + b);';
myFunc = new Function(args, body);
Is it possible to do it without eval()?
Thank you very much, guys! Actually, a+b was not my primary concern. I'm working on a code which would process and expand templates and I needed to pass unknown (and variable) number of arguments into the function so that they would be introduced as local variables.
For example, if a template contains:
<span> =a </span>
I need to output the value of parameter a. That is, if user declared expanding function as
var expand = tplCompile('template', a, b, c)
and then calls
expand(4, 2, 1)
I need to substitute =a with 4. And yes, I'm well aware than Function is similar to eval() and runs very slow but I don't have any other choice.
You can do this using apply():
args = ['a', 'b', 'return(a + b);'];
myFunc = Function.apply(null, args);
Without the new operator, Function gives exactly the same result. You can use array functions like push(), unshift() or splice() to modify the array before passing it to apply.
You can also just pass a comma-separated string of arguments to Function:
args = 'a, b';
body = 'return(a + b);';
myFunc = new Function(args, body);
On a side note, are you aware of the arguments object? It allows you to get all the arguments passed into a function using array-style bracket notation:
myFunc = function () {
var total = 0;
for (var i=0; i < arguments.length; i++)
total += arguments[i];
return total;
}
myFunc(a, b);
This would be more efficient than using the Function constructor, and is probably a much more appropriate method of achieving what you need.
#AndyE's answer is correct if the constructor doesn't care whether you use the new keyword or not. Some functions are not as forgiving.
If you find yourself in a scenario where you need to use the new keyword and you need to send a variable number of arguments to the function, you can use this
function Foo() {
this.numbers = [].slice.apply(arguments);
};
var args = [1,2,3,4,5]; // however many you want
var f = Object.create(Foo.prototype);
Foo.apply(f, args);
f.numbers; // [1,2,3,4,5]
f instanceof Foo; // true
f.constructor.name; // "Foo"
ES6 and beyond!
// yup, that easy
function Foo (...numbers) {
this.numbers = numbers
}
// use Reflect.construct to call Foo constructor
const f =
Reflect.construct (Foo, [1, 2, 3, 4, 5])
// everything else works
console.log (f.numbers) // [1,2,3,4,5]
console.log (f instanceof Foo) // true
console.log (f.constructor.name) // "Foo"
You can do this:
let args = '...args'
let body = 'let [a, b] = args;return a + b'
myFunc = new Function(args, body);
console.log(myFunc(1, 2)) //3
If you're just wanting a sum(...) function:
function sum(list) {
var total = 0, nums;
if (arguments.length === 1 && list instanceof Array) {
nums = list;
} else {
nums = arguments;
}
for (var i=0; i < nums.length; i++) {
total += nums[i];
}
return total;
}
Then,
sum() === 0;
sum(1) === 1;
sum([1, 2]) === 3;
sum(1, 2, 3) === 6;
sum([-17, 93, 2, -841]) === -763;
If you want more, could you please provide more detail? It's rather difficult to say how you can do something if you don't know what you're trying to do.
A new feature introduced in ES5 is the reduce method of arrays. You can use it to sum numbers, and it is possible to use the feature in older browsers with some compatibility code.
There's a few different ways you could write that.
// assign normally
var ab = ['a','b'].join('');
alert(ab);
// assign with anonymous self-evaluating function
var cd = (function(c) {return c.join("");})(['c','d']);
alert(cd);
// assign with function declaration
function efFunc(c){return c.join("");}
var efArray = ['e','f'];
var ef = efFunc(efArray);
alert(ef);
// assign with function by name
var doFunc = function(a,b) {return window[b](a);}
var ghArray = ['g','h'];
var ghFunc = function(c){return c.join("");}
var gh = doFunc(ghArray,'ghFunc');
alert(gh);
// assign with Class and lookup table
var Function_ = function(a,b) {
this.val = '';
this.body = b.substr(0,b.indexOf('('));
this.args = b.substr(b.indexOf('(')+1,b.lastIndexOf(')')-b.indexOf('(')-1);
switch (this.body) {
case "return":
switch (this.args) {
case "a + b": this.val = a.join(''); break;
}
break;
}
}
var args = ['i', 'j'];
var body = 'return(a + b);';
var ij = new Function_(args, body);
alert(ij.val);
Maybe you want an annoymous function to call an arbitary function.
// user string function
var userFunction = 'function x(...args) { return args.length}';
Wrap it
var annoyFn = Function('return function x(...args) { return args.length}')()
// now call it
annoyFn(args)
new Function(...)
Declaring function in this way causes
the function not to be compiled, and
is potentially slower than the other
ways of declaring functions.
Let is examine it with JSLitmus and run a small test script:
<script src="JSLitmus.js"></script>
<script>
JSLitmus.test("new Function ... ", function() {
return new Function("for(var i=0; i<100; i++) {}");
});
JSLitmus.test("function() ...", function() {
return (function() { for(var i=0; i<100; i++) {} });
});
</script>
What I did above is create a function expression and function constructor performing same operation. The result is as follows:
FireFox Performance Result
IE Performance Result
Based on facts I recommend to use function expression instead of function constructor
var a = function() {
var result = 0;
for(var index=0; index < arguments.length; index++) {
result += arguments[index];
}
return result;
}
alert(a(1,3));
function construct(){
this.subFunction=function(a,b){
...
}
}
var globalVar=new construct();
vs.
var globalVar=new function (){
this.subFunction=function(a,b){
...
}
}
I prefer the second version if there are sub functions.
the b.apply(null, arguments) does not work properly when b inherits a prototype, because 'new' being omitted, the base constructor is not invoked.
In this sample i used lodash:
function _evalExp(exp, scope) {
const k = [null].concat(_.keys(scope));
k.push('return '+exp);
const args = _.map(_.keys(scope), function(a) {return scope[a];});
const func = new (Function.prototype.bind.apply(Function, k));
return func.apply(func, args);
}
_evalExp('a+b+c', {a:10, b:20, c:30});