0

I'm reading this post from stackoverflow wiki. And I want to fully understand the following code snippet. Hopefully someone can help with the following questions.

var plane = function(defaultAirport) {
                var lastAirportLeft = defaultAirport;
                var car = {
                    driver: {
                        startAccessPlaneInfo: function() {
                            setInterval(function() {
                                console.log("Last airport was " + lastAirportLeft);
                            }, 20000);
                        }
                    }
                };
                car.driver.startAccessPlaneInfo();
                return {
                    leaveTheAirport: function(airPortName) {
                        lastAirportLeft = airPortName;
                    }
                }
            }("Boryspil International Airport");


            plane.leaveTheAirport("John F. Kennedy");
  1. When I open my console, i just check the typeof(plane) and it's an object. But if I call plane("default airport") - it will throw error.I know "Boryspil International Airport" is already passed into plane, but how to cover the existing value with another one? Also, plane is a function object, why I cannot call like plane("XXX")?

  2. after call plane.leaveTheAirport("John F. Kennedy"), the console will print out John F. kennedy instead of Boryspil International Airport. Can anyone explain why the old value from outer scope is replaced with the old one?

Community
  • 1
  • 1
catlovespurple
  • 682
  • 1
  • 7
  • 20
  • 1
    1. `plane` isn't a function. Because the function is invoked immediately, `plane` reference the *return value* of the function, which is an object `return { leaveTheAirport: ... };` –  Dec 16 '15 at 00:31

2 Answers2

1

1.When I open my console, i just check the typeof(plane) and it's an object.

Ok.

typeof is an operator, there's no need for a grouping operator so: typeof plane is sufficient.

But if I call plane("default airport") - it will throw error

Objects don't implement call, Functions do, so that is expected.

"Boryspil International Airport" is already passed into plane, but how to cover the existing value with another one? Also, plane is a function object, why I cannot call like plane("XXX")?

I think you mean "assign a new value to lastAirportLeft". The function assigned to plane.leaveTheAirport has a closure to the lastAirportLeft variable, so it can set the value (and it does).

Also, plane is a function object, why I cannot call like plane("XXX")?

No it isn't. If it was, typeof plane would return 'function', see above.

  1. after call plane.leaveTheAirport("John F. Kennedy"), the console will print out John F. kennedy instead of Boryspil International Airport. Can anyone explain why the old value from outer scope is replaced with the old one?

Because plane.leaveTheAirport has a closure to the variable, so it can access it.

See MDN: Closures and Private Members in JavaScript.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • Thanks. Much clear in my mind now. So in terms of the type of plane, can I say it's an object with a function as a return value (leaveTheAirport)? – catlovespurple Dec 16 '15 at 00:44
  • @catlovespurple—it's an object with a single property: *leaveTheAirport* that is a function (so it is said to be a method of *plane*). – RobG Dec 16 '15 at 06:13
0

plane is the object defined by the literal:

{
    leaveTheAirport: function(airPortName) {
        lastAirportLeft = airPortName;
    }
}

since that is what is returned by the function that is called in the expression that initializes plane. So plane is an ordinary Javascript object with a single property leaveTheAirport, which is a function that has access to some closured variables (namely: defaultAirport, lastAirportLeft, and car). Here are some simpler examples to help you understand:

1)

var x = function ( ) { return 2; }( );
// x === 2, and x is a number, not a function
// Notice the difference between this and:
var x = function ( ) { return 2; };

2)

var outerValue = 'foo';

function setOuterValue ( newValue ) {
    outerValue = newValue;
}

function printOuterValue ( ) {
    console.log( outerValue );
}

printOuterValue( ); // 'foo'
setOuterValue( 'bar' );
printOuterValue( ); // 'bar'

Together:

var obj = function ( outerValue ) {

    return {
        setOuterValue: function ( newValue ) {
            outerValue = newValue;
        },
        printOuterValue: function ( ) {
            console.log( outerValue );
        }
    };

}( 'foo' );

obj.printOuterValue( ); // 'foo'
obj.setOuterValue( 'bar' );
obj.printOuterValue( ); // 'bar'
Paul
  • 139,544
  • 27
  • 275
  • 264
  • FULLY understand now!!!! Thanks! Just one quick thing, in your last code snippet, I can see that the setOuterValue will reassign newValue to outerValue. However, is there any way to prevent this happening? - I mean make outerValue secured without being polluted by newValue parameter. – catlovespurple Dec 16 '15 at 00:51
  • @catlovespurple I'm not sure that I understand your question, so I apologize if this doesn't answer it properly. If you don't want `outerValue` to be modified you can just avoid returning a function that allows it to be. In the last example, if the returned object literal just had `printOuterValue` but no `setOuterValue` you wouldn't be able to modify `outerValue`. – Paul Dec 16 '15 at 00:57
  • @catlovespurple Similarly, in the code in your post, only `lastAirportLeft` can be modified, but neither `car` nor `defaultAirport` can be modified. – Paul Dec 16 '15 at 00:59
  • I think I got it. Only when I expose the variables by putting them into the return function, it will make them editable... Thanks for your comment, answer and code. Credit will be granted to you! – catlovespurple Dec 16 '15 at 01:01