I'm currently working on some exercises to get a deeper understanding of the 'this' keyword. It does seem to have a lot of use cases so I did read on MDN about 'this'. I'm wondering, what does the 'this' keyword in this exercise refer to? I know that when you use apply (which has a maximum of 2 arguments), your first argument is where you want the this 'keyword to be referenced to' and the second argument is an array to which the 'this' keyword is newly referenced to. where is return fn.apply(this,arguments); being referenced to and what is arguments in the second argument? Is it in the function, the window? Sorry, I'm just really confused and trying to wrap my head around it. This is the line of code that I'm confused about:
function add(a, b) {
return a + b;
}
function invokeMax(fn, num) {
var counter = 0;
return function() {
counter++;
if (counter > num) {
return 'Maxed Out!';
}
return fn.apply(this, arguments);
};
}
You can console.log() this in the returned function and find out. Here, you will see it points to the global object (or window in a browser). This code doesn't depend on this being anything in particular. You could rewrite it as:
return fn.apply(null, arguments);
and get the same result.
this is determined by the way functions are called. The function here returns a function that (presumably) you will just call by itself, so the only calling's context is the window:
function add(a, b) {
return a + b;
}
function invokeMax(fn, num) {
var counter = 0;
return function() {
counter++;
if (counter > num) {
return 'Maxed Out!';
}
console.log("this is window?", this === window)
return fn.apply(this, arguments);
};
}
let f = invokeMax(add, 2)
console.log(f(5, 6))
Calling the same function in a different context leads to a different value of this:
function add(a, b) {
return a + b;
}
function invokeMax(fn, num) {
var counter = 0;
return function() {
counter++;
if (counter > num) {
return 'Maxed Out!';
}
console.log("this: ", this)
return fn.apply(this, arguments);
};
}
let someObj = {name: "myObj"}
someObj.f = invokeMax(add, 2) // now this will be someObj
someObj.f()
EDIT based on comment
A basic apply() example. The function will use the object passed to the first parameter of apply() as this in the function:
function print(someArg){
console.log(this.myName, someArg)
}
print.apply({myName: "Mark"}, ["hello"]) // set this to the passed in object
print.apply({myName: "Teddy"}, ["hello"]) // set this to the passed in object
print("hello") // called normally `this` will be the widow which doesn't have a `myName` prop.
// but you can give window that property (but probably shouldn't)
window.myName = "I'm window"
print("hello")
In that instance this refers to the current scope, which is the function where this is contained. In JavaScript, functions are also objects that can have properties assigned to them.
Related
Is it possible inside list to get all available functions - a, b, c without their enumeration and without using window?
(function(){
function a() { return 1; }
function b() { return 2; }
function c() { return 3; }
function list()
{
return [a, b, c];
}
})();
No, it's not possible with functions declared directly in the current scope.
To achieve this, you would have to assign the functions to some property of the scope, i.e.:
(function() {
let funcs = {};
funcs.a = function() {
return 1;
}
...
function list() {
return Object.values(funcs);
}
});
NB: Object.values is ES7, in ES6 use:
return Object.keys(funcs).map(k => funcs[k]);
or in ES2015 or earlier use:
return Object.keys(funcs).map(function(k) { return funcs[k] });
If you haven't even got Object.keys, give up... ;)
I understand where you are trying to get. So perhaps this is the closest thing to what you requested, without using the window name (the same object though):
// define a non-anonymous function in the global scope
// this function contains all the functions you need to enumerate
function non_anon() {
function a() { return 1; }
function b() { return 2; }
function c() { return 3; }
function list() { return [a, b, c]; }
// you need to return your `list` function
// i.e. the one that aggregates all the functions in this scope
return list;
}
// since in here the purpose is to access the global object,
// instead of using the `window` name, you may use `this`
for (var gobj in this) {
// from the global scope print only the objects that matter to you
switch (gobj) {
case 'non_anon':
console.info(gobj, typeof this.gobj);
console.log(
// since you need to execute the function you just found
// together with the function returned by its scope (in order to `list`)
// concatenate its name to a double pair of `()` and...
eval(gobj + '()()') // evil wins
);
break;
}
}
I recently came across this pattern in the source for https://github.com/yeoman/generator-webapp:
AppGenerator.prototype.packageJSON = function packageJSON() {
this.template('_package.json', 'package.json');
};
What's the purpose of giving the function the name "packageJSON" when you're going to assign it to a variable or object property anyways? I've always used anonymous functions in similar cases.
For debugging purposes. If you use a named function you can see that name in the call stack trace in your favorite dev tools. Otherwise you'd see anonymous function.
That's called a named function expression (or NFE) and it makes the debugging process much easier.
An important detail to remember is that this name is only available in
the scope of a newly-defined function; specs mandate that an
identifier should not be available to an enclosing scope:
var f = function foo(){
return typeof foo; // "foo" is available in this inner scope
};
// `foo` is never visible "outside"
typeof foo; // "undefined"
f(); // "function"
As others says, for debugging purposes mainly. But not only that. For instance, you can rely on the fact that in function's body, you can access to the function itself using the name you set. To give a silly example:
var sum = function (a, b) {
if (a < 3)
return sum(3 + a, b);
return a + b;
}
sum(1, 2) // 3;
But let's see what happens now:
var aSum = sum;
sum = null;
aSum(1, 3); // TypeError: sum is not a function
Naming the function, will cover that use case:
var sum = function sum(a, b) {
if (a < 3)
return sum(3 + a, b);
return a + b;
}
sum(1, 2) // 6
var aSum = sum;
sum = null;
aSum(1, 2) // 6
That's because in the body of the function, the name of the function is always referring to it, and is not taken from another scope, like the first example.
Is there any way to share code between two closures?
Example:
// ANTIPATTERN
var cbDoThing = function cbDoThing(arg){
return typeof closed1 +" " + arg;
}
function getClosure1(closed1) {
return cbDoThing;
}
function getClosure2(closed1) {
return function(arg) {
// do other work
return cbDoThing(arg);
}
}
f1 = getClosure1();
f1("ARG1"); // returns "undefined ARG1"
f2 = getClosure2();
f2("ARG2"); // returns "undefined ARG2"
Here getClosure1() and getClosure2() return a closure that does similar tasks. I.e. both of them need to execute the cbDoThing() within a closure environment, but getClosure2() runs some other code in addition.
The above example does not work as wanted. cbDoThing() is defined in the global context, so closed1 variable is undefined. The wanted behavior is a pattern to make the closed1 variable be read from the closure scope chain, but without redefining the cbDoThing()function in each closure.
PS: JsFiddle playground.
EDIT:
Now that I asked, an answer came to me with minor modifications:
var cbDoThing = function cbDoThing(closed1, arg){
return closed1 +" " + arg;
}
function getClosure1(closed1) {
return function(arg) {
return cbDoThing(closed1, arg);
}
}
function getClosure2(closed1) {
return function(arg) {
// do other work
return cbDoThing(closed1, arg);
}
}
The cbDoThing does not access closed1 variable from the closure variable scope. Rather it is passed an extra argument. Then this function is called from each of the closures.
JsFiddle
Nice work. Javascript only walks down the prototypal chain, which means that cbDoThing has no reference or declaration of closed1. In this case, cbDoThing has only one prototype - Object. Without explicitly passing an argument to cbDoThing, it will not have any notion of the closed1.
Here is a thorough discussion of closures in javascript: http://jibbering.com/faq/notes/closures/
I want to pass a function reference "go" into another function "redefineFunction", and redefine "go" inside of "redefineFunction". According to Johnathan Snook, functions are passed by reference, so I don't understand why go() does not get redefined when I pass it into redefineFunction(). Is there something that I am missing?
// redefineFunction() will take a function reference and
// reassign it to a new function
function redefineFunction(fn) {
fn = function(x) { return x * 3; };
}
// initial version of go()
function go(x) {
return x;
}
go(5); // returns 5
// redefine go()
go = function(x) {
return x * 2;
}
go(5); // returns 10
// redefine go() using redefineFunction()
redefineFunction(go);
go(5); // still returns 10, I want it to return 15
Or see my fiddle http://jsfiddle.net/q9Kft/
Pedants will tell you that JavaScript is pure pass-by-value, but I think that only clouds the issue since the value passed (when passing objects) is a reference to that object. Thus, when you modify an object's properties, you're modifying the original object, but if you replace the variable altogether, you're essentially giving up your reference to the original object.
If you're trying to redefine a function in the global scope: (which is a bad thing; you generally shouldn't have global functions)
function redefineFunction(fn) {
window[fn] = function() { ... };
}
redefineFunction('go');
Otherwise, you'll have to return the new function and assign on the calling side.
function makeNewFunction() {
return function() { ... };
}
go = makeNewFunction();
Nothing is "passed by reference" in JS. There are times that references are passed, but they're passed by value. The difference is subtle, but important -- for one thing, it means that while you can manipulate a referenced object pretty much at will, you can't reliably replace the object (read: alter the reference itself) in any way the caller will see (because the reference was passed by value, and is thus merely a copy of the original reference; attempting to reassign it breaks in the same way it would if the arg were a number or string).
Some cowboys will assume you're redefining a global function and mess with it by name to get around the limitations of pass-by-value, but that will cause issues the second you decide not to have globals all over the place.
The real solution: return the new function, and let the caller decide what to do with it. (I'd argue that redefining functions right out from under the code that uses them is a pretty bad design decision anyway, but eh. I guess there could be a reason for it...)
Snook is wrong. And I don't think it's pedantic at all (#josh3736 :) to point out that EVERYTHING in JavaScript is pass by value. The article by Snook gets this COMPLETELY wrong. Passing a primitive and passing an object work the exact same way. These are equivalent:
var x = 2;
var y = x;
y = 3; //x is STILL 2.
function stuff(y){
y = 3; //guess what. x is STILL 2
}
stuff(x);
///////////////////
var x = {stuff: 2};
var y = x;
y = {stuff: 3}; //x.stuff is STILL 2
function stuff(y){
y = {stuff: 3}; //guess what. x.stuff is STILL 2
}
stuff(x);
This is important. Java, C#, and MOST languages work this way. That's why C# has a "ref" keyword for when you really do want to pass something by reference.
You can't modify the variable from inside the function, so the quick fix is to return the value and assign it outside the function, like this
// log() just writes a message to the text area
function log(message) {
$('#output').val($('#output').val() + message + "\n");
}
// redefineFunction() will take a function reference and
// reassign it to a new function
function redefineFunction() {
newvalue = function(x) { return x * 3; };
return newvalue;
}
// initial version of go()
function go(x) {
return x;
}
log(go(5)); // returns 5
// redefine go()
go = function(x) {
return x * 2;
}
log(go(5)); // returns 10
// redefine go() using redefineFunction()
go = redefineFunction();
log(go(5)); // returns 10, I want it to return 15
I believe functions are 'passed in by value'. If you put log(f(5)); inside your redefineFunction function it will output 15, but 10 when you call log(go(5)) afterwards.
If you change redefineFunction to return the function and then assign it to go (go = redefineFunction()) it will work as you expect.
This is equivalent to asking if you can redefine any variable by passing it as an argument to some function. No. You can reassign it by, uhh, reassigning it. In this case, if you make redefineFunction return a function, you can simply assign it to go:
function redefineFunction() {
var fn = function(x) { return x * e; };
return fn;
}
function go(x) {
return x;
}
go = redefineFunction();
go(5); // return 15
This is working in firefox:
function redefineFunction(fn) {
window[fn] = function(x) {
return x * 3;
}
};
function go(x) {
return x;
};
alert(go(5));
go=function(x) {
return x * 2;
}
alert(go(5));
redefineFunction('go');
alert(go(5));
The secret is that a global function called go also is called window.go and window["go"].
This can also be used at styles: element.style["overflow"] = "hidden", and in attributes:
element["value"] = "hello there".
This is a very useful knowlege.
Why dont use a object? something like this:
var o = {
go: function( x ) {
return x;
},
redefineFunction: function ( fn ) {
if (typeof fn === 'function') {
this.go = fn;
}
}
}
console.log(o.go(5)); // return 5
var fn = function (x) {
return x * 2;
};
o.redefineFunction(fn);
console.log(o.go(5)); //return 10
Hope it helps!
I understand calling function(1) but not function(1)(2), how does it work?
also possible for function(1)(2)(3)(4) too?
In this case you are supposing that function(1) returns a function, than you are calling this new, anonymous function with an argument of 2.
See this example:
function sum(a) {
return function(b) {
return a+b;
}
}
// Usage:
window.alert(sum(5)(3)); // shows 8
var add2 = sum(2);
window.alert(add2(5)); // shows 7
window.alert(typeof(add2)); // shows 'function'
Here we create a function sum that takes one argument. Inside the function sum, we create an anonymous function that takes another argument. This anonymous function is returned as the result of executing sum.
Note that this anonymous function is a great example of what we call closure. A closure is a function that keeps the context in which it was created. In this case, it will keep the value of the variable a inside it, as did the example function add2. If we create many closures, they are independent as you can see:
var add3 = sum(3);
var add4 = sum(4);
window.alert(add3(3)); // shows 6
window.alert(add4(3)); // shows 7
Furthermore, they won't get "confused" if you have similarly named local variables:
var a = "Hello, world";
function multiply(a) {
return function(b) {
return a * b;
}
}
window.alert(multiply(6)(7)); // shows 42
var twoTimes = multiply(2);
window.alert(typeof(twoTimes));
window.alert(twoTimes(5));
So, after a call to sum(2) or multiply(2) the result is not a number, nor a string, but is a function. This is a characteristic of functional languages -- languages in which functions can be passed as parameters and returned as results of other functions.
You have a function that returns a function:
function f(n) {
return function(x) {
return n + x;
};
}
When you call f(1) you get a reference to a function back. You can either store the reference in a variable and call it:
var fx = f(1);
var result = fx(2);
Or you can call it directly:
var result = f(1)(2);
To get a function that returns a function that returns a function that returns a function, you just have to repeat the process:
function f(n) {
return function(x) {
return function(y) {
return function(z) {
return n + x + y + z;
}
}
};
}
If your function returns a function, you can call that too.
x = f(1)(2)
is equivalent to:
f2 = f(1)
x = f2(2)
The parenthesis indicate invocation of a function (you "call" it). If you have
<anything>()
It means that the value of anything is a callable value. Imagine the following function:
function add(n1) {
return function add_second(n2) {
return n1+n2
}
}
You can then invoke it as add(1)(2) which would equal 3. You can naturally extend this as much as you want.