Thursday, May 8, 2014

By value or reference?

In JavaScript writing functions is easy. No need to declare return type, no need for argument types, In fact you don't even need to declare arguments! One might argue if all this freedom is actually a good thing. Freedom or not, it is important to understand the JS very basics and understand if what we pass into functions is passed by value or reference.

If you are familiar with Java the behaviour in JS will make sense to you. For all those confused however about how arguments are passed into functions I put together quick example that I hope is self explanatory. Consider the code:

var a = 100,
    b = "Homer",
    c = {
        firstName: "Homer"
    },
    d = {
        firstName: "Homer"
    },
    e = {
        firstName: "Homer"
    },
    f = {
        firstName: "Homer"
    }

function changeName(a1, a2, a3, a4, a5, a6) {
    a1 = 200;
    a2 = "Bart";
    a3.firstName = "Bart";
    a4 = {
        firstName: "Bart"
    };
    delete a5.firstName;
    delete a6;
}

changeName(a, b, c, d, e, f);
// output
console.log("a1:"+a); // 100
console.log("a2:"+b); // Homer
console.log("a3:"+c.firstName); // Bart
console.log("a4:"+d.firstName); // Homer
console.log("a5:"+e.firstName); // undefined
console.log("a6:"+f); // object


Ok, a and b are primitive types and these are obviously passed by value. References to objects are also passed by value. Confused? Let me explain..

Lets start with c, its a3 inside of function. Its an objects reference passed into a function. Inside we modify its property and it does modify original object c that a3 references.

Now da4 argument inside the function. Again reference to object with firstName property "Homer" is passed (by value) into a function as a4 argument. Inside the function we assign other object to a4 argument. From now on a4 is a reference to different object. Modify it all you want, d from outside won't be touched.

e and f are straightforward really. In case of a5 reference to firstName is deleted and in case of a6 the a6 reference pointing to original object is deleted. Original object stays however and can be accessed by still existing reference f from outside of function.

Understanding of all this is pretty fundamental I believe and getting it wrong might result in bugs and confusion. Luckily for us all its also fairly easy concept to grasp and as easy to experiment with.

Wednesday, May 7, 2014

jQuery and Array-like objects in JavaScript

JavaScript with its closures, prototypal inheritance etc. is not the easiest language to learn. Knowing certain topics is very important in effective writing and debugging JS code. I believe that Array-like objects is one of those concepts that everyone should get familiar with. Where can we find such thing? arguments accessible inside of functions is one example. jQuery returns such animal when you call $(“someSelector”). It looks like Array, behaves (in some cases) like Array, but its not Array. Try:

var a={},b=$(“div”), c=[],d=new Array();

a instanceof Array // outputs false (duh..)
b instanceof Array // outputs false
c instanceof Array // outputs true
d instanceof Array // outputs true


c and d are arrays, a and b not so much though. a is self explanatory, its an object literal. b is Array-like object jQuery returns.

As a is furthest from what Array should look like lets try to make it closer to what arrays are. Start from beginning and attach few properties to it e.g.:

a={ 1:”first”, 2:”second”};

Now calling (e.g. in Chrome dev tools):

a

Will output:

Object {1: "first", 2: "second"}

And calling:

a[1] // outputs first

a[2] // outputs second


However:

a.length

Outputs:

undefined

And for a good reason. It is still plain object and length property doesn't exists. Ok, so lets fake it till we make it and lets add:

a.length=2;

Now calling a from console will output:

Object {1: "first", 2: "second", length: 2}

True Arrays also have number of methods so lets add some and see what happens:

a.push=function() {}

Outputs:

Object {1: "first", 2: "second", length: 2, push: function}

Not much change. The trick lies in splice method. Simply add:

a.splice=function() {}

and voila! Calling a will output:

[undefined × 1, "first"]

Now, look at our original object. Its missing “0” element hence undefined in output above. Also “second” is missing as our length was set to 2 only.

Now, can we make it even more Array-like? Sure we can! Our splice and push implementations are empty so lets fill one in, e.g.:

a.push=function(el) {
// here you can extend implementation or not, then we call Arrays push
Array.prototype.push.call(this,el);
}


Now try:

a.push(“third”);

And call:

a

Result will be:

[undefined × 1, "first", "third"]

Calling a.length will return:

3

So third element was added to our fake array. Even length property increased by one. Hows that for array? :)

All good. We got ourselves Array-Like object. a instanceof Array will still return false, but its close.

As you see jQuery isn't using any sort of black magic, and I hope this gives you better understanding of Array-like objects that you often see in JavaScript. This is only the beginning however and if you are brave and want to learn more there is no better way then try it for yourself e.g. play around with a.__proto__=[].__proto__ and var b={};b.__proto__.{}.__proto__ and such. Or try removing splice from jQuery Array-like object or .. ok I better stop now but TRY, all these are fun too!

Wednesday, February 26, 2014

Testing window.scroll with QUnit/Jasmine

So you have to write set of tests for your code. Lets say it modifies evilGlobal variable when window is scrolled past certain point, e.g.:

var evilGlobal=false;

$(window).on("scroll.singleJob", function(e) {
if (window.scrollY > 100) 
{
evilGlobal = true;
 }
});

Say you using either QUnit or Jasmine (I will provide examples for both) to write your tests and so you got yourself nice fixture setup:

<div style="padding-top: 0px;height: 20000px;">
        Very tall content
</div>

HTML seems straightforward so you put your test together in no time. Using QUnit it might look something like:

test("sets evil to true", function() {

window.scroll(0, 1000);
ok(evilGlobal, "test 1 was great success!!!");

});

Jasmine version:

it("sets evil to true", function() {

window.scroll(0, 1000);
expect(evilGlobal).toBeTruthy();

});

You run the test and it fails miserably. You called window.scroll(0,1000) but the callback will not be executed immediately. It will be put in tasks queue that every browser maintains (I wrote a post on tasks queues a while ago). As Javascript is single threaded the callback will have to wait till current thread is finished. So as our thread continues, the ok assertion that follows will be executed before the callback will have a chance to modify our evil variable. The interesting part is that the browser will however change the window.scrollY position and so if you call window.scrollY you will get 1000. 

Knowing that, the solution is simple. Simply trigger the handler manually and as we already using jQuery, trigger method will do the trick. QUnit code:

test("sets evil to true", function() {

window.scroll(0, 1000);
 $(window).trigger("scroll");
ok(evilGlobal, "test 1 was great success!!!");

});

Jasmine version:

it("sets evil to true", function() {

window.scroll(0, 1000);
 $(window).trigger("scroll");
expect(evilGlobal).toBeTruthy();

});

Why does it work? As the scrollY of the window is already updated all we need is to execute our callback. Trigger function of jQuery is called synchronously setting our variable to true so its ready for our assertion.

Monday, February 10, 2014

Deciphering IE10 popular check syntax

Lovely Microsoft decided to remove support for conditional comments in IE10. So what to do when for whatever reason we need to target this browser and only this browser? There are different ways. One interesting method I would like to discuss is use of self invoking function as:

Function('/*@cc_on return document.documentMode===10@*/')()

In IE10 this will return true and in a code might be used as:

if(Function('/*@cc_on return document.documentMode===10@*/')()) {

$("html").addClass("ie10");
ie10=true;
}

If you are after quick solution its as easy as copy and paste (or try this if(/*@cc_on!@*/false && document.documentMode===10){}). Some might wonder though what exactly this twisted syntax is. Lets try to decipher it step by step. So we trying to understand:

Function('/*@cc_on return document.documentMode===10@*/')()

Right, lots happening here, self invoking function, conditional compilation and what not. Lets start from something easy, consider the code:

var doh=function() {
         alert('DOH!');
}

doh();

This will create a function object and alert DOH! on the screen. Because its a function JS allows us to call it as doh(). Another way of creating function object is via Function constructor as below.

var doh=Function("alert('DOH!')");

doh();

We can still call doh() with no problem. The difference is that this time the body of a function is passed as an argument to Function constructor. 

Keep in mind that there are more differences that you need to be aware when deciding on using constructor syntax. For details I would recommend reading MDN docs for our purposes however all you need to understand is that body of a function can be passed as an argument to a Function constructor.

Easy stuff so far. Now lets make this function self invoking. All we need to do is:

Function("alert('DOH!')")();

We simply instantiating a function object and invoking it right away. When you execute the line it will pop alert on the screen as in previous examples. Very useful construct indeed. Now we might as well replace our alert with /*@cc_on return document.documentMode===10@*/ getting back to our original code:

Function('/*@cc_on return document.documentMode===10@*/')()

Now, what exactly is all this /*@cc.... voodoo you ask? Well, Microsoft folks came up with JScript which is their implementation of JavaScript. JScript also supports something called conditional compilation. You can think of it as sort of conditional comments but for JavaScript (in IE). As per MSDN @cc_on activates conditional compilation within comments in a script so in IE<11:

Function("/*@cc_on alert('DOH!')@*/")()

Will alert DOH!, all other browsers will recognise the function body as a comment only. Now replace alert with our return statement and you got yourself check for IE10 ready to use. 

Furthermore, as I found out skipping cc_on still gives the same results so in my code Function("/*@ alert('DOH!')@*/")() also does the trick. 

I know what you thinking now.. You can check for any IE with this method. From my experiments however, despite of what MSDN documentation is saying I learned that conditional compilation is not supported in IE11. Oh well, I'm sure MS will come up with more conditional improvements soon that will make our lives (not necessarily) easier.

Sunday, February 9, 2014

Sass now even better in Chrome!

So you've tried Sass and you love it. No more CSS-mess for you no more! BUT (isn't there BUT always?) when debugging your code in your favourite Chrome the line numbers in Styles tab do not refer to exact lines in your Sass source file. These refer to generated CSS file that you no longer directly modify. So in dev. tools you still see line number refering to CSS file:



It would be so much easier if tools referred directly to Sass source file as below:


Now (and have been for a while to be honest) it is possible as Chrome allows use of source maps. This basically will map properties from CSS file that browser uses to style elements to source Sass file you directly edit.

To make it happen you need to have late version of Sass installed, at the time of writing this is 3.3.0.rc.2 (whole list of versions can be found here). If you don't have it yet simply run:

gem install sass --version=3.3.0.rc.3

One note.. there is a long list of versions available. As I found out installing anything above version 3.3.0.alpha.201 and running sass with --watch argument does not seem to detect when the file is being updated. --watch argument as you probably know makes Sass to detect when new version of the scss file is saved and recompiles css accordingly. In versions newer then 3.3.0.alpha.201 this doesn't seem to work, at least on my system. That might be fixed by the time you reading this, but I couldn't get it working even with the current latest RC3. If thats the case and you find --watch useful install Sass via gem install sass --version=3.3.0.alpha.201

Now you have Sass installed so go to Chrome dev. tools settings ans tick as below:


And after that you need to tell Chrome where the source file is so it can map CSS properties to it. To do that in Settings-->Workspace "Add folder" and point to the folder where source file is located. Chrome will ask you to confirm that you want to give access to this particular location.


Right, Chrome part is set, all we need to do is run Sass with additional --sourcemap argument e.g.:

sass --sourcemap --watch path_to_scss_file:path_to_css_file

Now you might remember --debuginfo argument used with earlier versions of SASS, this is no more and now --sourcemap does the trick.

And that's pretty much all, hit F5 to refresh the page and enjoy new and improved Styles tab with line numbers referring to Sass file.

Thursday, February 6, 2014

Debugging much?

We all debug. It's easy enough.. hit F12, find a script where breakpoint is needed, set it and wait when JS execution will pause where the breakpoint is set. Wouldn't it be nice though if you could specify directly in the source code when the debugger should pause exactly as the breakpoint does? Well, thank you lucky stars that if you are using Chrome all you need is debugger function. So given code:

// some amazing JS here

debugger; // program will pause here, that's the breakpoint

// even more amazing JS

If dev. tools panel is open this will pause execution at the point where debugger call is. Pretty useful if you ask me.

Wednesday, February 5, 2014

Pure ASCII awesomeness

If you are old enough you might remember how ASCII characters where used to generate images. Non-geeks will say "ehh...I like jpg better", but if you anything like me you will fully appreciate ASCII art awesomeness. I googled this generator, uploaded photo of my lovely daughter and screenshot of result is below. It sure brings back memories of times when 8bit computers ruled.