I recently watched a video where the teacher demonstrated that the javascript code
alert.call.apply(function(a) {return a}, [1,2])
results always in "2". So here is my question: Why??
I could not find any explination why this result is returned.
This code is just too clever!
But wait, the following code will produce the same result:
console.log.call.apply(function(a) {return a}, [1,2])
Here is what's happening: apply()'s first parameter is a 'this', the second is a list of argument. It then calls the function console.log.call with those parameters, which logically is equivalent to:
(function(a) {return a}).call(1,2)
This code produces the same result and is a little bit easier to understand - we are using call() on the unnamed function. call()'s parameters are a 'this' object followed by arguments. In this case 'this' is 1, and the argument is 2, so the function gets called with a assigned to 2 (the 1 is not used in the function which is unbound). So this will always return 2, since it is simply returning the second item in the list.
But what is the role of alert, and why can we substitute any function name there? Well, it seems that there is a single call() function that is shared between all prototypes. You can verify that hypothesis by running
alert.call === console.log.call
true
So it doesn't matter if we use alert, console.log, or nothing, we are always using the same call() function.
Related
I am new learning the fundamentals. I have looked at many questions on here and youtube, and even on my udemy lecture. But none answer my question.
To be clear, my question is NOT how to use the return operator. I can use it perfectly well. The question is more to do with HOW it works, and what is actually happening in detail.
And please don't say "So in short, when we return something from a function, we are actually returning it from a function." - because this was one of the explainations I got before, and it does not explain anything to me hahaha :)
Here is the example code for this question:
function example(digit1, digit2) {
const sum = digit1 + digit2;
return `${sum}`
}
const invoke = example(1, 2);
console.log(invoke);
I think the best way to answer this question is to give me a step by step list of the journey that 'sum' makes. From the moment it is written, to the end of the whole code.
The return operator is clearly moving 'sum', as the word 'return' can only mean this, by definition.
When I read this code I see that 'sum' is inside the curly braces off the function, and then directly after this 'sum' is then RETURNED (to the place which it started). Now as 'sum' has not gone anywhere, returning it (to the place which it started) is REDUNDANT.
when the function is invoked there must be some kind of journey happening which I do not understand.
Thank you for your time :)
When I read this code I see that 'sum' is inside the curly braces off the function, and then directly after this 'sum' is then RETURNED (to the place which it started). Now as 'sum' has not gone anywhere, returning it (to the place which it started) is REDUNDANT.
Nope. You're misinterpreting what's "returning" and where it's being returned to.
The function is returning the value contained in sum to whatever called the function, not to "the place where it (sum) started".
function example(digit1, digit2) {
const sum = digit1 + digit2;
return `${sum}`
}
const invoke = example(1, 2);
console.log(invoke);
The function example receives two values which it places in the variables digit1 and digit2, then creates a new variable sum which contains the result of adding digit1 and digit2. (The variables digit1, digit2, and sum are all scoped to the function itself; they do not exist outside of that function.) It then returns the value contained in sum -- not the variable itself -- to the thing that called the function.
Which in this case, is this line:
const invoke = example(1, 2)
The function example receives the values 1 and 2, and returns the value "3". Which means that outside the function, the returned value takes the place of the function call itself, resulting in, effectively,
const invoke = "3"
The code outside the function "calls" the function. The function "returns" a value -- not a variable, a value! -- to the code outside the function. You can think of a function as a box with inputs and an output: you call it with inputs, and it returns to you an output value.
(Incidentally, the return statement you've used unnecessarily coerces the result into a string, where you probably want a number: just return sum would likely be preferable.)
return will put whats being returned (sum in this case) at the place where the function is invoked (in this case, in front of invoke).
so invoke = sum (sum is returned/ put on the place where the function is invoked)
I have been dealing with issues in multiple pieces of code but it seems to boil down to what I’m showing in this demo. I think it is related to the ’s dereferencing of a closure:
function get_5(callback) {
var result = 5;
callback(result);
}
function get_self(x) {
return x;
}
get_5(console.log);
// 5
console.log(get_self(5));
// 5
In the first result, the first function ran as expected, sending its hidden variable into the input of the console.log function.
The second result also makes sense, as it really just proves the second function works: it takes what was fed in and returns it.
But things get strange when I try to combine the two functions:
var a = get_5(get_self);
console.log(a);
// Undefined!
This third result is undefined, strangely enough, and I am not sure why. Is the closure being dereferenced, maybe to the “sneakiness” of the get_self function? How can I fix this? As a bonus, is there a way to eliminate the get_self function entirely and be able to directly read the variable result, which isn’t modified, without specifying any particular callback?
get_5 has no return statement. It doesn't matter what you pass to get_5, it will always return undefined.
Perl will return the result of evaluating the last statement in a sub, but JavaScript will not.
If you want get_5 to return the result of calling the callback you pass to it, then you have to say so explicitly:
function get_5(callback) {
var result = 5;
return callback(result);
}
I am relatively new to Javascript and am working through ch. 5 of Eloquent Javascript. I came across some code that I don't quite understand. I know HOW it works (the general method and steps), but I don't understand WHY it works.
The code is here:
function filter(array, test) {
var passed = [];
for (var i = 0; i < array.length; i++) {
if (test(array[i]))
passed.push(array[i]);
}
return passed;
}
Basically the function takes the element the 'for loop is iterating over' from the array, and compares it to the test parameter.
I am wondering how/why this works:
if (test(array[i]))
There is no || && or other 'comparison operators'. How does it compare values with only using parenthesis?
How is test compared to the array[i] value with no operators?
Link to file: http://eloquentjavascript.net/05_higher_order.html
go to 'Filtering an Array' exercise
Thanks!
Whatever is inside the parentheses of an if statement will be evaluated. If the result is falsy (false, 0, "", NaN, null, undefined) it fails and if the result is truthy (everything else) it passes. So if your if statement contains a function call if (test(something)) {}, then the if statement just says if the result of the function call is truthy then pass.
Also, && and || are not comparison operators, they are boolean operators. They just connect the result of two statements, like true || false which evaluates to true.
I am not quite sure, but I think this is a custom function. Most likely there is some comparison there and the result of the function is True/False. If you give us the whole code we could explain it better to you.
This code is accepting a test parameter that is what is called a "predicate function" i.e. a function that given an element will return true or false.
It's going to be used for example with
var big_numbers = filter(numbers, function(x){ return x > 100; });
i.e. the expected parameter test is actually code.
In Javascript passing code is very common and idiomatic. It's something that is more annoying in other languages that don't support the concept of "closure" and of "nested function", forcing all code to live at the top level, being given a name and to have no context (e.g. the C language).
'test' here is a function, not a value. In Javascript, each function is an object and can be passed as parameter. In this case, test is a function that take one parameter and return true or false base on the parameter value.
So in the for loop, test function is called with each array element and if the result is true, it will be store in another array. Eventually, passed elements would be return to the function caller.
I'm reading "JavaScripts The Good Parts"(by Douglas Crockford). It's good.
I can not understand following code. It's working correctly. But I can not understand how it works.
There are 5 questions about this code.
values of arguments (I checked them as [A], [B] in comment)
reason that document.writeln does not work(i.e. show nothing) in function (I checked test position as [C], [D] in comment)
result of slice in this code (in [A], [B])
values of variable args (in [A], [B])
reason that document.writeln shows 'undefined' (in comment [E] )
After showing that code, I will explain more.
var myTest = {};
Function.prototype.method = function(name, func) {
if(!this.prototype[name])
{
this.prototype[name]=func;
}
};
Function.method('bind', function(that) {
var method = this,
slice = Array.prototype.slice,
args = slice.apply(arguments, [1]); //[A] value of arguments and args
//-------------------------------
//[C] following document.writeln do not work. why?
document.writeln("<C>arguments[0]:", arguments[0]);
document.writeln("<C>arguments[1]:", arguments[1]);
document.writeln("<C>args:",args);
myTest.str1 = 1;
myTest.str2 = "ABC";
document.writeln("<C>str1:", myTest.str1);
document.writeln("<C>str2:", myTest.str2);
//-------------------------------
return function(){
//-------------------------------
//[D] following document.writeln do not work. why?
document.writeln("<D>arguments[0]:", arguments[0]);
document.writeln("<D>arguments[1]:", arguments[1]);
document.writeln("<D>args:",args);
myTest.str3 = 2;
myTest.str4 = "DEF";
document.writeln("<D>str3:", myTest.str3);
document.writeln("<D>str4:", myTest.str4);
//-------------------------------
return method.apply(that, args.concat(slice.apply(arguments, [0]))); //[B] value of arguments and args
};
});
var x= function(){
return this.value;
}.bind({value:666});
//-------------------------------
document.writeln("str1:", myTest.str1, "<br/>"); //[E]show undefined. why?
document.writeln("str2:", myTest.str2, "<br/>"); //[E]show undefined. why?
document.writeln("str3:", myTest.str3, "<br/>"); //[E]show undefined. why?
document.writeln("str4:", myTest.str4, "<br/>"); //[E]show undefined. why?
//-------------------------------
alert(x()); //666 -> no problem
document.writeln in [C], [D], [E] was for testing. But they don't work as I expected.
Alerting '666' operates well. (No problem)
Help me, please...
----------- after removing if-confition in Function.prototype.method I got following result
[C]arguments[0]:[object Object]
[C]arguments[1]:undefined
[C]args:
[C]str1:1
[C]str2:ABC
str0C:[object Object]
str1C:undefined
str0D:undefined
str1D:undefined
str1:1
str2:ABC
str3:undefined
str4:undefined
[D]arguments[0]:undefined
[D]arguments[1]:undefined
[D]args:
[D]str1:2
[D]str2:DEF
str0C:[object Object]
str1C:undefined
str0D:undefined
str1D:undefined
str1:1
str2:ABC
str3:2
str4:DEF
Now, I wonder real value of arguments in [C], [D], the contents of array...
Using JSON.stringify(arguments[0])), I finally got the real value of arguments.
[C]arguments[0]:{"value":666}
This is what I really want.
[C]arguments[1], [D]arguments[0], [D]arguments[1] do not have values. So they are 'undefined', right.
Now, I want to know what "args = slice.apply(arguments, [1]);" does in [A].
args = slice.apply(arguments, [1]);
As I know, slice returns copy of array. Because we use apply, slice works using arguments as this, and [1] as array of argument. At this time, arguments have only one item {"value":666"}. slice(start, end) returns copy of array which starts from 'start' and ends with 'end'. Then, in this case slice.apply(arguments, [1]) must return copy of arguments which starts from 1. But as we know arguments have only 1 item, so arguments[1] does not exist.(arguments[0], {value:666} exists.) Then how this work? args is undefined. What does this do? Is there anything that I overlooked?
In [B] it returns "method.apply(that, args.concat(slice.apply(arguments, [0])));".
return method.apply(that, args.concat(slice.apply(arguments, [0])));
In this, [0] is array of argument. 0.. Why zero? And arguments is undefined. Um... Then this returns arguments[0]? And that is {value:666}? And alert '666'?
I got it..
arguments in [A] is arguments of bind function
arguments in [B] is arguments of x function
Right?
Now there is one (maybe last) question .. ^^
When I call document.writeln.bind(document,"TEST") , what is 'that' in Function.method('bind', function(that)?
'that' is document? or 'that' is [document, "TEST"]
Function.prototype.method = function(name, func) {
if(!this.prototype[name])
…is your problem. You're not overwriting existing functions - and Function.prototype.bind does already exist (and has the same result as the one you defined, but without logging). That way, you don't overwrite it with your custom implementation, and none of your document.writeln calls or myTest assignments will be executed.
You can remove the if-condition for test purposes, and it will work. You should be able to answer the other questions yourself, once you see in the output what happens.
Now, I wonder real value of arguments in [C], [D], the contents of array...
There's only one object in question: {value:666} :-) You can output that by using JSON.stringify:
document.writeln("<C>arguments[0]:", JSON.stringify(arguments[0]));
…
[slicing] Then, in this case slice.apply(arguments, [1]) must return copy of arguments which starts from 1.
Yes. Btw it would've been easier to write slice.call(arguments, 1) - they're the same.
But as we know arguments have only 1 item, so arguments[1] does not exist.(arguments[0], {value:666} exists.) Then how this work? args is undefined.
Not undefined, but the empty array [].
What does this do? Is there anything that I overlooked?
It takes further, optional arguments to bind. You didn't pass any.
In [B] it returns "method.apply(that, args.concat(slice.apply(arguments, [0])));". In this, [0] is array of argument. 0.. Why zero?
Because you want to get all of the (optional) arguments to the bound function - slicing them from the beginning.
And arguments is undefined. Um... Then this returns arguments[0]? And that is {value:666}? And alert '666'?
arguments is not undefined, but has length 0, so the whole args.concat(…) evaluates to an empty array. that still points to the {value: 666}, yes - it is what will be passed for the this keyword.
So what are all these optional arguments about?
In your x example you've only used this, your function did not really have any arguments. But it could have - let's try one that has more arguments, like console.log:
var logger = console.log.bind(console, "Here:");
logger(); // Here:
logger(5); // Here: 5
logger({value:666}); // Here: {value: 666}
If you're not (yet) comfortable with the console, you could equally use document.writeln.bind(document, ….
I achieve a forEach function:
function forEach(arr, fn) {
for (var i = 0; i < arr.length; i++) {
fn.call({}, arr[i], i);
}
}
what I confused is about fn.call({}, arr[i], i);
the first parameter is pass empty just like above {} is better
or pass this in: fn.call(this, arr[i], i); is better?
Or it doesn't matter
It matters quite a bit. The first parameter to .call() is the value to be used for this inside the called function. Thus, it doesn't make sense to talk about what value is "better"; the right value to pass is the one you need in order for the called function to operate properly.
For example, if you want to call a function on the Array prototype, then the value of this inside that function has to be something that "feels like" an array (a "length" property and numerically-indexed properties). Thus:
var sneaky = {
"0": "hello",
"1": "world",
"length": 2
};
alert( Array.prototype.join.call(sneaky, " - ") ); // "hello - world"
That works because that function expects this to refer to the array to be joined.
There are as many other examples as there are functions that have expectations about this. In your sample code, passing {} gives the called function a this reference to that newly-created empty object. Will that work? I don't know, because that function could expect anything. There's no way to find out, either, except by looking at the code (or trusting documentation). If all you know is that it's some random arbitrary function, then {} is a reasonable guess, though undefined might be better, to force early failure.
Personally I would go with passing this. By passing {} you are limiting the flexibility of your function. You will never be able to bind another object to this function the way it is currently written. This won't work:
forEach.call(newContext, array, fn)
Neither will this:
forEach(array, fn.bind(newContext));
By binding {} inside your forEach you are adding unexpected behavior.