Other Cool

Interesting Parts of Javascript.

Javascript is pretty logical language once you get to know all the parts. Time is the best teacher, some problems you have to experience to comprehend them. Still here are few unintuitive things you may run into as new developer or even existing one.

Objects are passed by Reference

In lots of languages Objects are passed by “reference” and primitive values like strings and integers are passed by value. Being passed by value mean the copy of value is made and modifying it wont affect the original.

Demo: http://jsfiddle.net/ob6yLmof/

var o = { a:1 };
console.log(o.a); //1
addOne(o);
console.log(o.a); //2

function addOne(x) {
  x.a += 1;
}

var n = 1;
console.log(n); //1
increaseByOne(n);
console.log(n); //1 - still

function increaseByOne(x) {
   x += 1;
}

Properties inherited can’t be directly changed

When property on an object is accessed and it doesn’t exist on it then lookup happens in prototype chain. And if property exists then the value of that property is returned. However, when assigning a property which doesn’t exist on the object but is present on its prototype chain won’t matter, it will be assigned to the object itself.

var p = { x: 1 };

var a = {};
var b = {};

a.__proto__ = p;
b.__proto__ = p;

console.log(a.x); 
console.log(b.x); 

a.x = 5;
console.log(a.x); //5

//but it didn't really change property

console.log(b.x); //1

Hoisting

In JavaScript, functions and variables are hoisted. Hoisting is JavaScript’s behavior of moving declarations to the top of a scope (the global scope or the current function scope).

play(); // Works because foo was created before this code runs
function play() {
   // code code code
}

however only function declarations are hoisted not anonymous functions.

play(); // this raises a TypeError
var play = function() {};

Hoisting of variables can create unexpected errors and or lead to misunderstandings.

Because variable declarations (and declarations in general) are processed before any code is executed, declaring a variable anywhere in the code is equivalent to declaring it at the top. This also means that a variable can appear to be used before it’s declared. This behavior is called “hoisting”, as it appears that the variable declaration is moved to the top of the function or global code.

var myvar = 'Ike'; 
logIt();

function logIt() { 
  alert(myvar); 
  var myvar = 'thunder'; 
}

 

it will result in alert showing undefined. and looking at code will show why? This code will essentially converted to this:

var myvar = 'Ike'; 
logIt();

function logIt() { 
  var myvar;
  alert(myvar); 
  myvar = 'thunder'; 
}

Only Function Definition create scope

Demo: http://jsfiddle.net/gu2n6Lqt/

Nothing beside function creates new scope, especially curly brackets. This behavior is opposite of some languages. And combined with this misunderstanding and Hoisting it can be really cause unexpected bugs.

var n = 3;
console.log(i); //doesn't give error, 
//console.log(a); //gives error, can't call undeclared variable

while (n--) {
  var i = 3234023;
}

setInterval (setTimeout) doesn’t follow time precisely

function foo(){
// something that blocks for 1 second
}
setInterval(foo, 100);

There are two things that on need to be aware of about timers in Javascript.

A) They are not precise.

B) They dont wait for previous interval to finish.

Js is single threaded, and timers simulate multithreading using event loop. Event loop goes through all function calls and then through timers, it checks if timer is due and should be called now, it calls it. If however, code beforehand took more time to execute then it can’t execute code inside timer inside hasn’t gotten there yet.

In Short, setInterval/setTimeout could take more than second even if you have set it to 1000ms. This has implications for gaming, web audio, and chat applications.

But what is real problem with this is that if duration of interval is short enough it could cause double calls, Since, delaying of one timer call won’t postpone the call for next interval call.


Strings are immutable

Unlike, Ruby, string in JavaScript can’t be modified. Only way to change something in a string is to get a new string.

This is however not a big problem but something to be aware of as no errors are thrown.

var myString = "aaaaaaa";
myString[3] = 'c';
console.log(myString); // aaaaaaa

var str = 'hi i am umer';
var newStr = str.replace('umer','abk');
console.log(str); //hi i am umer
console.log(newStr); //hi i am abk

Semicolons aren’t really optional

Before executing code JS compiler tries to auto insert semicolons where it sees fit it results in code such as below ..

function a() {
  console.log('hi')
  return
      {
        a: "hello"
       }
}

resulting in this

function a() {
  console.log('hi');
  return; // <---
      {
        a: "hello"
       };
}

Which completely changes the behavior,Omitting semicolon doesn’t result in any change in problems 80% of the time, but due it other 20% it’s easier to add semicolon everywhere then to trying to memorize the rules of how compiler works.


Always specify radix parameter in parseInt

parseInt function’s 2nd argument specifies a radix for the number conversion. If no radix is specified, the results is unexpected.

For example, if the string begins with a 0, the string is interpreted as an octal number:

parseInt("032") //returns 26
parseInt("032", 10) //returns 32

The octal numeral system, or oct for short, is the base-8 number system, and uses the digits 0 to 7. Octal numerals can be made from binary numerals by grouping consecutive binary digits into groups of three (starting from the right).


‘this’ in JS.

There are only 4 ways to set this in JS.

  1. obj.func()
  2. new
  3. apply/call
  4. bind

using obj.fun():

Inside function this statements are excuted in context with whatever is on left of dot.

function add1() {
  this.sum += 1;
}

var a = {sum:0};
var b = {sum:0};

a.add = add1;
b.add = add1;

a.add();
b.add();

using new keyword, it goes something like this:

First the constructor function declaration.

function Person() {
   this.name = 'Umer';
}

then we do this:

var a = new Person();

This is what happens here:

1. First It creates a new empty object, {}.

2. Then it sets this new object’s internal, __proto__ property to be the constructor function Person.prototype object (every function object automatically has a prototype property).
{}.__proto__ = Person.prototype;

3. Call Person function ( a constructor function) with this = {}.

{}.func();

4. It returns the newly created object, unless the constructor function returns a non-primitive value. In this case, that non-primitive value will be returned.

apply vs call

This lets you define the value of this when calling function.

For Example

var o = {
    sum: 1,
    showSum: function(){ console.log(this.sum); }
}

//then
o.showSum(); // shows 1

//but what if you wanted to use this function with this as something else, like another object.

var anotherObj = { sum: 9999999 };
o.showSum.call(anotherObj); // 9999999

apply and call Do the same thing, but apply takes parameters as an array where as, call takes each parameter to be passed to array as separate argument.

theFunction.apply(valueForThis, arrayOfArgs)

theFunction.call(valueForThis, arg1, arg2, ...)

using bind keyword:

bind unlike call/apply doesn’t call the function right away. But instead pass returns the function with its this already set.

For example:


var obj = { 
    name: 'umer', 
    sayIt: function() {
        console.log(this.name);
    }
};

var o2 = {
    name: 'test',
    sayIt: obj.sayIt.bind(obj)
};

It helps a lot in nodejs and events in browser, you can pass function without worrying too much about value of this.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s