Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why this behavior for javascript code? [duplicate]

Tags:

javascript

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?

like image 703
Pankaj Shukla Avatar asked Feb 16 '18 18:02

Pankaj Shukla


People also ask

Why is code duplication a problem?

Code duplication makes software less maintainable and reduces our ability to iterate fast.

How do I stop duplicating codes?

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.

What is duplicate code called?

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.

How do I stop code duplication in HTML?

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.


2 Answers

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.

like image 161
musicnothing Avatar answered Sep 30 '22 09:09

musicnothing


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);
like image 38
Jason Cust Avatar answered Sep 30 '22 08:09

Jason Cust