JavaScript : les Objets

Michel Buffa
Avril 2012

buffa@unice.fr

Basics

JavaScript orienté objet

Nous allons voir comment :

  • Créer et utiliser des objets,
  • Les fonctions de type constructeurs pour construire des objets,
  • Les objets built-in de JavaScript et leur utilité.

Des tableaux aux objets...

>>>> var myarr = ['red', 'blue', 'yellow', 'purple'];
>>> myarr;
       ["red", "blue", "yellow", "purple"]
>>> myarr[0]
       "red"
>>> myarr[3]
       "purple"
    

En JavasScript un objet = un tableau dont on définit les clés !

var heros = {
  race: 'Tortue',
  metier: 'Ninja'
};        
    

Nom de la variable qui contient l'objet = heros,

Au lieu de [ et ] on utilise { et },

Les éléments de l'objet (ses propriétés) sont séparés par une virgule,

Les paires de clés/valeurs sont séparées par : comme dans race:'Tortue'

Syntaxe de déclaration des propriétés

On peut mettre des simple ou double quotes autour du nom de la propriété, ou rien du tout :

var louis = {age: 40};
var louis = {"age": 40};
var louis = {'age': 40};        
    

Dans certains cas on est obligé de mettre des quotes autour du nom de la propriété :

  • Mot réservé de JavaScript,
  • ccontient des espaces ou des caractères spéciaux,
  • commence par un chiffre

Exemple qui utilise les trois possibilités

var objetBizarre = {
  age: 1,
  'oui ou non': 'oui',
  '!@#$%^&*': true
};
    

Eléments, propriétés, méthodes

Pour des tableaux on parle d'éléments,

Pour des objets on parle de propriétés

Une propriété peut aussi valoir une fonction, dans ce cas on parle de méthode.

var medor = {
  nom: 'Benji',
  parle: function(){
    alert('Ouah, Ouah!');
  }
};
    

Tables de hashage et tableaux associatifs

Dans certains langages de programmation (Java par ex) on distingue :

  1. Un tableau normal, donc les indexs sont des valeurs numériques,
  2. Un tableau associatif dont les clés sont des Strings ou des objets (ex: HashMap en Java)

JavaScript utilise les tableaux pour le cas 1, et des objets pour le cas 2

Accès aux propriétés d'un objet

var medor = {
  nom: 'Benji',
  parle: function(){
    alert('Ouah, Ouah!');
  }
};
    

Deux syntaxes possibles :

  1. medor['nom']
  2. medor.nom (à utiliser si possible)

Accès aux propriétés

var heros = {
  race: 'Tortue',
  metier: 'Ninja'
};
>>> heros.race;
   "Tortue"
>>> heros['race'];
   "Tortue"
>>> heros.age;
   "age is Undefined"
    

Un objet peut contenir un autre objet

var book = {
  name: 'Catch-22',
  published: 1961,
  author: {
    firstname: 'Joseph',
    lastname: 'Heller'
  }
};
>>> book.author.firstname    // à préférer
       "Joseph"
>>> book['author']['lastname']
       "Heller"
>>> book.author['lastname']  // on peut mélanger...
       "Heller"
>>> book['author'].lastname
       "Heller"
    

Autre cas classique où le nom d'une propriété est dans une variable

>>> var key = 'firstname';
>>> book.author[key];
    "Joseph"
    

Dans ce cas on est obligé d'utiliser la syntaxe avec [ et ]...

Appel de méthodes

Une méthode étant une propriété on peut utiliser l'opérateur . ou les crochets

var heros = {
  race: 'Tortue',
  metier: 'Ninja',
  parle: function() {
    return 'Je suis un ' + heros.metier;
  }
}
>>> heros.parle();       // recommandée comme syntaxe
       "Je suis un Ninja"
>>>heros['parle']();     // peu utilisé car moins Java-esque
       "Je suis un Ninja"
    

Modification de propriétés

Contrairement à Java, il est possible en JavaScript d'ajouter ou de supprimer des propriétés une fois l'objet créé.

>>> var heros = {};   // Objet sans propriétés
>>> typeof heros.metier
        "Undefined"
>>> heros.race = 'Tortue';
>>> heros.nom = 'Leonardo';
>>> heros.getNom = function() {return heros.nom;};
>>> hero.getNom();
       "Leonardo"
>>> delete heros.nom;
        true
>>> hero.getNom();
         reference to undefined property heros.nom
    

Utilisation de this

Dans l'exemple précédent le code de la méthode getNom() faisait référence au nom de l'objet, il vaut mieux utiliser le ot clé this.

var heros1 = {
  nom: 'Rafaelo',
  getNom: function() {
    return this.nom;
  }
}
>>> heros1.getNom();
       "Rafaelo"     
    

this correspond à "l'objet courant". Le code est plus portable si on affecte cet objet à une autre variable....

Constructeurs en JavaScript

Un exemple suffit à comprendre le principe (remarquez qu'on nomme la fonction comme une classe Java):

function Heros() {
  this.metier = 'Ninja';
}       
    

On peut maintenant utiliser l'opérateur new :

>>> var monHero = new Heros();
>>>typeof monHero
      "object"
>>> monHero.metier;
       "Ninja"
    

Constructeur avec paramètres

function Heros(nom) {
  this.nom = nom;
  this.metier = 'Ninja';
  this.decrisToi = function() {
    return "Je suis " + this.nom + ", je suis un " + this.metier;
  }
}
>>> var h1 = new Heros('Michelangelo');
>>> var h2 = new Heros('Donatello');
>>> h1.decrisToi();
       "Je suis Michelangelo, je suis un Ninja"
>>> h2.decrisToi();
       "Je suis Donatello, je suis un Ninja"
    

Note : cela commence un peu à ressembler à des classes Java...non ?

Remarques sur les constructeurs

Donner un nom de fonction commençant par une majuscule permet de distinguer les constructeurs !

>>> var monHero = new Heros();
>>>typeof monHero
      "object"        
    

Mais :

>>> var monHero = Heros();
>>>typeof monHero
        "undefined"
    

Normal, car dans ce cas monHero vaut la valeur de retour de Heros() qui ne renvoie rien !

Dans ce cas, le this à l'intérieur de la fonctin Heros() se réfère à ce que l'on appelle l'objet global, qui contient tous les autres.

L'objet global

Il est temps de dire la vérité :

  • Le code JavaScript est exécuté par un environnement (la plupart du temps le navigateur Web, ou plus rarement un Serveur),
  • Cet environnement définit un objet global,
  • Les variables globales sont les propriétés de cet environnement, de même que les fonctions prédéfinies.

Cas où l'environnement est un navigateur web :

  • L'objet global s'appelle window

Continuons sur l'objet global...

>>> var a = 1;
>>> a
    1
>>> window.a
    1
>>> window['a']
    1
>>> function Heros(nom) {this.nom = nom;}
// appel sans new, this = objet global
>>> var h = Heros('Leonardo');
>>> typeof h
      "undefined"
>>> typeof h.nom
      h has no properties h has no properties
>>> nom
      "Leonardo"
>>> window.nom
      "Leonardo"
    

Continuons sur l'objet global...

Si on oublie pas le new :

>>> var h2 = new Heros('Michelangelo'); // On a pas oublié le new !
>>> typeof h2
      "object"
>>> h2.nom
      "Michelangelo"
    

Les fonctions prédéfinies sont des méthodes de l'objet global window :

>>> parseInt('101 dalmatiens')
       101
>>> window.parseInt('101 dalmatiens')
       101
    

La propriété constructor

Quand un objet est créé on lui donne en coulisse une propriété nommée "constructor" :

>>> h2.constructor
       Heros(nom)
>>> typeof a.constructor
       "function"
    

Puisque ce constructeur est une fonction, on peut l'appeler :

>>> var h3 = new h2.constructor('Rafaello'); // construit moi comme h2
>>> h3.nom;
       "Rafaello"
    

La propriété constructor, suite...

Dans le cas où on construit un objet sous sa forme littérale :

>>> var o = {};
>>> o.constructor;
       Object()
>>> typeof o.constructor;
       "function"   
    

Object() est le constructeur built-in de JavaScript. Détails viendront plus loin...

L'opérateur instanceof

instanceof permet de tester avec quel constructeur un objet a été créé

>>> function Heros(){}
>>> var h = new Heros();
>>> var o = {};
>>> h instanceof Herso;
       true
>>> h instanceof Object;
       false             // Pas comme en Java !
>>> o instanceof Object;
       true
    

Fonctions qui retournent des objets (factories)

En plus de la création littérale et de la création par new, on peut aussi créer des objets à l'aide de fonctions qui en renvoient :

function factory(nom) {
  return {
    nom: nom
  };
}
>>> var o = factory('Michel');
>>> o.nom
       "Michel"
>>> o.constructor
       Object()
    

Passage d'objets en paramètres, copie d'objets

Par défaut, toute manipulation d'objet se fait par référence :

>>> var original = {valeur: 1};
>>> var copie = original;
>>> copie.valeur
       1
>>> copy.valeur = 100;
       100
>>> original.valeur
       100        
    

Les deux variables copie et original pointent en fait sur le même objets, ce sont deux références au même objet.

Comparer des objets

Comparer deux objets ne donnera true que s'ils ont la même référence.

Deux objets à priori identiques ne seront pas égaux s'ils n'ont pas la même référence

>>> var fido  = {race: 'chien'};
>>> var benji = {race: 'chien'};
>>> benji === fido
   false
>>> benji == fido
   false
>>> var monChien = benji;
>>> mydog === benji
       true
>>> mydog === fido
     false
    

Objets JavaScript built-in

Objets "wrappers" : Object, Array, Function, Boolean, Number, et String, ils correspondent aux types prédéfinis.

Objets utilitaires : Math, Date, RegExp

Objets pour le debug : Error, etc.

Object

C'est le "père" de tous les objets JavaScript que vous créez. Tous vos objets "héritent" de celui-ci, si on peut parler comme ça...

Ces deux lignes sont équivalentes :

>>> var o = {};
>>> var o = new Object();        
    

On bénéficie de méthodes par défauts comme toString() qui convertit l'objet en Strig:

  >>> o.toString()
     "[object Object]"
    

toString() est assez similaire à son usage Java

>>> alert(o);
>>> alert(o.toString()); // équivalent à la ligne précédente
>>> "L'objet en String : " + o // toString() implicite !
       "L'objet en String : [object Object]"
    

valueOf() renvoie la valeur d'un objet

>>> o.valueOf() === o
      true
    

Array

Array() est une fonction built-in que l'on peut utiliser pour construire des tableaux :

>>> var a = new Array(); // équivalent à var a = [];
>>> var b = new Array(1,2,3,'quatre');
>>> b;
       [1, 2, 3, "quatre"]
    

Piège : si un seul paramètre alors c'est la taille du tableau:

>>> var a2 = new Array(5);
>>> a2;
       [undefined, undefined, undefined, undefined, undefined]
    

Array et objets...

Dans les exemples précédents si on créée des tableaux avec Array() ce sont des objets :

>>> typeof a;
       "object"
    

Et on peut bénéficier des méthodes de Object

>>> a.toString();
       "1,2,3,quatre"
>>> a.valueOf()
       [1, 2, 3, "quatre"]
>>> a.constructor
       Array()
    

Compléments sur les tableaux

Les tableaux sont en fait des objets mais spéciaux :

  • Le nom de leurs propriétés sont des valeurs numériques partant de 0,
  • Ils ont une propriété length qui donne leur longueur,
  • Ils possèdent d'autres propriétés built-in en plus de celles héritées de Object
>>> var a = [], o = {};
>>> a.length
       0
>>> typeof a.length
       "number"
>>> typeof o.length
       "undefined"
    

Tableaux = objet ou pas ?

Hmmm... on peut faire de jolies horreurs quand même :

>>> a[0] = 1; o[0] = 1;
>>> a.prop = 2; o.prop = 2;
>>> a.length
      1
    

La propriété length ne "compte" que les propriétés numériques !

length peut être modifée !

Si plus grand que la taille du tableau

>>> a.length = 5 // peut agrandir le tableau
       5
>>> a
       [1, undefined, undefined, undefined, undefined]
    

Si plus petit, réduit le tableau

>>> a.length = 2;
       2
>>> a
       [1, undefined]
    

Méthodes utiles sur les tableaux

Les plus courantes : sort(), join(), slice(), splice(), push() et pop()

>>> var a = [3, 5, 1, 7, 'test'];
>>> a.push('new') // ajout en fin et renvoie length
       6
>>> a
       [3, 5, 1, 7, "test", "new"]
>>> a.pop() // retire le dernier élément et le renvoie
       "new"
>>> a
       [3, 5, 1, 7, "test"]
>>> var b = a.sort();
>>> b
       [1, 3, 5, 7, "test"]
>>> a
       [1, 3, 5, 7, "test"]
>>> a.join(' et ');
    "1 et 3 et 5 et 7 et test"
    

Suite des fonctions utiles sur les tableaux

slice() renvoie un sous-tableau sans modifier l'original.

>>> a
       [1, 3, 5, 7, "test"]
>>> b = a.slice(1, 3); // éléments 1 et 2
    [3, 5]
>>> b = a.slice(0, 1); // élément 0
    [1]
>>> b = a.slice(0, 2); // éléments 0 et 1
    [1, 3]
>>> a
   [1, 3, 5, 7, "test"]
    

Suite des fonctions utiles sur les tableaux

splice() modifie le tableau en enlevant une tranche, éventuellement en ajoutant aussi de nouveaux éléments.

Les deux premiers paramètres sont les indices de début et fin, les autres paramètres sont les éléments à insérer à la place de la tranche enlevée.

>>> a
   [1, 3, 5, 7, "test"]
>>> b = a.splice(1, 2, 100, 101, 102);
   [3, 5]
>>> a
   [1, 100, 101, 102, 7, "test"]
>>> a.splice(1, 3)
       [100, 101, 102]
>>> a
       [1, 7, "test"]
    

Function

Les fonctions sont des objets en JavaScript, elles ont toutes un constructeur intitulé Function()

>>> function myfunc(a){return a;}
>>> myfunc.constructor
    Function()
    

Les fonctions ont aussi une propriété length qui vaut le nombre de paramètres :

>>> function myfunc(a, b, c){return true;}
>>> myfunc.length
       3
    

Function, suite...

Elles possèdent aussi une propriété caller qui renvoie la fonction appelante :

>>> function A(){return A.caller;}
>>> function B(){return A();}
>>> B();
       B()
    

Si A est appelée depuis l'espace global, l'appelant vaut null :

>>> A();
      null
    

Function, propriété "prototype"

prototype est la propriété la plus importante des fonctions JavaScript

Elle contient un objet,

Elle n'est utile que lorsqu'on utilise une fonction comme un constructeur, par ex: var heros = new Heros('Michel');

Tous les objets créés par cette fonction/constructeur ont une référence vers la propriété prototype de leur constructeur, et considèrent les propriétés de cet objet prototype comme les leurs.

Voyons quelques exemples...

La propriété prototype des fonctions

var unObjet = {
  nom: 'Ninja',
  parle: function(){
    return 'Je suis : ' + this.nom;
  }
}
    

Créons une fonction vide, ah, elle a un prototype !

>>> function F(){}
>>> typeof F.prototype
       "object"
    

La propriété prototype des fonctions

Modifions la valeur de cet objet prototype :

>>> F.prototype = unObjet;
    

Et utilisons F comme un constructeur !

>>> var obj = new F();
>>> obj.nom
       "Ninja"
>>> obj.parle()
       "Je suis Ninja"
    

Intéressant non ? Nous y reviendrons...

Méthodes de l'objet Function : toString()

Function est un descendant de Object, il hérite donc des méthodes de ce dernier, comme toString()

toString() sur une fonction : renvoie le code de la fonction sous forme de String

>>> function myfunc(a, b, c) {return a + b + c;}
>>> myfunc.toString()
       "function myfunc(a, b, c) { 
           return a + b + c; 
        }"
    

toString() et fonctions natives

SI on appelle toString sur une fonction native on obtient [native code] :

>>> eval.toString()
    "function eval() {
        [native code]
    }"
    

Méthodes de l'objet Function : call() et apply()

Permettent d'emprunter des méthodes à d'autres objets et de les appeler :

var unObjet = {
  nom: 'Ninja',
  parlerA: function(interlocuteur){
    return 'Hello ' + interlocuteur + ', je suis un ' + this.nom;
  }
}
>>> unObjet.parlerA('Michel');
  "Hello Michel, je suis un Ninja"
    
>>> unAutreObjet = {nom: 'Gourou JavaScript'};
    

Appropriation de méthode avec call()

UnAutreObjet aime tellement la méthode parlerA() de UnObjet qu'il veut l'appeler :

>>> unObjet.parlerA.call(unAutreObjet, 'Michel');
       "Hello Michel, je suis un Gourou JavaScript"        
    

La fonction parlerA() de unObjet a été appelée avec un "this" différent correspondant à unAutreObjet.

On fait cela en appelant la méthode call() d'une méthode pour changer son "this" !

Peut-on faire cela en Java ?

call()... suite...

Si la méthode a plus de paramètres, on les ajoute :

unObjet.uneMethode.call(unAutreObjet, 'a', 'b', 'c');        
    

Si on ne passe pas d'objet ou si on passe null comme premier paramètre, c'est l'objet global qui correspondra à "this" dans le corps de la méthode.

call() et apply()

apply() est équivalent à call() si ce n'est que les paramètres sont passés dans un tableau :

unObjet.uneMethode.apply(unAutreObjet, ['a', 'b', 'c']);
unObjet.uneMethode.call(unAutreObjet, 'a', 'b', 'c');       
    

Les deux lignes précédentes sont équivalentes.

Avec l'exemple précédent :

>>> unObjet.parlerA.apply(unAutreObjet, ['Michel']);
       "Hello Michel, je suis un Gourou JavaScript"
    

arguments.callee : une propriété intéressante !

arguments est comme un tableau (propriété "length") mais ce n'en est pas un, (pas de slice() et sort() par exemple).

arguments.callee : référence la fonction elle-même.

Utile pour faire des fonctions anonymes récursives :

(function(count){
    if (count < 5) {
      alert(count);
      arguments.callee(++count);
    }
  })(1);
    

L'exemple précédent affiche dans une alerte "1", puis "2", "3" et "4".

L'objet prédéfini Boolean

Comme en Java, c'est un objet qui wrappe le type prédéfini boolean.

On utilise la méthode valueOf() pour avoir une variable du type prédéfini équivalent.

>>> var b = new Boolean();
>>> typeof b
       "object"
>>> b.valueOf()
     false
>>> typeof b.valueOf()
       "boolean"        
    

Utilité de l'objet Boolean : convertir des objets en boolean !

On appelle pour cela Boolean(...) sans new !

>>> Boolean("test")
       true
>>> Boolean("")
       false
>>> Boolean({})
       true
    

N'importe quel objet, même vide, se convertit en "true".

Un objet se convertit toujours en boolean dont la valeur est true !

>>> var b1 = new Boolean(true)
>>> b1.valueOf()
       true
>>> var b2 = new Boolean(false)
>>> b2.valueOf()
       false
    
>>> Boolean(b1)
       true
>>> Boolean(b2)
       true
    

L'objet prédéfini Number

Wrapper sur le type prédéfini "number".

Number() sans "new" sert à convertir en "number", comme parseInt() ou parseFloat()

>>> var n = Number('12.12');
>>> n
       12.12
>>> typeof n
       "number"
>>> var n = new Number('12.12');
>>> typeof n
       "object"
    

Propriétés prédéfinies (non modifiables) de Number()

Comme en JavaScript les fonctions sont des objets, Number() a des propriétés intéressantes :

>>> Number.MAX_VALUE
       1.7976931348623157e+308
>>> Number.MIN_VALUE
       5e-324
>>> Number.POSITIVE_INFINITY
       Infinity
>>> Number.NEGATIVE_INFINITY
       -Infinity
>>> Number.NaN
       NaN
    

Propriétés des objets de type Number

Conversions : toFixed(), toExponential(), toString()

>>> var n = new Number(123.456)
>>> n.toFixed(1)
       "123.5"
>>> (12345).toExponential()
       "1.2345e+4"
>>> var n = new Number(255);
>>> n.toString();
       "255"
>>> n.toString(10);
       "255"
>>> n.toString(16);
       "ff"
>>> (3).toString(2);
       "11"
>>> (3).toString(10);
       "3"

L'objet prédéfini String

new String() construit un objet, on peut utiliser les méthodes et propriétés prédéfinies de String.

>>> var primitive = 'Hello';
>>> typeof primitive;
     "string"
>>> var obj = new String('world');
>>> typeof obj;
      "object"
>>> obj[0]
      "w"
>>> obj[4]
      "d"
>>> obj.length
      5
    

String, suite...

On peut une "string" à partir d'un objet de type String :

>>> obj.valueOf()
       "world"
>>> obj.toString()
       "world"
>>> obj + ""
       "world"
    

JavaScript permet d'utiliser certains aspects des String sur des "string" :

>>> "potato".length
       6
>>> "tomato"[0]
       "t"
>>> "potato"["potato".length - 1]
       "o"
    

Conversion d'objets en "string" (type prédéfini)

On appelle String() sans new, comme pour Boolean().

>>> String(1)
      "1"
>>> String({p: 1})
      "[object Object]"
>>> String([1,2,3])
      "1,2,3"       
    

Ces exemples reviennent à appeler toString() sur les objets en paramètre.

Méthodes intéressantes des objets de type String

>>> var s = new String("Couch potato");
>>> s.toUpperCase()
       "COUCH POTATO"
>>> s.toLowerCase()
       "couch potato"
>>> s.charAt(0);
       "C"
>>> s[0]
       "C"
>>> s.charAt(101)
       ""
>>> s.indexOf('o')
       1
>>> s.indexOf('o', 2); // 2 est l'index de départ !
       7
    

Méthodes de String, suite...

>>> var s = new String("Couch potato");
>>> s.lastIndexOf('o')
       11
>>> s.indexOf('Couch'); // case sensitive
       0
>>> s.indexOf('couch');  // si pas trouvé renvoie -1
       -1
>>> s.toLowerCase().indexOf('couch')
       0
    

String : Piège avec if() et indexOf()

Ile pas tester un index avec un if car si l'index est zéro (début de chaine), alors on teste "false" !

Pas bon :

if (s.indexOf('Couch')) {...}
    

Bon :

if (s.indexOf('Couch') !== -1) {...}
    

String : slice() et substring()

Permettent d'extraire une sous-chaine, on passe la position de début et la position de fin en paramètre :

>>> var s = new String("Couch potato");        
>>> s.slice(1, 5)
       "ouch"
>>> s.substring(1, 5)
       "ouch"        
    

Différence si le dernier paramètre est négatif :

>>> s.slice(1, -1); // équivalent à s.slice(1, s.length -1)
       "ouch potat"
>>> s.substring(1, -1); // équivalent à s.substring(1,0);
       "C"
    

String : méthode split(), join(), concat()

Split renvoie un tableau de chaine, le paramètre est un séparateur, join() construit une String à partir d'un tableau de chaines :

>>> var s = new String("Couch potato");
>>> s.split(" ")
     ["Couch", "potato"]
>>> s.split(' ').join(' ');
       "Couch potato"
>>> s.concat("es"); // équivalent à s = s + "es;
       "Couch potatoes"
>>> s.valueOf();      
       "Couch potato"        
    

Aucune de ces méthodes ne modifie la chaine de départ.

String : méthodes replace(), match() et search()

Ces méthodes utilisent des expressions régulières en arguments, elles seront étudiées un peu plus loin, dans la section concernant l'objet prédéfini RegExp.

L'objet prédéfini Math

Particularité : on ne peut pas faire de "new Math()", mais l'objet Math possède de nombreuses propriétés et fonctions utiles pour les expressions arithmétiques.

>>> Math.PI
       3.141592653589793
>>> Math.SQRT2      // racine carrée
       1.4142135623730951
>>> Math.E          // Constante d'Euler
       2.718281828459045
>>> Math.LN2        // Log naturel de 2
       0.6931471805599453
Natural logarithm of 10:
>>> Math.LN10       // Log naturel de 10
       2.302585092994046
    

Math : nombres aléatoires

Générer un nombre réel aléatoire entre 0 et 1 :

>>> Math.random() 
  0.3649461670235814         
    

Entre 0 et 100

>>> 100 * Math.random()
    

Entre min et max : ((max - min) * Math.random()) + min

>>> 8 * Math.random() + 2 // nombre entre 2 et 10
   9.175650496668485
    

Math et arrondis : round(), ceil(), floor()

Pour arrondir au plus proche, à l'entier supérieur ou inférieur.

Par ex, pour obtenir soit 0 soit 1 :

>>> Math.round(Math.random())
    

Il y a aussi Math.min() et Math.max(). Exemple pour restreindre une valeur entre 1 et 12 :

>>> Math.min(Math.max(1, input), 12)
    

Math et opérations mathématiques : sin(), cos(), tan(), atan(), pow(), sqrt()

>>> Math.pow(2, 8)    // 2 puissance 8
       256
>>> Math.sqrt(9)      // Racine carrée de 9
       3
    

L'objet prédéfini Date

Date() est un constructeur, qui prend plusieurs arguments :

  • Rien : construit la date courante,
  • Une chaîne de caractère qui encode une date,
  • Un ensemble de valeurs numériques séparées par une virgule pour mois, jour, heure, etc.
  • Un "timestamp" Unix (nb de millisecondes écoulées depuis 1970
>>> new Date()
       Tue Jan 08 2008 01:10:42 GMT-0800 (Pacific Standard Time)        
    

Remarque : la valeur retournée est en fait un objet de type Date, ce qui s'affiche est l'appel à toString() sur cet objet.

Date : exemples

>>> new Date('2009 11 12')
      Thu Nov 12 2009 00:00:00 GMT-0800 (Pacific Standard Time)
>>> new Date('1 1 2012')
      Sun Jan 01 2012 00:00:00 GMT-0800 (Pacific Standard Time)
>>> new Date('1 mar 2012 5:30')
      Thu Mar 01 2012 05:30:00 GMT-0800 (Pacific Standard Time)
    

On peut passer aussi des paramètres numériques pour, dans l'ordre : année, mois (0-11), jour (1-31), heure (0-23), minutes (0-59), secondes (0-59), millisecondes (0-999). On n'est pas obligé de tout passer mais ce sera toujours dans cet ordre.

Date : exemple de construction avec paramètres numériques

>>> new Date(2008, 0, 1, 17, 05, 03, 120)
       Tue Jan 01 2008 17:05:03 GMT-0800 (Pacific Standard Time)
>>> new Date(2008, 0, 1, 17)
       Tue Jan 01 2008 17:00:00 GMT-0800 (Pacific Standard Time)
>>> new Date(2008, 1, 28)  // 1 c'est Février ! Ca commence à zéro !
     Thu Feb 28 2008 00:00:00 GMT-0800 (Pacific Standard Time)
>>> new Date(2008, 1, 29)
       Fri Feb 29 2008 00:00:00 GMT-0800 (Pacific Standard Time)
>>> new Date(2008, 1, 30) // Pas de 30 février -> ça donne premier Mars !
       Sat Mar 01 2008 00:00:00 GMT-0800 (Pacific Standard Time)
>>> new Date(2008, 11, 31)
      Wed Dec 31 2008 00:00:00 GMT-0800 (Pacific Standard Time)
>>> new Date(2008, 11, 32) // 32 Dec -> 1er Janvier !
      Thu Jan 01 2009 00:00:00 GMT-0800 (Pacific Standard Time)
    

Date : suite...

On peut construire la date avec un timestamp Unix (nb millisecondes depuis 1970)

>>> new Date(1199865795109)
    Wed Jan 09 2008 00:03:15 GMT-0800 (Pacific Standard Time)        
    

L'appel de Date() sans "new" renvoie la date courante sous forme de chaine de caractères. Peu importe que l'on passe des paramètres.

>>> Date()
       "Thu Jan 11 2012 18:15:47 GMT-0800 (Pacific Standard Time)"
    

Date : méthodes utiles !

// Construction
>>> var d = new Date();
>>> d.toString();
       "Wed Jan 09 2008 00:26:39 GMT-0800 (Pacific Standard Time)"
// Chenger le mois pour Mars
>>> d.setMonth(2);
       1205051199562
>>> d.toString();
       "Sun Mar 09 2008 00:26:39 GMT-0800 (Pacific Standard Time)"
// Récupérer le mois
>>> d.getMonth();
       2
    

Date : deux méthodes qui sont des propriétés de l'objet Date

Date.parse() transforme une chaine de caractère représentant une date en timestamp :

>>> Date.parse('Jan 1, 2008')
       1199174400000
    

Date.UTC() transforme des paramètres numériques représentant une date en timestamp :

>>> Date.UTC(2008, 0, 1)
       1199145600000
    

Date : jouons avec un anniversaire !

Quel jour est l'anniversaire de John en 2012 ?

>>> var d = new Date(2012, 5, 20); // Le 20 Juin !
>>> d.getDay();
       3
Dimanche = 0 donc 3 = mercredi, vérifions !
>>> d.toDateString();
       "Wed Jun 20 2012" // C'est juste !
    

Combien de fois l'anniversaire de John sera un dimanche, un lundi, etc... entre 2012 et 3012 :

var joursAnniv = [0,0,0,0,0,0,0];

for (var an = 2012; an < 3012; an++) {
  joursAnniv[new Date(an, 5, 20).getDay()]++;
}
>>> joursAnniv;
       [139, 145, 139, 146, 143, 143, 145]
143 Vendredis et 145 Samedis ! On pourra faire la fête !
    

L'objet prédéfini RegExp

JavaScript utilise la syntaxe des expressions régulières (en abrégé : une "regexp") de Perl5.

Une regexp se compose de 1) une pattern et 2) un ou plusieurs modifiers (ou "flags")

Ce cour n'est pas un cours sur les regexp Perl5, il montre comment les utiliser en JavaScript.

Le constructeur RegExp() sert à construire une expression régulière :

// regexp qui matche un élément qui commence par j, finit par t
 // avec 0 ou plusieurs caractères entre les deux
>>> var re = new RegExp("j.*t");
// Autre écriture sans le constructeur
>>> var re = /j.*t/;
    

Propriétés de l'objet RegExp

global : vaut false par défaut. S'arrête au premier match, sinon si true renvoie tous les matches.

ignoreCase : sensible aux majuscules/minuscules. False par défaut.

multiline: les matches peuvent être sur plusieurs lignes. False par défaut,

lastIndex: la position où démarrer la recherche, valeur par défaut = 0.

source: contient la valeur de la regexp.

A part lastIndex, ces propriétés ne peuvent être modifiées après la création de la RegExp.

RegExp : paramètres du constructeur

Les trois premieres valeurs du transparent précédent sont des modifiers de la RegExp (global, ignoreCase, multiline).

On peut passer n'importe quelle combinaison de ces paramètres en second paramètre du constructeur :

  • 'g' pour "global"
  • 'i' pour "ignoreCase"
  • 'm ' pour "multiline"
>>> var re = new RegExp('j.*t', 'gmi'); // l'ordre est peu
                                    // important img, gmi, etc.
>>> re.global; // vérifions que global est bien positionné
       true
    

L'objet RegExp suite...

>>> re.global = false;
>>> re.global // On ne peut modifier un modifieur une fois l'objet
        true  // construit !
    

Voici comment on peut reinitialiser l'objet :

>>> var re = /j.*t/ig; // modifieurs après le slash
>>> re.global
   true         
    

Méthodes de l'objet RegExp

L'objet regexp fournit deux méthodes :

  1. test(string) : renvoie un booléen indiquant s'il y a eu un matching entre le paramètre et la regexp,
  2. exec(string) : renvoie un tableau de strings matchées.
>>> /j.*t/.test("Javascript")
    false // A cause du J majuscule !
>>> /j.*t/i.test("Javascript")
    true  // Grace au /i !

 >>> /j.*t/i.exec("Javascript")[0]
    "Javascript" // première chaine matchée
    

Méthodes de l'objet String qui acceptent des RegExp en paramètres

  • match() : renvoie un tableau de string matchées,
  • search() : renvoie la position du premier matching,
  • replace() : permet de substituer les strings matchées par un autre texte,
  • split() : accepte une RegExp lorsqu'on splitte une string en tableau de strings

search() et match(), par l'exemple...

 >>> var s = new String('HelloJavaScriptWorld');
 >>> s.match(/a/);
       ["a"]
 >>> s.match(/a/g);
       ["a", "a"] // g pour search global, deux a dans Java !
 >>> s.match(/j.*a/i);
       ["Java"]
 >>> s.search(/j.*a/i);
       5 // Position du premier match
    

replace(), par l'exemple...

 >>> var s = new String('HelloJavaScriptWorld');
 s.replace(/[A-Z]/g, ''); // Supprime toutes les majuscule, globalement
      "elloavacriptorld"
>>> s.replace(/[A-Z]/, ''); // non global !
 "elloJavaScriptWorld"
    

Si lors d'un match on veut inclure le texte matché, on utilise $&.

 >>> s.replace(/[A-Z]/g, "_$&");
 "_Hello_Java_Script_World"
    

replace(), suite...

Lorsque la regexp contient des groupes, notés par des (...), $1 représente le premier groupe, $2 le second, etc...

>>> var email = "stoyan@phpied.com";
>>> var username = email.replace(/(.*)@.*/, "$1");
>>> username;
     "stoyan"
    

replace(), suite: utilisation de callbacks

On peut passer une fonction comme second paramètre d'un appel à replace(). Dans ce cas, la fonction de callback reçoit plusieurs paramètres automatiquement.

>>> function replaceCallback(match){return "_" + 
             match.toLowerCase();}
>>> s.replace(/[A-Z]/g, replaceCallback);
       "_hello_java_script_world"        
    

Paramètres de la fonction de callback (on a utilisé que le premier dans l'exemple précédent):

  • Premier paramètre: la string matchée,
  • Dernier paramètre: la string recherchée,
  • Avant dernier paramètre: position de la string matchée,
  • Autres paramètres: autres strings matchées par des groupes dans la regexp.

replace() et callback: un exemple !

>>> var glob; // pour mémoriser les paramètres reçus
              // par le callback

>>> var re = /(.*)@(.*)\.(.*)/; // Pour marcher email

var callback = function(){
  glob = arguments;
  return arguments[1] + ' at ' + arg
         arguments[3];
}

>>> "stoyan@phpied.com".replace(re, callback);
       "stoyan at phpied dot com"

>>> glob // les paramètres reçus par le callback
       ["stoyan@phpied.com", "stoyan", "phpied", "com", 0,
       "stoyan@phpied.com"]
    

split(), par l'exemple !

>>> var csv = 'one, two,three ,four';
>>> csv.split(',');
    ["one", " two", "three ", "four"]        
    

Ah, on a récupéré aussi les espaces ! Utilisons donc une regexp : \s* indique "un ou plusieurs espaces".

 >>> csv.split(/\s*,\s*/)  // "," mais avec espaces avant et après !
    ["one", "two", "three", "four"]
    

Passer une string en paramètre quand une RegExp est attendue...

Dans ce cas, c'est comme si la string est un paramètre d'un constructeur de RegExp :

 >>> "test".replace('t', 'r')
       "rest"
    

Identique à :

 >>> "test".replace(new RegExp('t'), 'r')
       "rest"
    

L'objet prédéfini Error