I found an example of the expansion of the built-in javascript
var n = 3;
Number.prototype.times = function(f, context) {
var n = Number(this);
for (var i = 0; i < n; i++) {
f.call(context, i);
}
};
n.times(function(n) {
console.log(n);
});
I understand that I call the function f (console.log) through the object context.
I understand that we pass this function a serial number from 0 to n.
The method time accepts only one argument - function console.log
Question: Where in the code appeared object context?
Thank you all
A function allows any number of parameters to be supplied. If there's too many, they're not used and if there's too few, the ones that are left out are undefined. n.times(myFunction) is the same as n.times(myFunction, undefined), but just shorter to write.
The context is actually not correctly named, scope would be better. When omitted, the global scope is used. The following is the same:
n.times(myFunction.bind(scope));
n.times(myFunction, scope);
More about scopes and binding:http://www.reactive.io/tips/2009/04/28/binding-scope-in-javascript/
Now all is clear, it was a difficult example.
To understand so much clearer:
var n = 3;
Number.prototype.times = function(f) {
var n = Number(this);
for (var i = 0; i < n; i++) f(i);
};
Related
While learning about javascript closures, I came across this answer https://stackoverflow.com/a/111111/3886155 on stackoverflow.
It's a very good explanation of closures.
But I have some confusion in Example 4 and Example 5.
I just copy entire snippet here:
Example 4:
var gLogNumber, gIncreaseNumber, gSetNumber;
function setupSomeGlobals() {
// Local variable that ends up within closure
var num = 666;
// Store some references to functions as global variables
gLogNumber = function() { console.log(num); }
gIncreaseNumber = function() { num++; }
gSetNumber = function(x) { num = x; }
}
setupSomeGlobals();
gIncreaseNumber();
gLogNumber(); // 667
gSetNumber(5);
gLogNumber(); // 5
var oldLog = gLogNumber;
setupSomeGlobals();
gLogNumber(); // 666
oldLog() // 5
After reading some examples I can say that whenever function inside the function executes it can always remember the variables declared inside outer function.
I agree that if these closure variable updated anyway it still refers to the new variable value.
My problem in this example is specially related to var oldLog=gLogNumber;
How it can return old number after call to the setupSomeGlobals();?
because now the var num has reset.So why it is not using this new num value 666?
Now Example 5:
function buildList(list) {
var result = [];
for (var i = 0; i < list.length; i++) {
var item = 'item' + i;
result.push( function() {console.log(item + ' ' + list[i])} );
}
return result;
}
function testList() {
var fnlist = buildList([1,2,3]);
// Using j only to help prevent confusion -- could use i.
for (var j = 0; j < fnlist.length; j++) {
fnlist[j]();
}
}
Here they have pushed functions into array and executed them after loop finishes.But now reference to the closure variables is the latest one after loop finishes.Why not old one?
In both examples you are just assigning function definition to variable or array index.But first one points to old and second one points to latest.Why?
How it can return old number after call to the setupSomeGlobals()
num is not globally scoped, so the value num is in the context of which reference of gLogNumber is invoked.
After invocation of setupSomeGlobals method again, reference to gLogNumber got changed. try this
console.log(Object.is( gLogNumber, oldLog )); //true
setupSomeGlobals();
console.log(Object.is( gLogNumber, oldLog )); //false
So, oldLog retained old reference and hence old value of num, but gLogNumber got new num.
But now reference to the closure variables is the latest one after
loop finishes.Why not old one?
For this problem, have a look at
JavaScript closure inside loops – simple practical example.
This uses var
var a = [];
for (var i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
a[6](); // 10
This uses let
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = function() {
console.log(i);
};
}
a[6](); // 6
I don't understand why the result is different. Can somebody guide me?
The resulting array consists of functions, each function body looks like this:
console.log(i);
The value of i depends on whether we used var or let to declare the variable.
var (ECMAScript 5 and 6)
Here i is a global variable whose value is 10 after exiting the loop. This is the value that is logged.
let (ECMAScript 6)
Here i is a local variable whose scope is restricted to the for statement. Moreover, this variable gets a fresh binding on each iteration. This is best explained by your code transpiled to ECMAScript 5:
"use strict";
var a = [];
var _loop = function(i) {
a[i] = function() {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
a[6](); // 6
So, on seventh iteration for example, the value of i will be 6 (counting from zero). The function created inside the iteration will refer to this value.
I think it would be much better to not define functions in a loop, you could easily accomplish this with one function definition that returns a closure:
function logNumber(num) {
return function() {
console.log(num);
}
}
var a = [];
for (let i = 0; i < 10; i++) {
a[i] = logNumber(i);
}
a[6]();
Regarding the difference between the two examples, one is using let for block scoping. A better example that shows the difference would be:
ECMA5:
for (var i = 0; i < 10; i++) { }
console.log(i); // 10
ECMA6:
for (let i = 0; i < 10; i++) { }
console.log(i); // i is not defined
Edit: as I stated in my comment to your question, this is more likely a side-effect of the transpiler you are using. Firefox supports block scoping and both versions of your loop produce 10 as output (which they should).
This is correct behavior according to the spec. The behavior with var and let is defined to be different.
See the spec, at https://people.mozilla.org/~jorendorff/es6-draft.html#sec-forbodyevaluation. According to this, the relevant concepts, which make the function declared inside the loop close over the current value of the block-scoped loop index, are things called "per-iteration bindings" and "per-iteration environment".
Babel handles it correctly, producing the following code:
var a = [];
var _loop = function (i) {
a[i] = function () {
console.log(i);
};
};
for (var i = 0; i < 10; i++) {
_loop(i);
}
This implements the semantics of for (let by isolating the contents of the for loop into a separate function parameterized by the index. By virtue of doing that, the function no longer closes over the for loop index, and i is treated separately in each function created. Thus the answer is 6.
Traceur does not produce the correct result. It yields 10.
So the famous question that has been asked 100 times on SO, about why my function declared in a loop and closing over the index index is using the "wrong" value of the loop index, shall be asked no more?
The issue is a bit more nuanced that merely proclaiming that "of course, let is block-scoped". We know that. We get how it works in an if block, for example. But what's going on here is a bit of an twist on block scoping in the context of a for, hitherto unknown to many people including me. It's a variable actually declared outside the "block" (if you think of the block as the body of the for statement) but has a separate existence inside each iteration of the loop.
For more, see https://github.com/babel/babel/issues/1078.
Why is result different in ES6 and ES5?
Because let and var are different. let is block-scoped while var is function-scoped.
In your first example there is only a single variable i. Every function you create has a reference to the same variable i. At the moment you call a[6](), i has the value 10, because that was the termination condition for the loop.
In the second example, every iteration of the loop has it's own variable i. It works exactly like in other languages with block scope.
I wanted to do a partial_left function that will be executed into an array, something liek that:
array_1.map(partial_left1(equal));
function equal(x){return x;}
, but I crushed when I pushed the variables of arguments into an other array(and not with the Array.prototype.slice.call(arguments)). Because I wanna do other way, But I surprised when the result were differents:
var array_1=[1,2,3];
with my method: th result is : [1,1,1]//doing reference only to the array[0]
with Array,prototype.slice.call: [1,2,3]//how I would want to be
this is my code, where I push the values of arguments in another array:
function concat(arg1,arg2,n){
for (var i = n; i < arg2.length; i++)
arg1.push(arg2[i]);
return arg1;
}
function partial_left1(f){
var argum_apply=[];
argum_apply=concat(argum_apply,arguments,1);
return function(){
argum_apply=concat(argum_apply,arguments,0);
return f.apply(this,argum_apply);
};
}
And this is the code with Array.prototype.slice.call:
function array(a, n) { return Array.prototype.slice.call(a, n || 0); }
function partial_left2(f /*, ...*/) {
var args = arguments;
return function() {
var a = array(args, 1);
a = a.concat(array(arguments));
return f.apply(this, a);
};
}
A simple definition of equal with partial:
var equal_left1=partial_left1(equal);
var equal_left2=partial_left2(equal);
Here are the results, and I don't know why they are differents?
var array_1=[1,2,3];
alert(array_1.map(equal_left1));//1,1,1
alert(array_1.map(equal_left2));//1,2,3
Someones who knows please explain me what are the differences between "Concat" and use "Array.prototype.slice.call"?
One of the bad design decisions: arguments is not an array. It is array-like, in the sense it has a length property.
You can't call the concat method of arguments because it doesn't exist.
Array.prototype.slice.call uses the slice method from the arrays and invokes it -- it is a quick and easy way to turn something array-like to a proper array.
You can do the same thing with a loop, if you want:
var arr = [];
for (var i = 0; i < arguments.length; i++) {
arr[i] = arguments[i];
}
How to create method twice? I can't understand how to change this in body of function. Why it doesn't work?
function twice() {
var buf = [];
for ( var i = 0; i < this.length; i++ ) {
buf.push(this[i]);
}
for ( var i = 0; i < this.length; i++ ) {
buf.push(this[i]);
}
this = buf;
}
Array.prototype.twice = twice;
a = [1,2,3];
a.twice();
a; // [1,2,3,1,2,3]
I can't understand how to change this in body of function
If you mean the value of this, you can't. But you don't have to for what you're doing
You're very close, you just have a fair bit to remove:
function twice() {
var i, l;
for (l = this.length, i = 0; i < l; ++i) {
this.push(this[i]);
}
}
Remember, your array is an object. To change its contents, you just change its contents, you don't have to change the reference to it.
Note, though, that you can use this trick on any modern browser:
function twice() {
this.push.apply(this, this);
}
That works by using the Function#apply function, which calls the function you call it on (so, push in our case) using the first argument you give it as the object to operate on, and the second argument as the arguments to pass into that function (which it takes as an array). More on MDN and in the spec. It happens that push allows you to pass it an arbitrary number of arguments, and will push each one in order. So if you're trying to add the contents of the array to the array a second time, that one line will do it (on modern browsers, some older IE implementations don't like this use of push.apply).
You cannot assign a value to this. That's the rules. But you can modify the value of this. Try pushing some values into this.
function twice() {
var len = this.length;
for (var i = 0; i < len; i++) {
this.push(this[i]);
}
}
Array.prototype.twice = twice;
a = [1, 2, 3];
a.twice();
alert(a);
Here's a fiddle. http://jsfiddle.net/Qvarj/ As you can see, most of the logic is yours.
I want to create a function in javascript with a variable amount of arguments. The next example is how I want to call this function:
myFunction(1,2);
myFunction(1,2,3);
myFunction(1,2,3,4);
myFunction(1,2,3,4,5);
myFunction(1,2,3,4,5,6);
Anyone knows how to define this function?
You can access the arguments by their ordinal position without the need to state them in the prototype as follows:
function myFunction() {
for (var i = 0; i < arguments.length; i++)
alert(arguments[i]);
}
myFunction(1, 2, "three");
>>1
>>2
>>three
Or if you really are passing in a set of semantically related numbers you could use an array;
function myFunction(arr) { ... }
result = myFunction([1,2,3]);
Latest update
Rest parameters are supported in all new browsers.
Check here for details
The rest parameter syntax allows us to represent an indefinite number of arguments as an array, which you can pass it to other functions too.
function myFunction(...data){
console.log(...data);
myOtherFunction(...data);
}
myFunction(1,2,3); //logs 1,2,3
myFunction([1,2,3]); //logs [1,2,3]
Use the 'arguments' variable like this :
function myFunction() {
alert(arguments.length + ' arguments');
for( var i = 0; i < arguments.length; i++ ) {
alert(arguments[i]);
}
}
Call the methods as you did before
myFunction(1,2);
myFunction(1,2,3,4,5,6);
Just refer to the arguments array.
https://developer.mozilla.org/en/JavaScript/Reference/functions_and_function_scope/arguments
If an argument is not present, use the default. Like this...
function accident() {
//Mandatory Arguments
var driver = arguments[0];
var condition = arguments[1]
//Optional Arguments
var blame_on = (arguments[2]) ? arguments[2] : "Irresponsible tree" ;
}
accident("Me","Drunk");
As an add-on: You can assign values to the unnamed function parameters, as in (german wiki)
arguments[0] = 5;