Google I/O ’19


Avec par ordre :

private class fields 6:57 Regex matchAll 9:16 Numeric literals 10:19 BigInt formatting 11:50 flat & flatmap 13:23 fromEntries 15:28 Map to Object conversion 16:47 globalThis 19:18 Stable sort 20:00 Intl.RelativeTimeFormat 22:45 Intl.ListFormat 24:29 Intl.DateTimeFormat -> formatRange 26:32 Intl.Locale 27:10 Top-Level await 28:12 Promise.allSettled/Promise.any 31:13 WeakRef 32:30

Class et extend : en action

fonction délégation

Utils.js

function $delegate(target, selector, type, handler, capture) {
const dispatchEvent = event => {
const targetElement = event.target;
const potentialElements = target.querySelectorAll(selector);
let i = potentialElements.length;

while (i--) {
if (potentialElements[i] === targetElement) {
handler.call(targetElement, event);
break;
}
}
};

  target.addEventListener(type, dispatchEvent, !!capture);
}

Utilisation

$delegate(target,"span","mouseover",show,true)

module : en action

Création du fichier helper.js

/**
 * querySelector wrapper
 *
 * @param {string} selector Selector to query
 * @param {Element} [scope] Optional scope element for the selector
 */
export function qs(selector, scope = document) {
return scope.querySelector(selector);
}

/**
 * addEventListener wrapper
 *
 * @param {Element|Window} target Target Element
 * @param {string} type Event name to bind to
 * @param {Function} callback Event callback
 * @param {boolean} [capture] Capture the event
 */
export function $on(target, type, callback, capture) {
target.addEventListener(type, callback, !!capture);
}

/**
 * Attach a handler to an event for all elements matching a selector.
 *
 * @param {Element} target Element which the event must bubble to
 * @param {string} selector Selector to match
 * @param {string} type Event name
 * @param {Function} handler Function called when the event bubbles to target
 *                           from an element matching selector
 * @param {boolean} [capture] Capture the event
 */
export function $delegate(target, selector, type, handler, capture) {
const dispatchEvent = event => {
const targetElement = event.target;
const potentialElements = target.querySelectorAll(selector);
let i = potentialElements.length;

while (i--) {
if (potentialElements[i] === targetElement) {
handler.call(targetElement, event);
break;
}
}
};

$on(target, type, dispatchEvent, !!capture);
}

/**
 * Encode less-than and ampersand characters with entity codes to make user-
 * provided text safe to parse as HTML.
 *
 * @param {string} s String to escape
 *
 * @returns {string} String with unsafe characters escaped with entity codes
 */
export const escapeForHTML = s => s.replace(/[&<]/g, c => c === '&' ? '&amp;' : '&lt;');

Utilisation de la fonction $on dans un fichier 

Voici la structure de l'application
avec dans le répertoire src : 

Pour utiliser la fonction $on dans app.js on écrit : 

import {$on} from './helpers.js';

Dans le fichier index.html, on utilise le code

<script src="src/app.js" type="module"></script>

Serveur

on peut utiliser simplement l'extension sous chrome.

Exemple en ligne





template

Utilisation de template :

/**
 *
 * @constructor
 */
class Template {

  constructor() {
    this.defaultTemplate = ` // notez le `
    <li data-id="{{id}}" class=""> // notez {{}} un code utilisé pour remplacer la valeur
      <div class="view">
        <input class="toggle" type="checkbox" />
        <label>{{title}}</label>
        <button class="destroy"></button>
      </div>
    </li> 
  ` // fin 
  }

  show = function(data) { //data = [tableau d'objets issus d'une bibliothèque]

    let view = ''

    for (let v of data) { // v est un objet contenant les informations
      let template = this.defaultTemplate;

      template = template.replace('{{id}}', v.id)
      template = template.replace('{{title}}', v.title)


      view = view + template
    }

    return view // une concaténation de <li>
  }
}

let view = new Template();
let li = view.show([{
    id: 1,
    title: "Hello",
  },
  {
    id: 2,
    title: "World",
  }
])

// insertion des <li> dans le DOM <ul>
document.querySelector(".todo-list").insertAdjacentHTML("afterbegin", li);




Remarque :

on pourra préférer cette écriture utilisant la méthode reduce sur le tableau items 

items.reduce((acc, item) => acc + `
<li data-id="${item.id}"${item.completed ? ' class="completed"' : ''}>
<div class="view">
<input class="toggle" type="checkbox" ${item.completed ? 'checked' : ''}>
<label>${item.title}</label>
<button class="destroy"></button>
</div>
</li>`, '');

RegEXP : en action escape

Considérer le code suivant, permettant d'échapper le code HTML (le texte saisie ne doit pas être interprété en HTML).

let p = '<h1>escapeForHTML<h1>';

let regex = /[<&]/gi;

let r = {
  '>' : '&gt;',
  '&' : '&amp;',
  '<' : '&lt;',
}

let f = function(c){
  return r[c];
}

Comparer le résultat des deux écritures :

document.body.insertAdjacentHTML("afterbegin",p);
document.body.insertAdjacentHTML("afterbegin",p.replace(regex,f));

Version compacte !

const escapeForHTML = s => s.replace(/[&<]/g, c => c === '&' ? '&amp;' : '&lt;');

document.body.insertAdjacentHTML("afterbegin",escapeForHTML("<h1> escapeForHTML </h1>"));
document.body.insertAdjacentHTML("afterbegin","<h1> escapeForHTML </h1>");

Version avec Map 

let p = '<h1>escapeForHTML<h1>';

let regex = /[<>&]/gi;

let r = new Map([
  ['>','&gt;'],
  ['&','&amp;'],
  ['<', '&lt;'],
]);

let f = c => r.get(c)

document.body.insertAdjacentHTML("afterbegin",p);

document.body.insertAdjacentHTML("afterbegin",p.replace(regex,f));