Javascript - what programmer should know about - difference between java and c#


Tips and tricks in javascript and things you need to know comparing to java and c#

declaring variables


var x; // undefined
var x = null; // null
var x = false; // boolean
var x = "text"; // string
var x = 4; // number
var x = 4.11; // number
var x = new Date(); // object which is Date
var x = {}; // empty object
var x = { a:1, b:"test", c: {} }; // object with keys and values
var x = []; // empty array
var x = [1, "text", {a:3}]; // array with values
var x = function() { alert('ok') } // function

You can also declare many variables at once

var a=1, b = a+1, c = 5;

Although I prefer to declare every variable in new line.

variables scopes

Unlike c# or java, in javasript we have 'function' scope. It means if variable are in the same function, they will be in the same scope. Brackets don't change anything!

var outVar = 1; // global variable

var f1 = function() {
  var f1Var = 2; // local variable
  if (true) {
     var f2Var = 3; // bracket doesn't change anything
  }
  console.log(outVar, f1Var, f2Var); // 1 2 3
};

f1();

console.log(outVar); // 1
console.log(f1Var); // error - variable not defined
console.log(f2Var); // error - variable not defined

outVar is global variable visible everywhere (like private variables in classes in java or c#)
f1Var is visible in function only. Similar f2Var - brackets don't change anything

Don't declare to many global variables - they should be avoided if it is possible - use functions or modules.

Don't forget to add 'var', because javascript will declare this variable as global!

var f1 = function() {
  f3Var = 2; // without 'var' this is global variable :(
};

f1();

console.log(f3Var); //2

You can sometimes show self invoking function:

(function() {
    var a = 1;
    console.log(a);
})();

this is the same as

var f = function() {
    var a = 1;
    console.log(a);
};
f();

This is useful in e.g. initializations if you don't want to declare global variables (local variables in function)

In javascript there is something called 'hoisting'. Javascript moves declaration of variables to the top

var f1 = function() { 
  console.log(a); // undefined
  var a = 4; 
};
f1();

is the same as

var f1 = function() { 
  var a;
  console.log(a); // undefined
  a = 4; 
};
f1();

That's why some developers always declare variables on the top.

accessing variables


You can access any variable by accessing object which hold it

Global variables are hold in global object 'window'

var outer = 1;

console.log(outer); // 1
console.log(window.outer); // 1
console.log(window["outer"]); // 1

window["outer"] = 2;
console.log(outer); // 2

If you add prefix to not existing variable you will get undefined, not error!

console.log(notExistingVar); // error - variable not defined
console.log(window.notExistingVar); // undefined
console.log(window["notExistingVar"]); // undefined


In functions:

var f = function() {
   var a = 1;
   console.log(a); // 1
   console.log(this.a); //1
   console.log(this["a"]); //1
};


In objects:

var o = {
   a: 1,
   b: 2,
   c: function() { alert('wow'); }  
};

console.log(o.a); // 1
console.log(o["a"]); // 1
o["c"](); // alert wow

arguments in functions


In javascript you can't overload functions - if you add two functions with the same name, second will overwrite first even if they have different number of parameters.
You can pass any number of parameters to the function!

var f = function(arg1, arg2) {
   console.log(arg1, arg2, arguments[0], arguments[1], arguments[2], arguments[3]);
}

arguments is built-in variable that holds all passed variables

f(); //  undefined undefined undefined undefined undefined undefined

f(1); //  1 undefined 1 undefined undefined undefined

f(1,2); //  1 2 1 2 undefined undefined

f(1,2,3); // 1 2 1 2 3 undefined


Not passed arguments will have undefined value without any error.

You can check number of passed arguments

var f = function(arg1, arg2) {
  if (arguments.length == 0) {
     console.error('zero arguments');
  }
}

f(); // zero arguments error
f(1); // ok

prototype


With prototype you can extend any function (your or native). This is something like extensions methods in c#

String.prototype.format = function () {
    var args = arguments;
    return this.replace(/\{\{|\}\}|\{(\d+)\}/g, function (m, n) {
        if (m === "{{") { return "{"; }
        if (m === "}}") { return "}"; }
        return args[n];
    });
};


Now you have function format in strings:
"{0} - {1}".format(1, 2) // "1 - 2"

classes


function F (type) {
    // private variable
    var privVariable1 = "test";
   
    // private method
    var privF = function() {
      alert('hello');
    };
   
    // public variable
    this.type = 'type';
   
    // public method
    this.show = function() {
        console.log('Show ', this.type);
    };
}

var f1 = new F();
var f2 = new F();

f1.type = "new value";
f2.show();

Or with prototype (it doesn't need to recreate methods when object is created)

function F (type) {
    // private variable
    var privVariable1 = "test";
   
    // private method
    var privF = function() {
      alert('hello');
    };   
}

// public variable
F.prototype.type = 'type';

// public method
F.prototype.show = function() {
    console.log('Show ', this.type);
};

var f1 = new F();
var f2 = new F();

f1.type = "new value";
f2.show();

module pattern (namespace)


Most elegant way:

var UT = function(){
   var current = null;

   var test1 = function(){
      current = 1;
      conosole.log('test1');
   };
  
   var test2 = function(){
      current = 2;
      conosole.log('test2');
   };
  
   return {test1:test1, test2:test2}
}();

UT.test1(); // test 1

if, conditions and variables


If in javascript accept all variable types!
If variable is null, undefined, "", or 0 it returns false otherwise true


var a = "test";
var b = 0;
var c;
var d = null;

if (a) // the same same if (a!== null && a !== undefined && a!="" && a !==0)
  console.log('a is defined'); // shows message on console

if (b)
  console.log('b is defined'); // b is 0 so it is converted to false
 
if (c)
  console.log('c is defined'); // c is undefined so it is converted to false
 
if (d)
  console.log('d is defined'); // d is null so it is converted to false

If you want to check if variable is defined, but you accept numbers, you can't use if (a), because 0 is treated as false.
You need to check if (a!== null && a !== undefined) 
 
It won't work if variable is not declared

if (anyVar) // ReferenceError: anyVar is not defined


You can check this in other way:

if (typeof anyVar == "undefined") {
 console.log("undefined")
}

or better

if (!window.anyVar) {
 console.log("undefined")
}

In Javascript you can compare values with == or ===

== - it compare values without checking types

console.log(1 == 1)  // true
console.log(1 == "1")  // true
console.log(null == undefined)  // true
console.log(1 == true) // true


=== - checks values types

console.log(1 === 1)  // true
console.log(1 === "1")  // false
console.log(null === undefined)  // false
console.log(1 === true) // false


it is recommended to use === only!

converting variable types


a) to bool

var a = null;
var b = 2;

var b = !!a; // false, works like if - null is converted to false
var c = !!b; // true, works like if - value is converted to true


b) to string

var a = 1;
var b = ""+1; // "1"
var c = a.toString(); // "1"


c) string to number

var a = "123";
var b = parseInt(a, 10); // 10 is radix, don't remember to put it because for example "09" will be converted with 8 as  radix!
var c = +a; //similiar to parseInt, but if string contains letter you will get NaN

this


Unlike java or c#, 'this' in javascript can be different in every function or object!


Example with jquery events

function init() {
  this.var = "hi";
  console.log('init', this.var, this);
 
  $('#ddl').change(function() {
    console.log('changed', this.var, this); // here this is not the same this as above
  });
}
 
$(function() {
  init();       
});


On console you have

init hi Window
changed undefined <select id="ddl">

In event 'change' this is the element you changed. So it doesn't work.

Example2

var F = function() {
  this.name = 'F';
 
  this.f = function() {
     console.log('f', this.name, this);
  } 
};

var X = function() {
 
  this.name = 'X';
 
  this.x = function() {
     console.log('x', this.name, this);
  } 
};

var f = new F();
var x = new X();

f.f(); // f F Object { name="F", f=function()}
x.x(); // x X Object { name="X", x=function()}

simple right?

What about this:

f.x = x.x;
f.x(); // x F Object { name="F", f=function(), x=function()}

Surprise! Method x was called, but this changed - not it points to F object!

this in an object on which you call method! - in other words object before dot f.x() -> this = f

Read next section to find out how to fix it

Changing and fixing this


The simples fix and most common is to add variable which holds this

Example

function init() {
  var self = this;
  this.var = "hi";
  console.log('init', this.var, this);
 
  $('#ddl').change(function() {
    console.log('changed', self.var, this); // changed hi <select id="ddl">
  });
}
 
$(function() {
  init();       
});

Usually this variable is called self or that. This variable is remembered, even in inner functions (this is called closure in javascript)

Another possibility is to use bind function

var F = function() {
  this.name = 'F';
 
  this.f = function() {
     console.log('f', this.name, this);
  } 
};

var X = function() {
 
  this.name = 'X';
 
  this.x = function() {
     console.log('x', this.name, this);
  } 
};

var f = new F();
var x = new X();

f.x = x.x.bind(x); // this = x

f.x(); // x X Object { name="X", x=function()}

bind creates new function with remembered new this.

You can also use call or apply

In above example

var f = new F();
var x = new X();
f.x = x.x;

f.x.call(x); // this = x
or
f.x.apply(x) // this = x

call is similar to apply, but apply accepts array of extra arguments

returning multi arguments in the function


This is simple with objects:

function f(inputOb) {
    return { sum: inputOb.a + inputOb.b, multiply: inputOb.a * inputOb.b };
}

var res = f({a: 1, b: 2});
console.log(res.sum, res.multiply); // 3 2

passing functions to other functions


You can pass callback function which will be invoked for example if function is finished

function f(finishedFn) { 
   // some comutations...
    if (finishedFn) {
      finishedFn();
    }
}

f(function() { console.log('finished') });

Function can also return other function

function addNumber(addedNumber) { 
   return function(number) {
       return addedNumber + number;
   }
}

var add5 = addNumber(5);
var add3 = addNumber(3);

console.log(add5(1)); // 6
console.log(add3(1)); // 4

for each in arrays and objects

var o = { a:1, b:2, c:3 }

for (var i in o) {
  console.log(i, o[i]); 
}


Result:
a 1
b 2
c 3

this for each actually iterates on indexes, not on values!

Similar in arrays:
var a = [1, 2, 3];

for (var i in o) {
  console.log(i, o[i]);
}

Result:
0 1
1 2
2 3

Interesting example:

var a = [1, 2, 3];

for (var i in a) {
  if (i === 0) {
     break;
  }
  console.log('big');
}

How many times 'big' is displayed? Then answer is three even we do a break if i === 0. Why?

Because i is string! This is how for each in table works (table is object with keys as indexes)

You can fix it with == instead of === (not recommended), comparing with string if (i === '0') or convert to int if (+i === 0)

New forEach

In Ecmascript 6 forEach has been added

var a = [1, 2, 3];

a.forEach(function(element, i) {
   console.log(element, i);
});

result:
1 0
2 1
3 2

Remember that 'this' in function is new 'this' and you cannot break it with 'break'

other


default values

instead

if (!a) {
  a = 5;
}

we can simply write

a = a || 5; //value 5 if a is not defined