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