I'd also love to hear your feedback and suggestions how I could make it better!
Wednesday, August 14, 2013
Indiana Jones and the Temple of DOM Slides
I recently gave a talk at ThatConference 2013 titled "Indiana Jones and the Temple of DOM" in which I received a lot of requests to share the slides from attendees so I figured I'd share them with everyone. I'll likely turn this into a video that I'll post online but until I get to that please enjoy the slides here:
Labels:
JavaScript
Thursday, August 1, 2013
Sessions I'm Excited to See at ThatConference 2013
With ThatConference right around the corner I thought I'd share what sessions I'm excited about attending. There is a ton of great content to choose from so making my decisions was quite hard. I ended up going with with a focus on Angular JS and CSS.
What sessions are you most looking forward to?
What sessions are you most looking forward to?
Indiana Jones and the Temple of DOM
me
How could I expect people to want to come to my presentation if I wasn't excited about it myself. I think I've put together a pretty fun presentation that I hope everyone will enjoy.
Angular JS Crash Course
Ian Muir
I've been learning a lot of Ember.js lately and I'm very happy with it, however it seems like a lot of people are turning to Angular lately. I'm really looking forward to seeing what Angular has to offer.
Tubing Down the Asset Pipeline in Node.js
Jacob Gable
I've used Node for a few things, however, I'd love to learn a lot more about it.
**JavaScript broke my heart. And then I met AngularJS.
Joe Eams
While I'm sad that there are no Ember talks at ThatConference, I'm glad that I'll get to take a longer look at Angular. Perhaps I'm missing something and I'll fall in love with it as much as everybody else after I see more of it.
Front End Legos: Better Design with Reusable HTML & CSS
Shay Howe
I've been spending a lot of time properly learning CSS lately. That means less hacks and more of being able to understand and explain what I'm doing. This means immersing myself into CSS as much as I can so this one is a no-brainer for me.
**Adventures in CSS: Advanced Techniques for a Fabulous Front-End
Amelia Marschall-Miller
This one sounds really fun! It sounds like I'm going to learn a lot from this session and hopefully bring back some new tools to use.
Laniard schmaniard! Spruce Up Your Existing Website With HTML5, CSS3, and Responsive Design
Wolf Loescher, Bertine Buchan
Responsive design is so hot right now. I know enough about it, and have worked on a few responsive sites, but I can always learn more. This session
Wednesday, June 26, 2013
A Look Into How Parameters Are Passed In JavaScript
I recently came across a question on StackOverflow about how JavaScript handles parameters, if they are passed by value or by reference. There seemed to be a lot of confusion and misinformation about what is actually happening behind the scenes.
TLDR; All arguments are passed by value in JavaScript, however, when dealing with non-primitive datatypes like objects and arrays a variable is created that points to the location of the object memory that is then is passed into the function. This means that changes to the variable inside the function will affect the original object's values. Once the argument is reassigned (e.g.
When we do this the variable obj is really just a reference to a location in memory that holds the actual object:
If a function is invoked and obj is passed into the function as an argument that reference is copied and passed into the function. In other words, the reference is being passed by value:
This is where things start to get interesting. The pointer to the object is passed into the function call by value. In other words, a copy of the pointer is created and passed into the function call. We now have two variables that point to the same object:
At this point if the argument is modified inside the function call the changes will be reflected on the original varialbe outside of the function call. However if the argument is reassigned inside the function the reference will no longer point to the original object and changes inside the function will no longer affect the variable outside the function call:
After reassignment our objects in memory look like this:
TLDR; All arguments are passed by value in JavaScript, however, when dealing with non-primitive datatypes like objects and arrays a variable is created that points to the location of the object memory that is then is passed into the function. This means that changes to the variable inside the function will affect the original object's values. Once the argument is reassigned (e.g.
arg = {}
) the variable now has the location of the new object in it so the original variable is no longer changed when the value changes.By Reference vs. By Value
Let's start be defining exactly what by passing a variable reference and by value actually means.By Reference
If a parameter is being passed into a function by reference it means that only a reference to the variable is being passed into the function is passed as the argument. The variable in the function and the variable that is passed into the function are actually pointing to the same location in memory. Put simply, if the value is modified inside the function the original value is also changed.By Value
If a value is being passed into a function by value it means that a copy of the variable is being passed into the function. The variable in the function and the variable that is passed into the function are two separate variables. Put simply, if the value is modified inside a function the original value will remain unchanged.By The Book
According to MDN:The parameters of a function call are the function's arguments. Arguments are passed to functions by value. If the function changes the value of an argument, this change is not reflected globally or in the calling function. However, object references are values, too, and they are special: if the function changes the referred object's properties, that change is visible outside the function.
Huh?
Let me try to describe this with pictures. First let's create a variable that is a simple object literal:var obj = { foo : 'foo' };
When we do this the variable obj is really just a reference to a location in memory that holds the actual object:
If a function is invoked and obj is passed into the function as an argument that reference is copied and passed into the function. In other words, the reference is being passed by value:
doSomething( obj );
This is where things start to get interesting. The pointer to the object is passed into the function call by value. In other words, a copy of the pointer is created and passed into the function call. We now have two variables that point to the same object:
At this point if the argument is modified inside the function call the changes will be reflected on the original varialbe outside of the function call. However if the argument is reassigned inside the function the reference will no longer point to the original object and changes inside the function will no longer affect the variable outside the function call:
function doSomething( obj ){
obj = { baz : 'baz' }; //reassigns the pointer
}
After reassignment our objects in memory look like this:
What about primitives?
At this point you might be asking yourself, what about primitive datatypes like strings and numbers? The truth is that the point is quite moot since primitives are immutable, which means they cannot be changed. When a primitive is changed a new variable is created and reassigned to the original. Since this reassignment happens every time a primitive is changed it doesn't matter, the primitive will never point to the original location in memory once its changed so you'll always end up with the same behavior as if it was being passed by value.Friday, May 24, 2013
JavaScript Inheritance - HowTo Shoot Yourself In the Foot With Prototypes!
One thing that has long eluded me is a good understanding how JavaScript inheritance works when the parent constructor function has instance properties. The following code has a Widget parent class that has a messages properties. In this case we want each instance to be initialized with an empty messages array:
Before we set SubWidget's prototype to a new instance of our Prototype constructor on line 12 we get an object graph that looks like this:
Now our object graph looks like this:
JS Bin
JS Bin
After the code on line 12 is run the new keyword does its magic and ties everything together creating a new inheritance tree and a new scope. Our object graph now looks something like this:
Do you see what the problem is yet? Lets create some instances of our subclass to highlight the issue:
Now our object graph looks like this:
Before I talk about the real problem here I'd like to step back and talk about the "type" property on the widget's constructor. If it is not initialized by assignment each instance's "type" property actually points to the constructor's "type" property. However, once it is initialized by assigning a value to like so: sub1.type = 'Fuzzy Bunny' it becomes a property of the instance, as shown in the new object graph:
Our bug should start to become clear now. Let's look at the value of both sub1 and sub2's messages array:
JS Bin
Each object is sharing the same messages array! It would be tempting to fix this by adding another property to the SubWidget constructor like so:
However, what if we wanted to create other objects that extended Widget? That new object would also need a messages array and pretty soon we have code that is a nightmare to maintain and extend. Additionally, what if we wanted to add other properties to the Widget constcutor that were initialized when instances of its sub classes were constructed? This isn't very reusable or flexible solution.
In order to properly fix this all that needs to be done is to add a single line of code to our SubWidget constructor that will invoke the Widget constructor with the same scope of our SubWidget constructor:
Now when we create new objects each instance has a new instance of the messages array:
JS Bin
Now our object graph is correct:
Labels:
JavaScript
Monday, May 13, 2013
Warm and Fuzzies
Be honest, how many times have you looked at someone else's code and said something like, "Who wrote this? They msut be an idiot!" or something to that effect? I do it all the time, and if my ears aren't deceiving me I hear others doing it all the time as well. Sometimes this kind of response is justified, like the time when I came across a piece of code that queried a table and used a for loop to filter the rows instead of using a WHERE clause. However, sometimes it's our own insecurities and shortsightedness that triggers this reaction and stops us from looking at things more objectively.
Today I found a piece of code that at first appeared to be completely backwards and I started going to the familiar place of negativity. I was ready to rip it out and reactor it till it was perfect, my perfect. Then I'd scour commit logs to find out who wrote such bad code. I'm not sure what happened but something inside me decided to take a step back and look at the code and do a little research first. After a few minutes I actually learned that the was actually written quite cleverly. I still scoured the commit logs to find out who wrote it but then I took a different approach. I chose to open up my e-mail client and wrote the developer a short e-mail telling them that I really liked the way they wrote that piece of code and that I learned something from it, and you know what, it felt pretty darn good.
It's so easy in the software development industry to focus on the negative, we are surrounded by it most of the time. The users of the software we write rarely communicate with us unless it's to tell us that something went wrong or doesn't work the way they expect. Even our friends and family encourage this sort of reaction by coming to us with their virus-laden computers and never asking to see what cool stuff we've been working on. We also love to look at other people's code and find the slightest problems. Raise your hand if you've scoured someones blog post looking for poorly written code? I have. It makes me feel like a smarter person when I can find flaws in other people's code, however it still doesn't make me feel any better about the code I've written. My point is, that it's super easy to focus on the negative to make us briefly feel better about ourselves. However, my experience today has taught me that it feels FAR better to focus on the positive aspects of others code and to take a few minutes to tell the other developer that you like what they've written as well.
Today I found a piece of code that at first appeared to be completely backwards and I started going to the familiar place of negativity. I was ready to rip it out and reactor it till it was perfect, my perfect. Then I'd scour commit logs to find out who wrote such bad code. I'm not sure what happened but something inside me decided to take a step back and look at the code and do a little research first. After a few minutes I actually learned that the was actually written quite cleverly. I still scoured the commit logs to find out who wrote it but then I took a different approach. I chose to open up my e-mail client and wrote the developer a short e-mail telling them that I really liked the way they wrote that piece of code and that I learned something from it, and you know what, it felt pretty darn good.
It's so easy in the software development industry to focus on the negative, we are surrounded by it most of the time. The users of the software we write rarely communicate with us unless it's to tell us that something went wrong or doesn't work the way they expect. Even our friends and family encourage this sort of reaction by coming to us with their virus-laden computers and never asking to see what cool stuff we've been working on. We also love to look at other people's code and find the slightest problems. Raise your hand if you've scoured someones blog post looking for poorly written code? I have. It makes me feel like a smarter person when I can find flaws in other people's code, however it still doesn't make me feel any better about the code I've written. My point is, that it's super easy to focus on the negative to make us briefly feel better about ourselves. However, my experience today has taught me that it feels FAR better to focus on the positive aspects of others code and to take a few minutes to tell the other developer that you like what they've written as well.
Friday, May 10, 2013
cf.Objective() Session: An Introduction to AMD With RequireJS
AMD modules have been the subject of a lot of talk lately, some people really like them, some people hate them. Regardless, there is a lot of AMD JavaScript code being written these days and it would behoove any JavaScript developer to have a working knowledge of AMD and RequireJS in their toolbelt. Personally, what I love about AMD modules is that I don't have to worry about loading my script files in the right order in my markup, I also love that each module's dependencies are clearly defined within its source code. Writing decoupled and reusable "micro" applications within a RequireJS application becomes super easy.
The barrier of entry to AMD and RequireJS can sometimes look a bit high when first exposed to the concepts, and indeed it may be if you are still putting all your code inside your $( document ).ready() function. However, if you've been using a MV* framework, or if you've been using Rebecca Murphey's Object Pattern to organize your code, getting started with AMD will be super easy in most cases.
This session will help you get acquainted with writing AMD modules, adding RequireJS to your project, and using the R.js optimizer to optimize your RequireJS source code. After it you should have a good understanding of how powerful modular JavaScript code can be and have a good working understanding of the moving parts of a RequireJS application so you can go home and start adding RequireJS to your next project.
The best part is, if you attend my session (which is scheduled in the last time slot of the conference) there's a chance we will get to site down one-on-one and talk about Require and AMD.
Thursday, May 9, 2013
cf.Objective() Session: The Art of JavaScript, Level Up Your Skills In 60 Minutes
JavaScript is a funny language, many really smart programmers never really take the time to learn it. They learn how to write jQuery code, but never learn the beauty of the language beneath it. I blame JavaScirpts trouble past for this, if you've ever had to debug JavaScript on IE6 you know what I mean.
This session is for developers who know JavaScript but dont really know JavaScript. If you are unsure about attending ask yourself these following questions, if you answer is "no" to any of them, you might want to attend this session:
- What is the difference between
var func = function(){}
andfunction func(){}
? - There is a subtle difference between lexical scoping and closures, what is it?
- What [7] == 7 is and why?
- What each log statement produces when running the following code:
- What
undefined || 'foo'
returns? - Why
foo.constructor === Foo
is false when running the following code:
Monday, May 6, 2013
I'll Be Speaking About The DOM At ThatConferenece In August
I'm really excited to have been chosen as a speaker for this year's ThatConference conference in the Wisconsin Dells in August. If you haven't heard of ThatConference before its billed as "Summer Camp For Geeks" and prides itself on being a relaxed, fun, and wide-ranging conference. It's also one of the few conferences where there are specific family friendly activities planned during the conference (being held at an indoor water park doesn't hurt in this regard).
With tracks on mobile, web, cloud, and "other" there each time slot is packed with interesting sessions from some top notch speakers. I'm extremely honored to be amongst such amazing company. One session I'd like to draw attention to is Mike Rohde's "Sketchnote Workshop". I have the pleasure to work with Mike and have been through his workshop. Even if you are a terrible drawer (like myself) you'll take away a lot of excellent information from this session.
My session is titled "Indiana Jones and the Temple of DOM" and will focus on using the browser's native Document API's to select and manipulate a page's contents without the help of a library like jQuery. Why is this important? Here I defer to Remy Sharp's "I know jQuery. Now What?" TLDR, while jQuery super awesome every project doesn't need to start with immediately adding jQuery for it. There are many cases where all of the events your project needs are already built right into the web Browser.
With tracks on mobile, web, cloud, and "other" there each time slot is packed with interesting sessions from some top notch speakers. I'm extremely honored to be amongst such amazing company. One session I'd like to draw attention to is Mike Rohde's "Sketchnote Workshop". I have the pleasure to work with Mike and have been through his workshop. Even if you are a terrible drawer (like myself) you'll take away a lot of excellent information from this session.
My session is titled "Indiana Jones and the Temple of DOM" and will focus on using the browser's native Document API's to select and manipulate a page's contents without the help of a library like jQuery. Why is this important? Here I defer to Remy Sharp's "I know jQuery. Now What?" TLDR, while jQuery super awesome every project doesn't need to start with immediately adding jQuery for it. There are many cases where all of the events your project needs are already built right into the web Browser.
Labels:
JavaScript,
Speaking
Friday, April 19, 2013
Kick Ass Cross-Platform Workflow With Grunt
My apologies for the vulgar title, but Grunt has me pretty excited these Days. I work on a Mac at home and on a Windows machine at work, this means that cross platform tools are extremely important to my workflow. I hate having to use CodeKit at home and Scout at work to compile my .scss files. Additionally tying a project to a platform specific tool means that its that much harder for others to get involved. Lately I've become a bit of a GruntJS fanboy, not only does it
meet my cross platform needs, but it cuts down the number of tools I need to use because it does so many things.
meet my cross platform needs, but it cuts down the number of tools I need to use because it does so many things.
The watch plugin has made my workflow even better by allowing me to run Grunt tasks when files in my project are added, changed, or deleted. With watch whenever a .less or .scss file gets updated Grunt will see the change and automatically compile the file for me. This post will walk you through installing watch and a compiler plugin and addresses a few of the gotcha's I ran into along the way.
Install Grunt
Duh. Installing Grunt is out of the scope of this post but the Grunt Homepage does an excellent job of walking you through the intstall (here's a hint you'll need to install Node too). It's important to note here that version 0.4.0 and newer of Grunt works much differently than prior versions, and that the examples in this post will only work with version 0.4.0 or newer of Grunt.
Install Compiler Plugin
Once you have Grunt installed the next step is to get a compiler installed (since my current project is using Twitter Bootstrap I'm going to walk through setting up the LESS compiler in this post, however the process is the same for any other compiler).
To find the plugin you need the Grunt plugin page has a list of plugin's available for Grunt. Clicking on a plugin will send you to the plugin's NPM page where you'll find documentation on the plugin and the command needed to install the plugin.
A quick not on plugins. There are two type's of plugins "contrib" and "non-contrib". The "contrib" plugins are official plugins and are maintained by the Grunt team. I always prefer to use the "contrib" plugins whenever I can since they are generally better maintained and supported.
To install the Grunt LESS plugin:
- open the terminal and navigate to the project's root directory in a terminal
- type in
npm install grunt-contrib-less --save-dev
in the command line - hit enter
It really is that simple. The
--save-dev
command will ensure that the plugin, and its version, are added to your package.json file.
If you are not using a package.json file I strongly suggest you start. Using a package.json file means that you don't have to add your node_modules code to your distributions, users simply have to type in npm install
in a terminal to install the dependencies.
Install The Watch Plugin
The next step is simple, install the watch plugin. While still in your project's root directory in the terminal type in:
npm install grunt-contrib-watch --save-dev
Configure your Gruntfile
Before you go any further read the "Configuring Tasks" section of the Grunt website. This will save you a lot of time in the long run, I promise. Many plugins will assume that you know how to configure tasks and will leave these details out of their documentation.
A few points of frustration that I've run into that are covered in "Configuring Tasks" are:
- Specifying the task name to configure. Typically the task name is the same as your plugin name.
- Specifying source and destination files. This is almost always left out of documentation and is almost always extremely important since a lot of plugins deal with manipulating files.
- Targets and how to use them (some plugins require targets and some do not, the bad news is that it's usually poorly documented whether a plugin uses them or not).
Configure the Compiler
Now that I've gotten that out of the way, lets walk through setting up the LESS compiler in the Gruntfile. In order to add a LESS task to the Gruntfile add a property named
less
to the object that is passed into the grunt.initConfig()
function. Since the LESS plugin requires targets (it will fail without them) I am going to specify a development
target in the configuration.A quick note on targets: if no target is specified when register or running a task ALL targets for a task will be executed.
The
development
target in this example only uses properties: src
and dest.
These properties are used to tell the LESS task where to find the .less
files and where to put the compiled .css file. The syntax /**.*.less
tells Grunt to get all files with a .less
extension in the less
directory and all of its sub-directories.
grunt.initConfig({ less: { development : { src : [ 'less/**/*.less' ], dest : 'css/compiled-better.css' } } )};
Configure Watch
The watch plugin does exactly what it's name implies, watches a directory for changes. Since this plugin does not require the use of targets I'll skip them in this example and will put properties directly under the watch task. At a minimum watch needs two properties:
files
and tasks
. The files property tells watch what files to look for changes for, and tasks property tells watch what tasks to run when a change is detected.
The example below is telling watch to listen for any changes to files with a
.less
extension in the less
folder and any of its sub-folders and to run the less
task when a change is detected.watch: { files : [ 'less/**/*.less' ], tasks : [ 'less' ] }
Register Tasks
The last step in configuring your Gruntfile is to register the
less
and watch
tasks. To do this the following lines are added to the Gruntfile immediately after the grunt.initConfig()
call:grunt.initConfig({
...
});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-contrib-watch');
Run the Watch Task
The last step is to run the watch task. In a terminal window once again navigate to the root directory of the project and enter:
grunt watch
Grunt will run the watch task which will then tell you that its "
Waiting...".
When a change is detected Grunt will spring into action and you'll see the normal Grunt messages start to appear in the console. When the tasks are complete watch will go back to the Waiting...
status.
Labels:
Grunt,
JavaScript
Monday, April 15, 2013
A Quick Look at e.target and e.currentTarget. And Bubbling.
Since jQuery makes such easy work of event listeners it's sometimes easy to ignore some of the finer points of JavaScripts events. Two things that I often forget is the difference between the e.target and e.currentTarget properties of the event object that gets passed into a event callback. Hopefully writing this post will help the concepts stick in my head.
The reason we need both of these properties is because of event bubbling. Event bubbling is when a event travels up the DOM, until it reaches the document node. Lets say we have a DOM tree that looks like this:
document
|
|--div
| |
| |--span
| | |
| | |--a
Here we have a document node with a child of a div with a child of a span with a child of an anchor. When the anchor is clicked the any event listeners for the anchor are triggered, then the event bubbles up to it's parent, the span and any of it's event listeners are triggered, then the event bubbles up to the div where its event listeners are triggered, and finally the event bubbles up to the document element where any of it's event listeners are triggered.
Assuming that the span and div have a margin, padding, and border of 0 whenever a user clicks on the link the event the target property of the event that is triggered on the anchor, span, div and document will always be the anchor, since this is where the event originated. The currentTarget property will always be the element that is listening for the event.
The following code shows event listeners on 4 different objects, however when a user clicks on the anchor link the target will be the same for each event listener.
Open up your console and run the following example, paying close attention to the order the events fire as they bubble up the dom:
JS Bin
The reason we need both of these properties is because of event bubbling. Event bubbling is when a event travels up the DOM, until it reaches the document node. Lets say we have a DOM tree that looks like this:
document
|
|--div
| |
| |--span
| | |
| | |--a
Here we have a document node with a child of a div with a child of a span with a child of an anchor. When the anchor is clicked the any event listeners for the anchor are triggered, then the event bubbles up to it's parent, the span and any of it's event listeners are triggered, then the event bubbles up to the div where its event listeners are triggered, and finally the event bubbles up to the document element where any of it's event listeners are triggered.
Assuming that the span and div have a margin, padding, and border of 0 whenever a user clicks on the link the event the target property of the event that is triggered on the anchor, span, div and document will always be the anchor, since this is where the event originated. The currentTarget property will always be the element that is listening for the event.
The following code shows event listeners on 4 different objects, however when a user clicks on the anchor link the target will be the same for each event listener.
Open up your console and run the following example, paying close attention to the order the events fire as they bubble up the dom:
JS Bin
Labels:
DOM,
JavaScript
Wednesday, March 13, 2013
Exploring jQuery Queues
This week I ran into an interesting issue at work. There was an event that was triggered when a custom font loaded that added a fixed position element to an item in a container. Another team wrote some code that caused that container to animate when the page loaded. Sometimes the fixed position element would get placed randomly inside that container because the event was firing before the animation completed. Instead of tightly coupling the animation with the positioning of the element I decided to inspect the animating element's FX queue when the event was triggered to make sure that the element was not in the process of moving when it was added.
Queues in jQuery are a useful way to add a list functions to an element that should be executed in a particular order. The real benefit is that queues give you full control of when each item in the queue is invoked using the
dequeue
method. If you've used a jQuery animation function you've already used the jQuery fx queue. What a lot of people don't know is that jQuery provides a nice API for inspecting and manipulating queues.
Lets take a look at the typical use case for a jQuery queue; adding multiple animations to an element:
Demo:
JS Bin
When this code is executed each function is invoked one immediately right after the other. However, each animation is NOT performed instantly, each animation is added to the elements fx queue. When each animation is finished the next animation in the queue is invoked.
One interesting thing to note about the fx queue is that calling the
stop()
method on an element that is animating will only stop the current animation in the queue and immediately call the next animation in the queue. In order to truly stop all of the the animations the element's queue must be cleared as well.
In order to modify the first example to stop all animations when an element is clicked the following code is needed:
Demo:
JS Bin
Delaying And Creating Queues
Custom queues can be created on any elements by passing in a name to the queue call. In addition any queue's execution can be delayed when it is dequeued by using the
delay( delayMs, queueName )
method. It's important to note that the delays are added to the queue itself so they need to be added to the queue before the function that you want delayed, however calling dequeue will trigger the delay and invoke the next callback from the queue. This timer will not start until dequeue()
is called on the element's queue.
In the following example the queue's execution will be delayed by 1 second, an item will be added to the element, the queue will be delayed by another half second, another item will be appended to the element, the queue is then delayed for another second, and finally another item will be added to the element. The first item in the queue will be invoked in the
$.ready()
function and each callback in the queue will dequeue
the next item in the queue.
Demo:
JS Bin
What makes custom queues with delays an attractive alternative to setTimeout or setInterval is that each item in the queue can have a different delay time before it is invoked.
Labels:
JavaScript,
jQuery
Wednesday, February 27, 2013
Playing with ECMAScript.Harmony Modules using Traceur
As aI was a preparing a presentation on AMD and RequireJS I started looking ahead at the modules proposed for ECMAScript.Harmony. In Addy Osmani's article Writing Modular JavaScript With AMD, CommonJS & ES Harmony he mentioned called Traceur which is a JavaScript compiler for ECMAScript Harmony syntax. This allows developers to give the future of JavaScript a test drive today.
One of the new features coming in Harmony that has me excited is modules. Modules will be a way to encapsulate code and explicitly define its dependencies and public API. ES Harmony gives us three new keywords for modules:
In addition Harmony modules:
Now that we have a compiler in place we just need some code for it to compile. To do this simply create a script block with a type of
When the page loads Traceur will compile your Harmony code to JavaScript that works in today's modern browsers.
For your convince I've created a JS Bin with Traceur ready to go on JS Bin. In addition there is an online compiler you can use here: http://traceur-compiler.googlecode.com/git/demo/repl.html
Now that we have an environment that supports Harmony to work in lets take a look at modules.
First I'd like to point modules aren't meant to be classes, there the
Even though a module does not get a new execution context , it does get a new static scope. In the following code I am creating a new module called carFactory that exports a variable named ford into the global namespace. Calling ford.wheels results in '4' and trying to access carFactory's internal wheels variable results in an error:
JS Bin
Its also important to note that doing an
A module can also have multiple exports as shown in the following code (note the syntax for importing multiple exports in a single statement):
JS Bin
A module also doesn't only have to export objects, it can export anything:
JS Bin
Variables that are imported can also renamed the from modules using the following syntax:
JS Bin
Lastly modules can be nexted. Nested modules have privileged access to their parent modules scope. Nested modules are also private to their parent modules scope unless they are explicitly exported. Here is an example of a public nested module that accesses its parents scope:
JS Bin
One of the new features coming in Harmony that has me excited is modules. Modules will be a way to encapsulate code and explicitly define its dependencies and public API. ES Harmony gives us three new keywords for modules:
module
, import
, and export
. The module
keyword is used to initialize a new module, the import
keyword declares dependencies to import from a module into a context, and the export
keyword explicitly declares public properties that will be available for other modules to import.In addition Harmony modules:
- are statically scoped
- have the
this
keyword bound to the global object
Traceur
Before we are able to write modules today we'll need an environment that supports Harmony syntax. For this we'll use Google's Traceur compiler. In order to implement Traceur you'll need three things:- Traceur library file
- Traceur bootstrap file
- Harmony code
Now that we have a compiler in place we just need some code for it to compile. To do this simply create a script block with a type of
script/traceur
.When the page loads Traceur will compile your Harmony code to JavaScript that works in today's modern browsers.
For your convince I've created a JS Bin with Traceur ready to go on JS Bin. In addition there is an online compiler you can use here: http://traceur-compiler.googlecode.com/git/demo/repl.html
Now that we have an environment that supports Harmony to work in lets take a look at modules.
Playing With Modules
First I'd like to point modules aren't meant to be classes, there the
class
keyword for that. According to the ECMAScript Wiki modules are a"Standardized mechanism for creating libraries"Modules do not create a new execution context, the
this
keyword in a module is bound to the global object. Looking at the code that Traceur outputs for a simple module
definition shows this:Even though a module does not get a new execution context , it does get a new static scope. In the following code I am creating a new module called carFactory that exports a variable named ford into the global namespace. Calling ford.wheels results in '4' and trying to access carFactory's internal wheels variable results in an error:
JS Bin
Its also important to note that doing an
import *
will import the variables from the modules with the same names the have in the module.A module can also have multiple exports as shown in the following code (note the syntax for importing multiple exports in a single statement):
JS Bin
A module also doesn't only have to export objects, it can export anything:
JS Bin
Variables that are imported can also renamed the from modules using the following syntax:
JS Bin
Lastly modules can be nexted. Nested modules have privileged access to their parent modules scope. Nested modules are also private to their parent modules scope unless they are explicitly exported. Here is an example of a public nested module that accesses its parents scope:
JS Bin
Conclusion
Modules in Harmony look like they are going to be very useful and there's a lot you can do with them. They help reduce the need for the overuse of the function keyword and reduce the need for patterns like AMD and complex loaders RequireJS and CurlJS (of which I am currently a huge fan). For more reading on modules I suggest checking out the modules section on the ECMAScript Harmony WIKI.
Labels:
ECMAScript Harmony,
JavaScript
Subscribe to:
Posts (Atom)