Javascript overloading functions - javascript

So I'm reading through a book and it uses this method to overload functions-
function addMethod(object,name,fn){
var old = object[name];
object[name] = function(){
if (fn.length == arguments.length){
return fn.apply(this,arguments);
} else if(typeof old == 'function'){
return old.apply(this,arguments);
}
}
}
I have a few questions on this.
Why is fn.length still in scope when the function that's passed in is called? Shouldn't executing the addMethod have caused fn to go out of scope?
Why isn't the arguments referring to the arguments property of the anonymous function, rather than the arguments property of the fn function? (which it should I thought?)

The parameter "fn" is in scope because that's how JavaScript works. It's part of the closure around that anonymous function.
The anonymous function created is the replacement for the original function bound to the object with the property name "name". When called, it checks the arguments actually passed on that particular call by looking at the arguments object. If it sees that the number of arguments passed is the same as the number of formal parameters in the "fn" function, then it calls that function. Otherwise, it calls the previous ("old") function, if it exists and is a function.A key thing to understand is that the .length property of a function instance gives you the number of formal parameters in the declaration. For example, the .length for that "addMethod" function would be 3.
The way that closures work in JavaScript took me a while to really "get" because I was a C programmer for a long time. In languages like that, space for the function call local variables (etc) is allocated on the stack, and when the function exits it's all popped off the stack. JavaScript just doesn't work that way.

Related

When will an anonymous function be used?

For example below is an anonymous function that has been placed in parentheses so now the function can be stored as a variable and called on else where as seen in number 2, However how can script number 1 be called to run? How can it be identified if it has no name? And how to change an anonymous function to a defined function?
**Number 1**
(function() {
// Do something
})();
**Number 2**
(var funcName = function() {
// Do something
})();
funcName();
The first function is called immediately because it is followed by () which calls a function.
Then if you were to remove the () from around the var statement (which is an error):
The second function is also called immediately, for the same reason.
The value stored in funcName (which is called as if it were a function, so will cause an error if it is not a function) is the return value of the second function (and is defined by the code you represented as // Do something — the "something" needs to include "return a function").
How can it be identified if it has no name?
Names are only really useful for use in debuggers (where they are very useful in stack traces and the like). For identifying a function to call, you access them like any other object or primitive (via a variable, property, etc). A function declaration just creates a variable with a matching name in the current scope.
Yes, these are anonymous functions, but they are also functions that are being called / invoked immediately, and hence don't need names to be referred to later.
There are many uses for Immediately-Invoked Function Expression (IIFE), but one is to use functions to establish namespaces that do not pollute global

different types of parameters in javascript function

I am quite new to javascript. When going through the javascript codes, I have found ::
function Method1(sender, args) { ... }
function Method2(source, arguments) { ... }
When to use (sender, args) and (source, arguments)? What do they mean?
arguments is actually not a JS reserved word, otherwise your Method2 would not have worked and would have thrown a Syntax Error.
When arguments is used in the parameters list of a function, it is simply a regular function parameter / argument, exactly like your sender, source and args.
It is true now that Arguments cannot be used as a class name. It is used internally by JavaScript to create an arguments object (that is the one referred to by Tushar in the comments).
When control enters an execution context for function code, an arguments object is created unless (as specified in 10.5) the identifier arguments occurs as an Identifier in the function’s FormalParameterList or occurs as the Identifier of a VariableDeclaration or FunctionDeclaration contained in the function code.
In every function, you can access all the parameters passed during that function call using this arguments array-like object. It is very useful for functions that may accept a non-predetermined (and possibly unlimited) number of parameters.
So what happens with your Method2 is that it uses the same identifier "arguments" which now is assigned just a single parameter. As if it had shadowed the built-in arguments object.
Whereas if it had not been used in the parameters list, arguments within the function block would have been automatically assigned the list of all parameters.
Demo: http://jsfiddle.net/5cexbrff/ (see result in the console)

Why "this" refers to Window in forEach in javascript? [duplicate]

This question already has answers here:
The invocation context (this) of the forEach function call
(5 answers)
Closed 5 years ago.
If I run this code, window object gets printed to console.
var arr= [1,2,34,5,6,7,7,8];
arr.forEach(function(e){
console.log(this);
});
Why does it not refer to arr object or specific items in array object? I want to understand the reason behind it, like what's going on. this gets defined using by new, or the object invoking this function, right?
.forEach() specifies the value of this within the iterator based on its 2nd parameter, thisArg.
arr.forEach(callback[, thisArg])
So, it will only use a particular object if you provide it:
arr.forEach(function(e){
console.log(this);
}, arr); // <---
Otherwise, the value of this will be the default value of a normal function call -- either undefined in strict mode or the global object (window in browsers) in non-strict.
function foo(e) {
console.log(this);
}
foo(); // [object Window]
[1].forEach(foo); // (same)
Though, the arr is still provided to the iterator, just as its 3rd argument:
arr.forEach(function (e, i, arr) {
console.log(arr);
});
This comes from two different factors of how the engine will determine the this value for the function, the thisArg optional parameter to forEach, and whether or not the code is in strict mode.
From MDN:
If a thisArg parameter is provided to forEach(), it will be passed to callback when invoked, for use as its this value. Otherwise, the value undefined will be passed for use as its this value. The this value ultimately observable by callback is determined according to the usual rules for determining the this seen by a function.
These rules are elsewhere documented as follows:
Inside a function, the value of this depends on how the function is called.
function f1(){
return this;
}
f1() === window; // global object
In this case, the value of this is not set by the call. Since the code is not in strict mode, the value of this must always be an object so it defaults to the global object. (emphasis added)
Note that this behavior changes in strict mode. If you add "use strict" to the top of the call back, it will log undefined to the console.
In short, if you want the this value to refer to the array, arr, you just need to call forEach like this:
var arr= [1,2,34,5,6,7,7,8];
arr.forEach(function(e){
console.log(this);
}, arr);
Because the specification says so. Relevant parts:
15.4.4.18 Array.prototype.forEach ( callbackfn [ , thisArg ] )
...
5. If thisArg was supplied, let T be thisArg; else let T be undefined.
...
7.c.ii Call the [[Call]] internal method of callbackfn with T as the this value and argument list containing kValue, k, and O.
Now, we all know (hopefully) that if a function is to be called with a this value of null or undefined, this is set to the global object instead. Here is a refresher:
10.4.3 Entering Function Code
If the function code is strict code, set the ThisBinding to thisArg.
Else if thisArg is null or undefined, set the ThisBinding to the global object.
...
As you can also see, this will not point to the global object if we are not in strict mode (the default).
I want to understand the reason behind it
Why it was decided to do it this way can likely only be explained by someone who worked on the language. You could ask at https://esdiscuss.org or http://es-discourse.com/.
this gets defined using by new, or the object invoking this function, right?
Yes. And in this case, it's forEach that invokes your function. Since no special precautions[1] are made, it simply passes nothing for this[2] just like any non-method function call, which will result into the global object as your function is sloppy code[3].
1: Like passing a second argument to forEach, which would be used for this
2: The spec says it should pass undefined
3: Meaning, that it does not use strict mode. In strict code, this would literally really be undefined.
The function you've passed into forEach does not have the same context as your object. The forEach (as well as map etc) functions run detached from any object, so functions passed into them are executed in global scope by default.
You could be explicit and fix that in one of two ways.
give the forEach a context to run in (as suggested by every other answer)
This uses code like:
var arr = [...];
var iterator = function(e) { console.log(this); };
arr.forEach(iterator, this);
make your iteration function explicitly bound to your object first
this uses code like:
var arr = [...];
var iterator = function(e) { console.log(this); };
var iteratorWithThisContext = iterator.bind(this);
arr.forEach(iteratorWithThisContext);
The bind(<context>) function is a core javascript function for taking any function, and any context, and returning a new function that will always execute with the specified context when called, no matter who's doing the calling, or when:
var fn = function() { console.log(this); }
fn(); // window
var fndoc = fn.bind(document);
fndoc(); // document
var arr = [];
var fnarr = fn.bind(arr);
fnarr(); // the array
From MDN:
If a thisArg parameter is provided to forEach(), it will be passed to callback when invoked, for use as its this value. Otherwise, the value undefined will be passed for use as its this value. The this value ultimately observable by callback is determined according to the usual rules for determining the this seen by a function.
If you expect this to be the array, you have to call arr.forEach(function(e){}, arr); using the optional second paramater, thisArg.
Well that's very interesting.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
You can include a second argument for the this object when calling forEach. If not provided, this will be limited to the same scope as if you were simply to write for (var i in arr) {.. }. I suspect they did this so that the forEach function behaves as closely to a built-in syntactical feature of JS as possible.
Because the function being called here is not being called as an object method, this refers to the current object context, and in a browser console window, that's the window object.
This Mozilla Developer Network article goes into great depth about what this means in different contexts.

Access function propertes (.caller) without specifying it's own name

In JavaScript you can access a function's "functional properties", for instance caller. (Actually, I do not even know if the "functional property" is a right word.)
For example:
func0 = function() {
console.log(typeof func0.caller)
}
func1 = func0
func1()
var o = { func2: func0, func3: function(){ console.log(typeof o.func3.caller) } }
o.func2()
o.func3()
As you can see, you must provide a function name before you can add .caller. But if the function is anonymous or for some reason I do not want to use the name (maybe I plan to rename the fucntion in the future): can I still access caller?
What you are accessing is the arguments object that is 'assigned' to every function. So you don't use the function name. You use the arguments object.
arguments object acts like an array, so arguments[0] returns the first argument passed to the function.
arguments.length
// a property of the arguments object that tells you how many arguments the function has
arguments.caller
// reference to the function that invoked the current function.
arguments.callee() will call the function recursively. Its a reference to the currently executing function.
Is that what you mean?
Use arguments.callee.caller
It seems that the reason this works is because arguments.callee is giving you a reference to the function that is currently executing, and then arguments.caller is referencing the function that invoked that function (which is actually the same function). Maybe that is why using arguments.caller is not advisable.

Is it good to write javascript functions inside functions and not use 'new' on the main function?

I now know this works:
function outerfunction(arg1, arg2, arg3) {
var others;
//Some code
innerFunction();
function innerFunction() {
//do some stuff
//I have access to the args and vars of the outerFunction also I can limit the scope of vars in the innerFunction..!
}
//Also
$.ajax({
success : secondInnerFunction;
});
function secondInnerFunction() {
// Has all the same benefits!
}
}
outerFunction();
So, I am not doing a 'new' on the outerFunction, but I am using it as an object! How correct is this, semantically?
There doesn't appear to be anything wrong with what you're doing. new is used to construct a new object from a function that is intended as a constructor function. Without new, no object is created; the function just executes and returns the result.
I assume you're confused about the closure, and how the functions and other variables belonging to the function scope are kept alive after the function exits. If that's the case, I suggest you take a look at the jibbering JavaScript FAQ.
You are not using the outer function as an object. You are using it to provide a closure. The border line is, admittedly, thin, but in this case, you are far away from objects, since you do not pass around any kind of handle to some more generic code invoking methods, all you do is limiting the scope of some variables to the code that needs to be able to see them.
JFTR, there is really no need to give the outer function a name. Just invoke it:
(function() { // just for variable scoping
var others;
...
})()
I do this sort of thing all the time. Yes - javascript blurs the boundary between objects and functions somewhat. Or perhaps, more correctly, a javascript function is just an object that is callable. You would only really use the 'new' prefix if you wanted to have multiple instances of the function. My only suggestion here is that its usually considered good practice to call a function after you've declared it (you are calling the innerFunction before it has been declared) - although that could be considered nit-picking.
This is a valid example.
Functions in JavaScript are first order objects. They can be passed as an argument, returned from a function or even set to a variable. Therefore they are called 'lambda'.
So when you are directly using this function (without new keyword) you are directly dealing with the function as an object. When u are using new keyword, you are dealing with an object instance of the function.

Categories

Resources