Recently one of my friends asked me the output of following code
var length = 10; function fn() { console.log(this.length); } var obj = { length: 5, method: function(fn) { fn(); arguments[0](); } }; obj.method(fn, 1);
I thought the answer would be 10 10 but surprisingly for second call i.e. arguments[0]();
the value comes out to be 2 which is length of the arguments passed. In other words it seems arguments[0]();
has been converted into fn.call(arguments);
.
Why this behavior? Is there a link/resource for such a behavior?
Code duplication makes software less maintainable and reduces our ability to iterate fast.
Using DRY or Do not Repeat Yourself principle, you make sure that you stay away from duplicate code as often as you can. Rather you replace the duplicate code with abstractions or use data normalization. To reduce duplicity in a function, one can use loops and trees.
Code duplicate – identical or similar source code Source code that is used in identical form several times within a piece of software is called a code duplicate – alternatively also a software clone or source code clone. Similar code sections or fragments are also considered duplicates.
If you want to keep a consistent html structure for the sidebar on each page, use php. You would create a file called sidebar. php, and use the include method to import the same code into each page. If you want to change it later, edit the single sidebar.
The difference is because of the this
context of each method call.
In the first instance, because the call is merely fn();
, the this
context is Window
. The var length = 10;
variable declaration at the top happens in the root/Window context, so window.length
should be 10
, hence the 10
in the console from the first function call.
Because arguments
is not an array but is actually an Object of type Arguments
, calling arguments[0]()
means that the this
context of the function call will be of the parent Object, so this.length
is equivalent to arguments.length
, hence the 2
(since there are 2 arguments). (See @Travis J's answer for a more thorough explanation of this part.)
If you were to add
this.fn = fn; this.fn();
to the method()
function, the result would be 5
.
It is due to how this
works within the various scopes in which it is referenced.
Notice the outputs of the this.toString()
and you will see what the referenced target is.
Starting with calling the function f
directly from the Window, this
will reference Window
and thus the length will be Window.length
which has been declared to be 10
.
Moving on to if we assign f
directly as a method of obj
, then this
would reference obj
and thus the length will be obj.length
which has been declared to be 5
.
Where it gets interesting/confusing is when you pass in f
as a parameter to function method
of obj
.
NOTE: The outcome here will be browser specific. Run it in Safari and Chrome and observe the different outputs.
On both browsers: arguments[0]()
is pseudo equivalent to arguments.0()
(although not syntacticly allowed for arguments
) which is exactly the same behavior observed earlier with obj.fn()
which means arguments
is the reference target. Which as noticed is the number of arguments passed to obj.method
.
The execution of fn
inside of method
is how a callback function works for which you can find a more expansive answer here.
var length = 10; function f() { console.log(this.toString()); console.log(this.length); } var obj = { length: 5, fn: f, method: function(fn) { fn(); arguments[0](); } }; f() f(1); obj.fn(); obj.fn(1); obj.method(f, 1); obj.method(f, 1, 2);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With