Dec 05, 2014

Keeping Scopes Clean While Coding in JavaScript or CoffeeScript

blogpost cover image
As you know JS is a dynamic programming language which makes both an efficient and dangerous tool. When you are expanding someone else’s code you have to be careful not to overwrite used variables. If creating libraries or even writing a simple script it’s very important to have clean scopes to prevent overwriting variables or functions in the future. Clean scopes also mean no unnecessary global variables. In this post I will show you how to have full control while declaring your variables, functions and objects.

I would like to start this tutorial with a short example of using global and local scopes.

var global1 = 'This is global' // variable declared outside any functions is global
global2 = 'This is global' // variable not declared at all is automaticly global

f = function() {
  global3 = 'This is global' // if you don’t declare variable before you use it
                             // in a function it becomes global

  var local = 'This is local' // this variable is declared in function therefore it's local

It is good practice while coding in JS is to write all code in self-invoking anonymous function to keep your global scope clean like this:

(function() {
  // your code here

Notice the brackets at the end of the code – () is shortcut of .call(this) and executes the function.

When using CoffeeScript you don’t have to make this warping function because CoffeScript creates it by default. CoffeeScript keeps watch to make sure you don’t make an unnecessary global variable by accident. If you’re sure you want to make global variable, you have to use this. scope or simply @ which is Coffee’s shortcut.

a = 42 # local variable accessible only in this script
@b = 42 # global variable accessible in every script
this.c = 42 # global as same as ‘b’ variable
f = ->
  d = 42 # local variable accessible only in ‘f’ function

That’s the end of this little cheat sheet about scoping variables in JS and Coffee. Now some words about executing your page-specific JS in Rails application. The most common way to deal with JS is to declare all your functions in JavaScript assets files and executing them via <script> tag in html/haml views files. After reading this introduction to JS and CoffeeScript you can presume that it’s not the best way to deal with it, because every function is in a global scope and in big applications function names can create conflicts. You should use namespaces to minimize chance of accidentally overwriting a function. One of the ways of declaring name space:

some_namespace = {
  function_a: function(a, b) {
    // some code
  function_b: function() {
    // some other code
// executing your functions
@some_namespace =
  function_a: (a,b) ->
    # some code
  function_b: ->
    #some other code
# executing your functions

To make a favorable first impression of your code, name your namespaces after Rails’ controllers and functions after actions. With this approach you can easily assume in which view that function is used.

Sadly, executing those functions is still quite uncomfortable. And this where “paloma” gem comes in. With this gem you only have to declare yours Rail’s controllers in yours JS files and attach functions to actions. Here is a full documentation of the paloma gem with some nice examples. With Paloma it’s also possible to pass variables from Ruby to JS in a very convenient way.

At the end of this post I would like to show you how to code function shared between many actions in a clean way that is consistent with everything I wrote earlier.

UsersController = Paloma.controller 'Users'

welcome = (user) ->
  alert "Hi #{user}"

some_kindness = (user) ->
  alert "#{user},  how are you?"

UsersController::show = -> # same as
  user = 'foo'
  welcome user
  some_kindness user

UsersController::index = ->
  user = 'foo'
  welcome user

As you can see using scopes in a sensible way isn’t very difficult and it can protect you from possible future complications. When coding in JS always remember to declare your variables, functions and object in a deliberate way.