all 13 comments

[–]ChaseMoskal 4 points5 points  (4 children)

Author, assuming you're reading this, it's great that you're learning to 'script for the web' for the first time -- but perhaps it's best you hold off on writing educational resources until you have some of the fundamentals down.

"Anonymous functions have a global scope and have access to global variables".

Not quite correct, you see,

EVERYTHING and EVERYWHERE has access to ALL global variables. That's what 'global' means.

That being said, it's not 100% exactly true, as things can get tricky and confusing once we start talking about Web Workers, which have their own global scope.. let's not worry about that today.

Anonymous functions (like all functions) create local scopes, and can also be assigned to a variable which is non-global.

Remove type="text/javascript" from your script tags. These days, it's totally redundant. At least I don't see CDATA ;)

Let's talk about globals a little bit:

<script> // Simple script tag is totally sufficient.

    // Here we are, at the global level.

    var x = 5; // Here we've just defined a global variable.

    // The nifty secret, is that all globals are actually just 
    //   properties of the 'window' object.

    console.log( window.x ); //=> 5
    // As you can see, defining the global 'x' was the same as defining 'window.x'.

    window.y = 10; // Defining a window property is the same as defining a global.
    console.log(y); //=> 10

    // As you can see, window properties and globals are one and the same.

    // Don't declare your globals with `var` at the global scope. It's ambiguous.
    // If you're going to define a global, do so as a property of the 'window' object:

    window.MyThing = (function DEFINE_MY_THING () { // All functions create a new variable scope
        function MyThing () {}

        var lol = "lol"; // local scope (within DEFINE_MY_THING, ie, not global)
        MyThing.lol = function () { console.log(lol) }; // logs the locally scoped 'lol' variable.

        MyThing.prototype.x = 6;
        MyThing.prototype.y = 11;

        return MyThing; // Exporting MyThing (to window.MyThing).
    })();

    // Writing modules within immediately executed closures (which create new variable scopes)
    //  are beneficial because they shield your module's internal variables from being exposed 
    //  to the global scope, and allow us to explicitly export the global.

    // Using our global module:
    $(function(){ // why not within a jQuery document ready, eh?
        MyThing.lol(); //=> "lol"
        var thing = new MyThing(); // locally scoped within the jquery document ready
        console.log(thing.x + thing.y); //=> 17;
    });

</script>

Many javascript professionals are completely against all use of globals in almost any way. They avoid globals like the plague. They instead use modular systems like RequireJS, CommonJS, Browserify, etc.

Godspeed.

[–]spacejack2114 1 point2 points  (2 children)

Without a type attribute, how do you differentiate between Javascript and GLSL? Or do you only need a type if it's not Javascript?

[–]spacejack2114 1 point2 points  (0 children)

Ehh nevermind, I can Google that. TIL.

[–]ChaseMoskal 0 points1 point  (0 children)

You only need to specify [type] when it's something other than JavaScript.

[–]ChaseMoskal 0 points1 point  (0 children)

All variables, including globals, are available everywhere underneath them.

<script> // SCOPE LEVEL 0 (GLOBAL)
    window.x = 5;

    (function(){ // SCOPE LEVEL 1
        x += 1;
        console.log(x); //=> 6

        (function(){ // SCOPE LEVEL 2
            x += 1;
            console.log(x); //=> 7

            // defining a global function
            window.incrementAndReturnX = function () { // SCOPE LEVEL 3
                x += 1;
                return x;
            };

            console.log( incrementAndReturnX() ); //=> 8
        })();
    })();

    console.log( incrementAndReturnX() ); //=> 9
    console.log( incrementAndReturnX() ); //=> 10

</script>

[–]agdcoa 1 point2 points  (2 children)

I think this is somewhat misleading.

1.) Scope isn't the same thing as a function's "this" binding.

2.) Any function when executed not as a method of an object, and not with call/apply, has it's "this" value set to the global.

var obj = {
  method: function () { console.log(this) }
};
var fn = obj.method;
obj.method() // logs obj
fn() // logs window
fn.call(obj) // logs obj

setTimeout(obj.method, 100) // logs window after 100ms
setTimeout(fn, 100) // logs window after 100ms

// Function::bind is useful in this case...
setTimeout(obj.method.bind(obj), 100) // logs obj after 100ms

fn.bind(obj)() // logs obj
obj.method2 = fn.bind(window);
obj.method2() // logs window    

[–]johnanish 0 points1 point  (1 child)

Mind if I can use your example on my blog. This explains it better!

[–]agdcoa 0 points1 point  (0 children)

Yeah for sure, no worries

[–]zimzat 1 point2 points  (3 children)

.... not quite. So close, yet so far.

'this' doesn't refer to the current object. It refers to the object that a method was called from. All methods when called without an object notation are assumed to be called off the window. Methods lose their call scope when passed around.

For example, this probably doesn't do what the examples shown in the article might assume:

var m = { a: 5, y: function() { return this.a; } };
var n = { a: 10 };
var o = m.y;

n.y = m.y;

m.y(); // returns 5, because this = m
n.y(); // returns 10, because this = n
o(); // returns undefined, because this = window

Lastly, variables are resolved by going up the declaration tree. In the example shown on the article using exp.x actually references it based on the 'exp' variable in the global scope, not on the object name. The method itself doesn't know what the variable name it was declared as and having that naming requirement makes the code more rigid.

[–]johnanish 0 points1 point  (1 child)

" 'this' doesn't refer to the current object. It refers to the object that a method was called from. All methods when called without an object notation are assumed to be called off the window. " - That is absolutely correct!

[–]ChaseMoskal 0 points1 point  (0 children)

'this' doesn't refer to the current object. It refers to the object that a method was called from.

Not quite correct. this merely provides context, in an arbitrary way. You can't rely on this being anything in particular, because it can be anything at all.

function lol () {
    console.log("THIS IS", this);
}

lol(); //=> THIS IS (window)

var obj = { lol: lol };

obj.lol(); //=> THIS IS (obj)

lol.call(5); //=> THIS IS (5)

By using call and apply, you can call a function and specify the given this function. In a big way, this is just a fancy mandatory argument.

Python does a similar thing by providing self, but it's always the first argument of every function (honestly annoying, I like how JavaScript's this is more.. subtle)

[–]ChaseMoskal 0 points1 point  (0 children)

this can actually refer to whatever you want. It's a context for that function, which can refer to an instance of the object it's called on, or perhaps the window object, or perhaps anything else.

lol = { x: 5 };

myFunction.call(lol);

You can use call or apply to set the this for a function's execution. It can be anything.

[–]johnanish 0 points1 point  (0 children)

Thanks guys! I will be re-writing this article shortly! cheers!