简体   繁体   中英

Why does this return a reference to the global window object, even though 'this' is within another function

if (typeof obj == 'undefined') {
  obj = {};
}

obj.thing = new function () {
  if (typeof this.global == 'undefined') {
    this.global = (function () {return this;})();
  }
}

this.global is assigned to this inside of a function. So, why does this return a reference to the window object?

console.log(this) > DOMWindow
console.log(obj.thing.global) > DOMWindow
console.log(window) > DOMWindow

I would love to understand this better.

In ES 3 and ES 5 there is a this keyword associated with every execution context (ES 3) or Lexical Environment (ES 5). The value is set according to the rules for entering global or function code as described in ECMA-262 §10.4 .

In your code you have:

  this.global = (function () {return this;})();  

Where the result of calling an anonymous function is assigned to this.global . Within that anonymous function, the value of this is set according to the algorithm in §10.4.3 .

Since the function is called without setting the value of this , and the code is not in strict mode, the value of this is set to the global object (which, in a browser, is generally the window object) per step 2 of the algorithm.

If the code was in strict mode, then the value of this within the anonymous function would be undefined , which is the value that would be assigned to this.global .

this is a keyword which always returns the current context. Try this:

if (typeof obj == 'undefined') {
  obj = {};
}

obj.thing = new function () {
  if (typeof this.global == 'undefined') {
    var self = this;
    this.global = (function () {return self;})();
  }
}

The problem is, that within your self-invoking anonymous function, the context is the global object aka window there. So it returns the window reference. Even if the new keyword creates a new object as context for your outer function. That outer context does not matter for the invocation of your self-invoking function.

To avoid that, you can modify the code slightly into:

obj.thing = new function () {
  if (typeof this.global == 'undefined') {
    this.global = (function (that) {return that;})(this);
  }
}

this in javascript is really tricky. It does not mean what you think it means and can indeed have its value substituted in lots of little ways depending on how the function is invoked. Although it can help with optimization and gives you a certain degree of power and javascript-knowledge-points, you might want to avoid using it until you are comfortable with the idea.

It is better to think of 'this' as a special variable that contains extra information the invoker of the function passed in. If you want to lock down the value you can do it with the call/apply methods on functions or the browser Function.bind or _.bind in libraries like underscore.js.

var x = {
  name: "George",
  hiThere: function() { return "hi "+(this.name || "no value") ; }
}

x.hiThere(); // hi George

var thisWillBeGlobal = hiThere;
thisWillBeGlobal() // hi no value

var manuallyBoundToGeorge = function() {
  return x.hiThere();
}    
manuallyBoundToGeorge(); //hi George (always)
manuallyBoundToFred = function() {
  return x.hiThere.call({name: 'Fred'});
}
manuallyBoundToFred(); //hi Fred (always)

var hiGeorge = Function.bind(x.hiThere, x);
hiGeorge(); //hi George (always) - same as manual bind above

notice that Function.bind is not avilable in older browsers and it is generally preferred to use something like underscroe's _.bind

  • You would of course still use this when working with libraries like jquery that pass information through it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM