Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why the code this point to window object?

my code is:

var length = 20;
function fn(){
    console.log(this.length);
}

var o = {
    length:10,
    e:function (fn){
       fn();
       arguments[0]();
    }
}

o.e(fn);

the output is 20,1,who can tell me why?

like image 805
artwl Avatar asked Feb 19 '23 07:02

artwl


2 Answers

When the this keyword occurs inside a function, its value depends on how the function is called.

In your case, fn() is called without providing the a this value, so the default value is window. With arguments[0](), the context is the arguments object, whose length is 1.

The point is it does not matter where the function is called, but it matters how the function is called.

var length = 20;
function fn(){
    console.log(this.length);
}

var o = {
    length:10,
    e:function (fn){
       fn(); // this will be the window.
       arguments[0](); // this will be arguments object.
    }
}

o.e(fn);

Further more, if you want this to be the object o, you could use call or apply, or bind an object first.

var length = 20;
function fn(){
    console.log(this.length);
}

var o = {
    length:10,
    e:function (fn){
       var fn2 = fn.bind(this);
       fn.call(this); // this in fn will be the object o.
       fn.apply(this); // this in fn will be the object o.
       fn2(); // this also will be the object o.
    }
}

o.e(fn);
like image 92
xdazz Avatar answered Mar 08 '23 12:03

xdazz


Let's expand your code a little bit:

var length = 20;
function fn() {
    console.log(this, this.length);
}

var o = {
    length: 10,
    e: function(fn) {
        fn();
        fn.call(this);
        arguments[0]();
    }
}

o.e(fn);​

Demo: http://jsfiddle.net/ambiguous/Ckf2b/

Now we can see what this is (and thus where this.length comes from) when fn is called. This gives me the following output:

DOMWindow 0
Object 10
[function fn() { console.log(this, this.length); }] 1

We also have three ways of calling the function fn:

  1. fn(): just call it like any old function.
  2. fn.call(this): Use call to force a specific context (AKA this).
  3. arguments[0](): Call fn through the arguments object.

When you say fn(), there is no explicit value of this anywhere in sight so, in a browser, you get window as your this. The global window happens to have a length property:

Returns the number of frames (either frame or iframe elements) in the window.

That's where the zero (in my output) comes from, your window.length may be different.

We call e as o.e(fn) so this inside e is o, that's what o.e(...) means (barring bound functions and related complexities). So the this in fn.call(this) is o and that makes fn.call(this) the same (more or less) as o.fn = fn; o.fn() and we get o and 10 in the console. Notice that dot showing up again?

fn.call(o) is like o.fn = fn; o.fn()

The third one, arguments[0](), contains a hidden dot as p = 'm'; o[p] is (more or less) the same as o.m so arguments[0]() is like fn = arguments[0]; arguments.fn = fn; arguments.fn().

like image 23
mu is too short Avatar answered Mar 08 '23 10:03

mu is too short