Coder Social home page Coder Social logo

js-scope-readme's Introduction

JS Scope

Objectives

  • Explain how scope works in JavaScript
  • Explain what lexical or function-level scope is
  • Explain what block-level scope is
  • Explain how local and global variables work in JS

What Is Scope?

Scope is the current context of your code, and can be locally or globally defined. Understanding scope is the key to understanding how your variables interact with each other in your code. Without a solid understanding of scope, your variables could be storing entirely different values than you think they are.

Ruby versus JavaScript Scope

When talking about scope in this README, we mean variable scope — what's available in the context of your currently executing code. In Ruby, there are four levels of variable scope — global, class, instance, and local — determined by prefixes on the variable name:

  • $ for global variables
  • @@ for class variables
  • @ for instance variables
  • no prefix for local variables

We'll focus on local variables for now. In Ruby, a variable's locality is determined by the function context it appears in. So in this example

def locality
  here = true
end

here is local to the method locality. Similarly,

["bread", "wine", "cheese"].each do |food|
  puts food
end

in the above example, food is local to the each block.

In Ruby, you can only access local variables that have been declared before the currently executing line in the current scope:

x = 1
$x = 3
@@x = 4
@x = 5

def my_method
  y = 2
  puts $x
  puts @@x
  puts @x
  puts x
end

my_method

puts y

puts x

The method call my_method returns the unknown local variable or method error, because x is not defined in the scope of that method. However, it successfully prints $x, @@x, and @x because of their broader scopes. (You'll probably see warning: class variable access from toplevel for @@x — this is expected, and you shouldn't use class variables in this way. We're bending the rules here to highlight how local scope works.)

puts y returns the exact same error as my_method because y was only defined inside the method, not in the global scope. puts x does work, because we're printing out x in the same scope in which it was created.

But translate that same code to JavaScript and you get a very different result:

var x = 1;

function myFunction(){
  var y = 2;
  console.log(x);
}


myFunction();
// prints out 1

console.log(y)
// error - y is not defined

console.log(x)
// prints out 1

The function call myFunction(); actually does work perfectly, even console.log(x); This is because the variable x is defined in the global scope. Any variable defined in an outer scope is available to inner scopes. (So everything defined in the global scope is available everywhere.)

However, anything defined in a function is not accessible outside of it, which is why the console.log(y); does not work. y was only defined inside the myFunction function, making it inaccessible anywhere else.

And again console.log(x); works because we're printing it out in the scope in which it was defined.

The Key To Scope

To determine a variable's scope in JavaScript, ask yourself two questions:

1. Is it declared inside a function?
2. Is it declared with the `var` keyword?

If a variable is declared in the outermost scope of a project, it's going to be global no matter what – that is, whether you write var foo = 'bar' or foo = 'bar'. Remember, saying that a variable is "global" in JavaScript just means that it's a property of the top-most object. (In the browser, that object is window; in other environments (like Node.js), it could be global.)

Inside a function, variables declared with var are only available within that function's scope. Variable's declared without var attach themselves to the global object.

Contrast this to Ruby's variable scoping mechanisms: Where Ruby uses prefixes to determine a variable's scope, JavaScript determines scope primarily based on where a variable is declared (and only when declared within a function does any sort of keyword prefix matter).

In our myFunction function, the variable y was defined with the var keyword. If instead, we had done:

function myFunction(){
  y = 2;
  console.log(x);
}

We would be able to call console.log(y) outside the function as well.

Let's take our whole code example:

var x = 1;

function myFunction(){
  y = 2;
  console.log(x);
}

console.log(y);

console.log(x);

If you copy and paste this into the JS Console, you'll get an error with console.log(y); At this point in time, even though y is a global variable, the variable hasn't been defined. JavaScript has just stored a function called myFunction.

If we were to do this:

var x = 1;

function myFunction(){
  y = 2;
  console.log(x);
}

myFunction();

console.log(y);

console.log(x);

Now, because of the myFunction call, the global variable y exists, and console.log(y) will work!

The Scope of Scope, or Getting Closure

One of the most powerful things about scope in JavaScript is how easily we can hide variables from the global scope but still make them available in inner scopes.

function outerFunction() {
  var innerVariable = "I'm sort of a secret.";

  return function innerScope() {
    var inaccessible = "Nothing can touch me.";

    return innerVariable;
  }
}

JavaScript has first-class functions, meaning that we can pass them around with ease. When we call outerFunction(), the returned value is another function.

Let's give it a try:

var myScope = outerFunction();

// the stringified version of `innerScope()`
myScope;

Cool! What happens if we try to call innerScope() directly?

innerScope();

This will throw the error undefined is not a function (very helpful, JavaScript). But if we call myScope (the variable to which we assigned the output of outerFunction()):

myScope();

We should see "I'm sort of a secret." returned! What happened?

Inside outerFunction(), we made the variable innerVariable available to innerScope() in what we call a closure. In this example, innerScope() remembers the environment it was created in, and it maintains references to variables declared in that environment in a closure. As we noted above, JavaScript functions have access to their entire outer scope, so the innerScope() function has access to outerFunction()'s environment and to the global (window) environment.

Note, though, that outerFunction() doesn't know anything about what's in innerScope() — the variable inaccessible is aptly named, because we can't get at its value except inside innerScope().

A Final Note (Extra Credit)

We've over-simplified the case for JavaScript for the moment. ECMAScript 6 (ES6) introduces two new declarations, let and const. Scope-wise, the difference is that let and const have block-level scope whereas var only has function-level scope. This means that declaring with let and const inside, for example, an if block will restrict the use of a variable to that if block. You can try out the following at https://babeljs.io/repl

if (true) {
  const blockVariable = "block";
  var localVariable = "local";
}

// when you run the following lines, you should see:
// "local"
// blockVariable is not defined
// on the right-hand side of the lower middle part of your screen.
console.log(localVariable);
console.log(blockVariable);

Try changing const to let — you should get the same error output.

View JS Scope on Learn.co and start learning to code for free.

js-scope-readme's People

Contributors

annjohn avatar bacitracin avatar bhollan avatar franknowinski avatar pletcher avatar victhevenot avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

js-scope-readme's Issues

block level scope

is it true ruby has block-level scope? i'm not sure, never heard that term before

Improving "The Key to Scope" section in README

screen shot 2016-04-01 at 1 09 36 am

The highlighted text in the screenshot above doesn't accurately encapsulate how scope works in JavaScript.

The var keyword does not inherently determine whether a variable is global or local, as you can define both types using var. What it does do is define what object a given variable is scoped to. If the variable is defined either in the global namespace — with or without var — or inside of a function object without using the var keyword, it is bound to the window object (the latter resulting from JavaScript's 'bubbling up' effect). If the variable is defined inside of a function expression or declaration using the var keyword, it is bound to the function object inside of which it was defined.

While the selected text may be technically valid if we're talking solely about the effect of var inside of a function, I think it misses the larger point of how scope works in JavaScript, and verbiage such as "the var keyword makes a variable have a local scope" and "var for local variables or nothing for globals" could too easily be taken out of context by a beginner.

Happy to chat about this IRL!

closures

do we want to talk about closures?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.