CSS3 Selectors and JavaScript's "this"

Mar 29, 2010
Episode 18
Nick continues coverage of selectors and demonstrates what's new in CSS3. Then, Jim demystifies the "this" variable in JavaScript.
Spotlight

Thanks to those who make Doctype possible!

CSS3 Selectors

Attribute Selectors

If you watched last week’s episode, the attribute selectors I’m about to show you should look a little familiar. Attribute selectors allow you to select an element based on the element’s attributes.

E[foo^=”bar”]

The carrot equals attribute selector allows you to grab an element based on an attribute that begins with the specified value. So for example, if you had a bunch of class names that started with the word “green” and had some text after it, you could use this selector to style them all at once.

E[foo$=”bar”]

The dollar equal selector does the opposite of the last selector. Here, you can select any elements that have attributes ending with a particular value. So for instance, if you chose to end several class names with a particular word, you could select them based on that.

E[foo*=”bar”]

Finally, with the star equal selector, you can select attributes that contain a value anywhere in them. So if you wanted to find all your alt tags that contain a word in them, this would be the selector to use.

Pseudo Classes

CSS2 already has several pseudo class selectors, but CSS3 adds a ton more.

E:last-child

In last week’s episode I talked about the first-child selector, and the last-child selector is similar. Let’s say you have an unordered list and you want to select the last item. Rather than applying a special class on the last item, it’s much cleaner to select it using the last-child pseudo class.

E:nth-child()

Next is the Nth-child pseudo class. Let’s say you had that same unordered list, and you wanted to select a list item that was somewhere in the middle. So for example, if you wanted to select the 2nd item in the list, you would apply the nth-child pseudo class to the unordered list and then type 2 as your value.

E:enabled and E:disabled

Sometimes when you’re working with forms, elements can become enabled or disabled. With the enabled and disabled CSS3 pseudo classes, you can select form elements that are in either of those two states. There’s another related pseudo class, called “checked,” which allows to select checkboxes or radio buttons that are checked.

Browser Support

CSS3 selectors are very well supported across all the “good” browsers. Internet Explorer is just OK, and IE9 should improving things, but that doesn’t come out until 2011. Until then, if you absolutely must make use of CSS3 selectors in Internet Explorer, you can use jQuery which was covered in episode 1.

Scopes and this in JavaScript

JavaScript actually has very simple rules for determining the scoping of variables.

When a variable is used inside of a function, JavaScript searches the most local function to see if that variable name is defined. If it is not, it looks at the function that surrounds the current one. If it can’t find the declaration It continues searching upwards until it finds the variable declaration.

In JavaScript, if it reaches the global scope, and still can not find the variable declaration, it implicitly declares the variable at the global scope, which is why it is important to always use the var keyword to define variables.

var color = "blue";
function introduce(){
  var name = "John";
  alert('My name is ' + name + ' and I like ' + color);
}

So, in this example, we have 2 variables, name and color. We can see that the name variable is bound in the scope of the function introduce, but color is not. we have to look up the scope chain to see that color is defined in the global scope.

We can understand how variable color is bound to by looking at the code itself. Note that color is has the value “blue” in this code, but if someone were to change the value of color to “red” and then invoke the function introduce, it will alert that I like “red”. >

This is because color inside introduce doesn’t refer to the value “blue”, but the actual variable color defined in the global.So when we change the value of colorit is reflected in the code wherever that color variable is used.

We call this Static or Lexical Scoping. All variables in JavaScript use these straightforward rules, except one. And it’s called this.

this

The this keyword is a pseudo-variable used in JavaScript to allow for some dynamic scoping. How does this work? Let’s take a look at an example.

What does this refer to inside of sayHi? Well we can see that there is no variable called this defined. The confusing thing about this is that we cannot tell by looking at the function definition what variable this will be bound to. The this variable for a function will always be bound when the function is called, not when it is defined.

function sayHi(){
  alert("Hi, I'm " + this.name + "!")
}

var john = { name: "John", sayHi: sayHi}
john.sayHi(); 

var jane = { name: "Jane", sayHi: sayHi}
john.sayHi();

sayHi();

Now we create an object john, and give it a name property, and a method sayHi, which will be the same as our sayHi function. When we call john.sayHi(), JavaScript will bind the variable this inside of sayHi to the object john. So when sayHi looks up this.name, it is actually looking up john.name.

A simple way to think of it is that this will be the same thing as the variable before the dot when the function is called as a method.

We can do the same thing and create a jane object, and it will say Jane’s name instead of John’s. Now there is only one copy of the sayHi function in all of this code, but we can make it act differently by using the this variable, and invoking sayHi as a method of different objects.

What happens if we just call sayHi, but not as a method of another object? Well, JavaScript will bind this to the global object, which is the window object in the browser. So you need to be careful about how you invoke a function which uses this

Setting this

We can actually explicitly define what this should be bound to in a function call by using the call and apply methods that are available on all functions.

function sayHi(){
  alert("Hi, I'm " + this.name + "!")
}

var john = { name: "John"}
sayHi.call(john);

Instead of assigning and calling the function as a method of the john object, we can use the call method of the sayHi function. The first argument to call is a variable that should be bound to this inside of the function. All arguments after the first will be sent as arguments to the function itself.

We could also call .apply to the sayHi function. The only difference between call, and apply is how the extra arguments are passed. With call, we pass in our arguments one by one like a normal function, but with apply, we pass additional arguments bundled together into an array.

One last thing to note is this is re-defined by JavaScript for every function definition so if you want to refer to the this of an outer function from within an inner function, you must assign this to another variable in your outer function, so that the variable can follow the normal scoping rules of variables. Often times to achieve this people will assign this to a variable that but you should use a more descriptive name if you can

function onClick(){
  // this == HTMLElement
  var that = this;

  setTimeout(function(){ // New function, new this
    // this == global object
    that.innerHTML = "Hello"
  }, 1000);
}.