简体   繁体   中英

Peculiar JavaScript construct: variable of object type in object definition

Okay, I stumbled upon this piece of code..

How come this works? What sort of evil scheme does JavaScript use to resolve variables?

The way I see it, as a C++ kind of guy: the class/object definition contains a non-existent reference to an object of the class being defined. Seriously, how?

(To be honest, I understand partially - I could deduce a strawman concept of how and when JS resolves names.. but maybe this way the question will be of more use to someone else, someday)

Guilty code:

function Sio() {
    this.someValue = 5;
    this.doStuff = function() {
        console.log("look: "+howDoYouResolveThisYouFoulCreature.someValue);
    };
}

var howDoYouResolveThisYouFoulCreature = new Sio();

That seems so wrong.

Lots of concepts here, and I'm not sure which one is giving you troubles…

The two most likely ones are new / this and var .

new / this

When you call a function the value of this is determined by the context in which you call it.

If you use the new keyword, you create an instance of the function and make that instance the context.

When you call howDoYouResolveThisYouFoulCreature.doStuff() you are accessing that instance as a global. It would usually make more sense to:

this.doStuff = function() {
    console.log("look: "+ this.someValue);
};

Since foo.doStuff() makes foo the context for that invokation of doStuff() (which makes the function reusable between different instances of Sio )

var

  1. Scope in JavaScript is at the function level.
  2. Using var something anywhere inside a function will scope that variable to that function
  3. It is considered good practise to use a single var statement at the top of a function to avoid confusion

Also, the doStuff function is not called before howDoYouResolveThisYouFoulCreature has a value. Until that point all that matters is that the function is syntactically correct, it doesn't matter what type the variable is.

It works because the function() this.doStuff isn't executed before howDoYouResolveThisYouFoulCreature is created. Keep in mind for as many new Sio()'s that you make this will always console.log the howDoYouResolveThisYouFoulCreature.someValue regardless of the variable name that doStuff() is called from.

This works because:

 
 
 
  
  var howDoYouResolveThisYouFoulCreature = new Sio();
 
  

... actually resolves into:

 
 
 
  
  var howDoYouResolveThisYouFoulCreature; howDoYouResolveThisYouFoulCreature = new Sio();
 
  

So at the time the function doStuff is assigned, the var is already declared.

Edit: Forget that, I was being foolish. It turns out pimvdb is right, and here's the proof ( also on jsfiddle ):

 function A() { this.logValue = function() { if (b === undefined) { console.log('Wah, wah, wah...'); } else { console.log(b.someValue); } }; } function B() { this.someValue = 42; } var a = new A(); a.logValue(); // Wah, wah, wah... var b = new B(); a.logValue(); // 42 

So the execution context is the key. When Sio (or, in this case, A ) is constructed, it's scoped to where b might , at some point, be defined. The variable isn't resolved until the function is called, at which point it might be defined. Or not. No biggie. :-)

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