Duplo

Building Blocks & Learning Experiences

Browsing Posts tagged javascript

… it has function scope.  Okay, I get that, but apparently I hadn’t totally wrapped my head around just what that means.  In essence, it means that all variables that have a declaration in the function, are declared, regardless of whether or not the line of code which declares them would be executed.  Given the following code:

var foo = "bar";

function test() {
  console.debug("foo is (1st time)" + foo);
  if (false) {
    var foo = "baz";
  }
  console.debug("foo is (2nd time)" + foo);
}

Your console will show something like this:

foo is (1st time) undefined
foo is (2nd time) undefined

Which is a little weird since the local declaration of foo was never executed.  A quick search didn’t turn up any promising hits, but I imagine that there must be a preprocessing step that executes all variable declarations before the function is run.  The very similar function below (diffs in bold):

var foo = "bar";

function test() {
  console.debug("foo is (1st time)" + foo);
  if ("undefined" == typeof(foo)) {
    var foo = "baz";
  }
  console.debug("foo is (2nd time)" + foo);
}

Yields:

foo is (1st time) undefined
foo is (2nd time) baz

A more intentional use is probably (diffs also in bold):

var foo = "bar";

function test() {
  console.debug("foo is (1st time)" + foo);
  if ("undefined" == typeof(foo)) {
    foo = "baz";
  }
  console.debug("foo is (2nd time)" + foo);
}

Which has output:

foo is (1st time) bar
foo is (2nd time) bar

So this isn’t anything groundbreaking, or even weird.  It’s clearly defined1, and discussed2, but the consequences eluded me for about an hour last night.  Hopefully by writing this article, I’ll remember for next time.

  1. http://docstore.mik.ua/orelly/webprog/jscript/ch04_03.htm#jscript4-CHP-4-SECT-3.1 []
  2. http://stackoverflow.com/questions/1711173/declaration-for-variable-in-while-condition-in-javascript []

Rails’s JavaScript generator provides some great functionality. But unfortunately, one of the things it can’t do for you, is generate JavaScript conditionally, based on the page’s content. The reason is simply that the page’s content doesn’t exist at the time the conditional in your code was executed. I wanted to do something like the following:

if page["album_1_rating"]
  page["album_1_rating"].visual_effect(:highlight)
end

As I said, at the time the if statement above is executed, there is no HTML file yet, so the generator can’t possibly know if the element referenced will exist in the file or not. In fact, page["album_1_rating"] is a ActionView::Helpers::JavaScriptElementProxy object, which is not false, so the if statement will always execute. This wasn’t what I wanted. So I came up with something that would work. I added the following method to lib/prototype_helper_hacks.rb, then required it in config/environment.rb.

def if_element(id, &block)
  self << "if ($(\"#{id}\")) {"
  block.call(self[id])
  self << "}"
end

This lets me do things like this in my views:

page.if_element("album_1_rating") do |element|
  element.visual_effect(:highlight)
end

That made me happy.

In thinking more about the situation, I’m not sure this is really such a great method. It works, but I can’t help but feel there’s some better way of going about this. I could simply use the page append method, to do something like:

page << "if ($(id)) {"
  page["album_1_rating"].visual_effect(:highlight)
page << "}"

But at least if nothing else, my if_element method makes this a lot cleaner looking. So really this is just some syntactic sugar, and I wish at least I could make it more of a general purpose if statement, but since I don’t need that sort of funcationality at this point, YAGNI tells me to leave that hurdle for another day.