JavaScript Tips

JavaScript is one of the most used languages on client-side, most of the websites you know contains some JavaScript code even if it’s not so important. Nowadays, this use exploded, especially with the introduction of MV* frameworks on client-side such as BackboneJS or AngularJS, etc. In this post I’ll speak about some JavaScript tips that I learned in my carreer. I’m not a JavaScript specialist, so your comments are welcome.

1. Global variables

Don’t forget to use the var keyword when declaring variables, because if you don’t do, this will be interpreted as a global variable and this is not a good habit because it will make the debugging more difficult.

2. Testing equality

Try always to use === instead of == when testing equality, because === operator evaluates both type and the value

if(1 === '1') //Returns false
if(1 == '1') //Returns true

if(0 === '') //Returns false
if(0 == '') //Returns true

Note that this is the same advice for inequality operators != and !==

3. Semicolons

Always include all semicolons, why ? Because when you didn’t do it, the browser will do it for you where he thinks that is the best and necessary place. So imagine what could be the results.

4. Blocks

Like in C programming language, It’s preferred to use the K&R style of formatting for block quotes. This format starts the opening curly brace on the same line as the preceding line of code. Below, an example:

if(debug === true) {
   console.log('DEBUG mode is enabled');
} else {
   console.log('DEBUG mode is disabled');
}

Furthmore, you should always use explicit blocks. So it’s not appreciable to write the below code

if (i < 10)
    do_something(i);

Instead, write:

if (i < 10) {
    do_something(i);
}

5. Variables declaration

One of the most strange notions in JavaScript that encounters developers coming from C-family languages is the fact that variables is hoisted: variables are available before declaration. It’s strange ! This is due to the interpreter’s strategy. The interpreter starts with scanning code and retrieving all declarations, it executes code line by line. This is why the below code does not throws any error:

console.log(my_variable);
//Outputs: undefined

var my_variable = "Hello World!";
console.log(my_variable);
//Outputs: Hello World!

So, the interpreter scans the code, and collect all declared variables and put them in the concerned scope, then it executes the code. In our case my_variable is declared but it’s not yet initialized until the 4th line. This why the output was undefined for the first time.

Install OpenERP V8.0 on Ubuntu/Debian for development environment

Since May 15, 2014 OpenERP S.A announced several news, the most appreciable one for the OpenERP community was the move of source code from Launchpad to Github. Unfortunately, I did not find neither the time, neither the energy to build an development environment for the 8.0 version. So, today I decided to build it and share this experience with you.

Installation steps

1. As we will install Odoo from Github, we have to install git package

sudo apt-get install git

2. Let’s update the system and install requirement packages

sudo apt-get update
sudo apt-get upgrade
sudo apt-get install graphviz ghostscript postgresql-client \
    python-dateutil python-feedparser python-matplotlib \
    python-ldap python-libxslt1 python-lxml python-mako \
    python-openid python-psycopg2 python-pybabel python-pychart \
    python-pydot python-pyparsing python-reportlab python-simplejson \
    python-tz python-vatnumber python-vobject python-webdav \
    python-werkzeug python-xlwt python-yaml python-imaging

3. Create the database role odoo with the required privileges

sudo su - postgres
createuser --createdb --username postgres --no-createrole --no-superuser --pwprompt odoo
Enter password for new role: ********
Enter it again: ********

then exit form the postgres account

exit

Remember the password entered, you need it for the configuration of Odoo (step 6)

4. Create odoo user

adduser --system --quiet --shell=/bin/bash --home=/opt/odoo --gecos 'Odoo' \
    --group odoo

5. Let’s now login as odoo user and clone the odoo repository

sudo su - odoo
git clone -b 8.0 https://github.com/odoo/odoo.git

6. Configuration of Odoo

cd odoo/odoo
cat &gt; odoo.rc &lt;&lt; EOF
[options]
db_host = False
db_port = False
db_user = odoo
db_password = False
EOF
Then open odoo.rc file and updat e the line db_password = False by the password chosen in step 3)

7. Run the server and get fun

./openerp-server.py -c odoo.rc

Now open your browser and go to http://127.0.0.1:8069 and create your first database

Dive into Python super built-in

super is a Python builtin, first introduced with the new-style class in Python 2.2. super delegates method calls to a parent class. However, In multiple inheritance case, the order is important. So Python uses something called method resolution order (MRO) and an algorithm called C3.

Practical use cases

1. Using super with __init__

This is the common use of super, this is where you can initialize then you complete the initialization in the parent class. Below an example which explain more the idea:

class Child(Parent):
    def __init__(self, arg):
        self.arg = arg
        super(Child, self).__init__()

2. Extending classes

For example, the dict type does not keeps its keys in the order in which they are inserted, let create a new class using Python’s super capability:

class OrderedDict(dict):
    def __new__(cls, *args, **kwargs):
        instance = super(OrderedDict, cls).__new__(cls, *args, **kwargs)
        instance.keyOrder = []
        return instance

    def __setitem__(self, key, value):
        if key not in self.keyOrder:
            self.keyOrder.append(key)
        super(OrderedDict, self).__setitem__(key, value)

    def __delitem__(self, key):
        super(OrderedDict, self).__delitem__(key)
        self.keyOrder.remove(key)
    ...

How super works

First of all, you should know that in multiple inheritance, we don’t have a superclass, and super does not returns the superclass, but it returns a proxy object that will look to the ancestor tree of class in which it was called. Let’s explain more with an example:

class Base(object):
    a = 0

class A(Base):
    pass

class B(Base):
    a = 1

class C(A, B):
    pass

c = C()

If the superclass of C was A, then super(C, c).a should returns 0. But this not the case, super(C, c) will returns an proxy object that will comply with the MRO.

The Method Resolution Order (MRO)

Since Python 2.3, The MRO algorithm is the C3 algorithm for the new-style classes. So, How does the C3 algorithm works? First of all, we starts with the computing of the class precedence list or the linearization of C, which is the list list of the ancestors of a class C, including the class itself, ordered from the nearest ancestor to the furthest.

the linearization of C is the sum of C plus the merge of the linearizations of the parents and the list of the parents.

In symbolic notation, we will have

L(C(B1, B2, …, Bn)) = C + merge(L(B1), L(B2) … L(Bn), B1 … Bn)

with C inheriting from the base classes B1, B2, … , Bn

and merge is calculated following this algorithm:

  1. if the head of the first list is a good head (aka does not exists in the tail of the others lists), then add it to L(C), otherwise check if the head of the next list is a good head.
  2. If it is a good head then, repeat 1) for the tail of the list until there is no candidate or it’s impossible to find a good head

NB: If we did not found a good head, so in this case it’s impossible to construct the merge and Python will raise an exception.

Particular cases:

  • L(object) = object
  • merge(A, A) = A
  • merge(L(A), A) = L(A)
  • L(B(A)) = B + merge(L(A), A) = B + L(A)

So, let’s calculate L(C):

L(Base) = L(Base(object))
        = Base + merge(L(object), object)
        = Base + L(object)
        = Base + object

L(A) = L(A(Base)) = A + merge(L(Base), Base) = A + L(A) = A, Base, object

L(B) = B, Base, object

L(C) = L(C(A, B))
     = C + merge(L(A), L(B), A, B)
     = C + merge([A, Base, object], [B, Base, object], A, B)
     = C + A + merge([Base, object], [B, Base, object], A, B)
     = C + A + B + merge([Base, object], [Base, object], A, B)
     = C + A + B + Base + object