Skip to content

Latest commit

 

History

History
807 lines (591 loc) · 19.6 KB

js-basics-1.md

File metadata and controls

807 lines (591 loc) · 19.6 KB

JavaSript Basics (part 1)

In a nutshell:

  • Created by Brendan Eich at Netscape, in 1995.
  • The name comes from a cooperation with Sun Microsystems but it has nothing to do with Java.
  • Standardized by ECMA (ECMAScript Language Specification).
  • Interpreted language.
  • Dynamic typing.
  • Object Oriented language based on Prototypes.
  • Functional language with nested functions and closures.

Below is a detailed overview of the basis of the language. This presentation is heavily based on JavaScript: The Good Parts by Douglas Crockford. This more or less correspond to the fift version of the ECMAScript standard (ES5). The sixth version ES6 or ES2015 has many new features (classes, modules, arrow functions, etc.) that are not described here.

  1. JavaSript Basics (part 1)
    1. Syntax
    2. Numbers
    3. Strings
    4. Control Flow
    5. Expressions
    6. Scope
    7. Objects
    8. Prototype
    9. Creation of new Objects
    10. Arrays
    11. Regular Expressions

Syntax

JavaSript has a c-based syntax with lots of idioms borrowed from Java.

Variables

Variables are dynamically typed but need to be declared with the var keyword:

var i;
var j = 0;
var k = 1, l = j+k;

Comments

/*
    C-Style multiline comment
 */

// C-Style single line comment

Names

One letter or underscore optionally followed by one or more letters, digits, underscores.

Reserved Words

Most of them are not used.

abstract boolean break byte case catch char class const continue debugger default delete do double else enum export extends false final finally float for function goto if implements import in instanceof int interface long native new null package private protected public return short static super switch synchronized this throw throws transient true try typeof var volatile void while with

Numbers

Number is the single type for all numerical values. No integers, float, double, etc. Only numbers. A number is composed of :

  • an integer part, e.g. 123,
  • followed by an optional fraction part, e.g. 123.456
  • followed by an optional exponent part, e.g. 123.456e+7

Numbers Encoding Format

  • 64 bits floats (Java doubles)
  • No integers, 1 is the same value as 1.0.
  • Arithmetic is not exact, ( 0.1 + 0.2 !== 0.3) as in all programming languages...

NaN

NaN is a value that results from an operation producing abnormal arithmetic result.

⚠️ NaN can't be tested against itself:

Math.sqrt(-2) === NaN; // false

isNaN(number) is used to spot NaNs.

isNaN(Math.sqrt(-2)); // true

Infinity

Infinity > 1.79769313486231570e+308 // true

Utility functions

Utility functions and constants are available through the Math object.

Math.floor(3.45); // 3
Math.random();  // 0.22312605078332126
Math.PI; // 3.141592653589793
Math.sin(Math.PI/2); // 1

Parse Strings to Numbers

parseInt(string, base);
parseInt('345€', 10); // 345
parseInt('$345', 10); // 'undefined'
parseInt('8'); // 8
parseInt('08'); // 0 -> leading 0 is understood as octal base
parseInt('08', 10); // 8 -> always give the base!!!

Strings

Strings are immutable objects.

String Literals

Written between single or double quotes ( 'this string', "that string").

  • The empty string '' is allowed (0 characters).
  • No char type. We use one-character strings ( 'a').

Escaped Characters

  • \(backslash) escapes characters.
  • \\ \' \' \n \/ \t \b \f \r \u0065

unicode

  • Strings are 16 bits unicode characters.
  • '\u004A \u0053 \u062D \u0F1C \u3FEF \u0DF4' === 'J S ح ༜ 㿯 ෴'
  • Characters above '\uFFFF' need 2 JS characters.

Concatenation

The + operator has 2 functions:

  • concatenation of strings
  • and addition of numbers.
'J' + 'S' === 'JS' // true

The concatenation has the priority over the addition. Addition will occure only if the two operators are numbers. In any other case, concatenation will occure.

'HTML' + 10 / 2 === 'HTML5' // true

Length

String objects have a length property that represents the number of 16-bits unicode characters in that string.

 '€\u5555ñ'.length === 3 // true

'€\u5555ñ' === '€啕ñ' // true

String Methods

The String pseudo-class has methods.

Since strings are immutable, methods are static and only return new objects (no modification).

var s = 'ok/ko';
var s1 = s;
s += '/ok'; // 'ok/ko/ok' but strings are immutable, so s is a new object.
s1; // 'ok/ko' The original object remains unchanged.

s1.toUpperCase(); // 'OK/KO'
s1.split('/'); // [ 'ok', 'ko' ]
s1.replace('/', ' ≠ '); // 'ok ≠ ko'
'one, two , three'.split(/\s*,\s*/); // [ 'one', 'two', 'three' ]
String.fromCharCode(74, 83) // 'JS'

Control Flow

Classical C-Style Block statements.

if/else

if (expression) {
    // statements;
} else if (expression) {
    // statements;
}

for

var i; // at beginning of function
// ...
for (i = 0; i < 10; i += 1) {
    // statements;
}
for (i in obj) {
    // statements;
}

while

var i; // at beginning of function
// ...
i = 0;
while (i < 10) {
    // statements;
}

switch

switch (expression) {
    case expression:
        // statements;
        break;
    default:
        // statements;
}

Expressions

Literals, names, operators and other expressions.

Operators Precedence

Operator comment
. [] () Refinement and invocation
delete new typeof - + ! Unary operators
* / % Multiplication, division, modulo
+ - Addition (or string concatenation), subtraction
<= < >= > Inequalities
=== !== Equality
&& Logical AND
`
?: Ternary operator

Refinement

object.property;
object['property'];

Invocation

my_function(param1, param2);

Literals

Objects

{
    property1: 'value1',
    my_property: true,
    '% of value': 23
}

Arrays

['a', 'b', 'c', 3, true, my_obj]

Regexp (borrowed from perl)

/^[a-zA-Z_][a-zA-Z_0-9]*$/ // recognizes javascript 'names'

Functions

function my_function(p1, p2) {
    // var statements;
    // statements;
}

Anonymous functions

some_function(p1, p2, function(){
    // var statements;
    // statements;
});

Scope

Although being a block-based syntax language, JavaSript does not have block scope. Javascript has function scope.

Functions get access to the context (surrounding variables) they are defined within.

function f () {
    var a = 10, b = 2;
    function f2() {
        var b = 20, c = 2;
        // a : 10,  b : 20,  c : 2
    }
    f2();
    // a : 10,  b : 2,  'c' exists but is undefined
    if (a > 0) {
        var c = 34;
        b = 25;
        // a : 10, b : 25, c : 34
    }
    // a : 10, b : 25, c : 34
}
f();

A function scope extended example.

Objects

  • Numbers, strings, booleans, null and undefined are simple and immutable types.
  • All other values are objects.
  • Objects are mutable dictionaries (Java's hashtables, Python's dicts).
  • An object is a container for properties.
  • A property has a name and a value. A name of a property can be any string (quotes are optional if name matches /^[a-zA-Z_][a-zA-Z_0-9]*$/).
  • A value of a property can be any JS value except for undefined.

Object Literal

var w = {
    '°C': 27,
    humidity: '80%',
    place: 'Le Havre'
}

Access to properties

w['°C']; // 27
w.humidity; // '80%'
w.pressure; // undefined
w.pressure = 1030;
w.place = 'Nice';

Objects are passed by reference

var w2 = w;
w['°C']=34;
w2['°C']; // 34

Prototype

  • Every object inherits properties from a prototype object.

  • Object literals are linked to Object.prototype.

  • New objects can have any object as a prototype.

  • Accessing an object's property is a recursive search into the prototype chain.

  • Recursively, all objects inherit from Object.prototype.

  • object

    • properties
    • prototype
      • properties
      • prototype
        • ...
        • ...

Example:

var o = {
    'a': 0,
    'b': false
};
Object.prototype.ok = function() {
    return 'That\'s OK!';
};
Object.prototype.not_ok = 'Not OK.';
o.ok(); // 'That's OK!'
o.not_ok; // 'Not OK.'

Searching the prototype chain: - object o - properties {'a':0, 'b':false} - prototype Object.prototype - properties { ok: [Function], not_ok: 'Not OK.'} - prototype undefined

##Creation of new Objects

Several technics allow the creation of new objects. The most common uses Constructor Functions and the new operator.

Constructor Functions

Like an ordinary function, with a capital first Letter name (convention) The function body can be described as the constructor of the new object. The new object's properties can be accessed/defined in the constructor with the this special value.

function Point() {
    this.x = 0;
    this.y = 0;
    this.toString = function() {
        return '('+ this.x + ', ' + this.y + ')';
    };
}

The new operator

The new creates new objects using a Constructor Function.

It gives newly created objects properties referred to by this in the body of the Constructor Function.

var p1 = new Point();
p1; // { x: 0, y: 0, toString: [Function] }

⚠️ The newoperator uses the Constructor Function's prototype property to initialise the new object's prototype.

A Constructor Function is an object like an other JS object. It has properties an a prototype.

Object Point
Properties prototype: {}
Prototype Function.prototype
Object p1
Properties x: 0, y: 0, toString: [Function]
Prototype Point.prototype
  • The special class method Object.getPrototypeOf(object) retrieves an object's prototype.
  Object.getPrototypeOf(p1) === Point.prototype
  ```

-	Changing an object's properties does not change its prototype object.
  ```javascript
  p1.z = 0;
  Point.prototype.z; // undefined
  ```

-	:warning: Changing an object's prototype will change all the objects that use this prototype!
  ```javascript
  var p2 = new Point();
  p2.z; // undefined
  var proto = Object.getPrototypeOf(p1); // {}
  proto.z = -1;
  p1.z; // -1
  p2.z; // -1
  Point.prototype; // { z: -1 }
  ```

### Dealing  with properties of an object

The `for in` statement iterates through the properties of an object.

```javascript
var prop;
for (prop in p1){
  console.log(prop+' : '+p1[prop]);
}

The for in loop might bring properties inherited from the prototype chain. hasOwnProperty filters only properties (not function) belonging to that object.

for(var prop in options) {
    if(options.hasOwnProperty(prop) && this.hasOwnProperty(prop)) {
        this[prop] = options[prop];
    }
}

Delete a property from an object. Cannot affect properties from the prototype.

delete p1.x; // true
p1.x; // undefined

Augmenting Default Types

Preexisting objects also have a prototype link that can be accessed.

The String pseudo-class can be augmented. We call it a pseudo-class because it does not create real mutable objects. Indeed strings are immutable.

 String.prototype.trim = function() {
    return this.replace(/^\s*|\s*$/, '');
};

' Ok then     '.trim(); // 'Ok then'

Number.prototype.integer = function() {
    return Math[this >= 0 ? 'floor' : 'ceil'](this);
};

(2.34).integer(); // 2
(-Math.PI).integer(); // -3

Creating Objects with the ECMASript 5 pattern

The ECMASript 5 uses the Object.create function to create objects.

Object.create(proto[, propertiesObject])

This Method returns a new object based on the given prototype and optionally the given properties.

The proto parameter can be null or Object.prototype or any other object. Newly created objects will have this proto object as a prototype link.

The propertiesObject parameter defines the new objects properties.

The added value of this approach is the possibility to tune properties with a set of parameters that define their behavior.

  • configurable : if true, then it is possible to change this property's type. false by default.
  • enumerable: if true, then this property can by eniumerated (e.g. for(var prop in obj){...}). false by default.
  • value: The value associated with that property. Can be any Javascript type (Number, String, object, function, etc.) undefined by default.
  • writable: if true, then the property can be modifiable. It is then possible to set a value without using accessors. false by default.
  • get: An accessor function. This function returns what is considered to be the value of the underlying property. undefined by default.
  • set: A modifier function that sets a value to the property. This function has one parameter: the new value to be given to the property. undefined by default.

The most important feature of Object.create is to provide a way to define safe objects. Values car be read only or protected with accessors... But attributes can't be private.

Example:

var obj = Object.create(null); // object without prototype link

var obj2 = Object.create(Object.prototype); // equivalent to "var obj2 = {};"

var positivePoint = Object.create(Object.prototype, {
  x: {
    get: function() {return this._x || 0;},
    set: function(value) {
      if (value < 0) {
        console.log("Error! this point must have positive values", this.y);
      }
      else {
        this._x = value;
      }
    },
  },
  y : {
    get: function() {return this._y || 0;},
    set: function(value) {
      if (value < 0){
        console.log("Error! this point must have positive values");
      }
      else {  
        this._y = value;
      }
    },
  },
  toString: {
    value: function() {
      return '('+ this.x + ', ' + this.y + ')';
    },
  }
});

Arrays

  • Literals
    var a = [ 'a', 'b', ['c', 'd'], true];
    var b = [];
  • Access with integer indices
    a[0]; // 'a'.
  • Javascript's Arrays are ordinary objects (key/value) with arrays characteristics.
  • Indices are converted into keys (strings)
    a[0] === a['0'] // true.
  • Arrays can be sparse (no memory wasted):
    a[10] = 'k';
    a[8]; // 'undefined'
    a; // ['a', 'b', ['c', 'd'], true, , , , , , , , 'k']
    var prop;
    for (prop in a) {
        if (a.hasOwnProperty(prop)) { console.log(prop);}
    } // 0 1 2 3 10

Length

Arrays have a length property. The highest index plus one, not this actual size:

a.length; // 11

Add elements

a[a.length]='v1';
a.push('v2');

Delete elements

The delete operator can be use (as for objects) but array will not be rearranged. We use splice instead.

delete a[2]; // ['a', 'b', , true, , , , , , , , 'k', 'v1', 'v2']
a.length; // 13
a.splice(2, 1); // ['a', 'b', true, , , , , , , , 'k', 'v1', 'v2']
a.length; // 12

Arrays Methods

concat(item...)

Returns a new array that has the items of this plus the flatten items given in parameters:

var a = ['a', 'b', 'c'];
var b = ['d', 'e', 'f'];
var c = a.concat(b, 'g', 'h');
c; // ['a','b','c','d','e','f','g','h']

push(item...)

Appends items in parameters to this array.

a.push(b, 'g', 'h');
a; // ['a', 'b', 'c', ['d', 'e', 'f'], 'g', 'h']

join(separator)

Returns a concatenated string of values of the array. The separator is inserted between each value.

a.join('-'); // 'a-b-c-d-e-f-g-h'

pop()

Removes and returns the last element of the array. Arrays can be used as stacks when pop() and push(...) are used.

var a = ['x', 'y', 'z'];
a.pop(); // 'z', a : ['x', 'y']

unshift(item...)

Adds items at the beginning of the array. Returns the size of the array. Existing elements are shifted.

a.unshift('a'); // 3
a; //  ['a', 'x', 'y']

shift()

Removes and returns the item at the beginning of the array.

a.shift(); // 'a'
a; // ['x', 'y']

reverse()

Reverses the order of the array and returns it.

splice(beg, len, item...)

Removes 'len' elements at position 'beg' and insert items 'item...' at that position. Re-indexing if needed.

var a = ['a', 'b', 'c'];
a.splice(1, 1, 'b1', 'b2'); // ['b']
a; // ['a', 'b1', 'b2', 'c']

slice(beg, end)

Return a copy array (references only if objects) of elements between beg and end indices. Original array not affected.

a.slice(1, 2); // ['b1', 'b2'];
a; // ['a', 'b1', 'b2', 'c']

sort(func)

Reorders the array according to the given function. The function takes 2 args ( a,b) and returns 0 id a === b, a positive number if a > b, and a negative number if b > a.

function by(prop){
    return function(obj1, obj2){
        var a = obj1[prop],
        b = obj2[prop];
        if(a === b){
            return 0;
        }
        return a > b ? 1 : -1;
    }
}
var pts = [ {x:10,y:34},
{x:-10,y:4},
{x:0,y:-4}];
var i;
pts.sort(by('y'));
for(i = 0 ;  i < pts.length; i++) {
    console.log(Point.prototype.toString.apply(pts[i]));
}
// (0, -4)
// (-10, 4)
// (10, 34)

map(callback[, thisArg])

  • from ECMAScript 5.1

New array with the result of the execution of callback on each value of that array.

var a = [1, 2, 3, 4];
var map_a = a.map(function(e){
	return e*e;
});
// [1, 4, 9, 16]

reduce(callback[, initialValue])

  • from ECMAScript 5.1

Apply the callback function between an accumulator and each value of the array, from left to right.

var reduce_a = map_a.reduce(function(previous, current){
	return previous + current;
});
// 30

Regular Expressions

  • For search and replace operation in strings.
  • Faster than equivalent string operations.
  • Not as powerful as real Perl regex.
  • Main methods: exec, test, match, replace, search, split.
 /* matching ip addresses */
var worst = /^\d+\.\d+.\d+.\d+$/;
var bad = /^(?:\d{1,3}\.){3}\d{1,3}$/
var better = /^(?:\b(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b\.){3}
            \b(?:25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\b$/

Full example on CodePen.

More on Mozilla Developer Network's article on RegExp.