ES6


exemple de décomposition

Allez dans votre console et tapez :
const doc = document.documentElement;
const { clientWidth, clientHeight } = doc;
console.log( `la largeur de la fenêtre est : ${clientWidth} ` );

MAp en action

let tag = [];

explore = (node) => {
    for (let elt of node.children) {
            tag.push(elt.nodeName);
            explore(elt);
      }
    }

explore(document.body); //

getEleCnt = (arr) => {
      return arr.reduce(function(prev,next){
         prev.has(next) ? prev.set(next,prev.get(next) + 1) :prev.set(next,1);        
        return prev;
      },new Map());
    }
 
let allCntEle = getEleCnt(tag);

for(let [u, r] of allCntEle.entries())
console.log(`${u}: ${r}`);

Class en action


HTML : 

<article class="td">
   <section> ...</section>
   <section> ... </section>
</article>


CSS



.hide {
   overflow : hidden;
   opacity:0;
   max-height : 0px;
   transition:all 2s ease;
   padding : 10px;
}

article>section+section {
   max-height : 300px;
   overflow : hidden;
   opacity:1;
   background-color : black;
   color : white;
   padding : 10px;
   transition:all 2s ease;
}

JS

class tdHandler {

     constructor(el) { // el = article
          this.el= el;
     }

    init() {
      this.el.addEventListener("click", () => this.action(), false);
      return this;
     }
    
    action( ) {
       this.el.lastElementChild.classList.toggle('hide');
       return this;
    } 
};

Array.from(document.querySelectorAll('.td'), (el) =>{
  let h = new tdHandler(el).init().action();
});

Parcours du Dom

allTag = (node) =>{

    let tag = [],
        allEle = {};


    _explore = (node) => {
      for (let elt of node.children) {
            tag.push(elt.nodeName);
            _explore(elt);
      }
    }


    _explore(node);
 
    _getWordCnt = (arr) => {
      return arr.reduce(function(prev,next){
        prev[next] = (prev[next] + 1) || 1;
        return prev;
      },{});
    }
 
    allEle = _getWordCnt(tag);

    //allEle {div:2,p:10}


    console.log(Object.keys(allEle).map(key => `${key}*${allEle[key]} `));

   console.log(`La balise la plus utilisée est : ${Object.keys(allEle).reduce((keya, keyb) =>allEle[keya] > allEle[keyb] ? keya : keyb)}`);

    let all = Object.keys(allEle).sort((keya, keyb) => allEle[keyb] - allEle[keya]);


    console.log("par ordre de présence  ** ");
    for (var b of all) {
         console.log(` ${b} ${allEle[b]} ` );
    }

 
    return allEle;


}


let a = allTag(document.body);


for (var b in a) {
  if (a.hasOwnProperty(b)) {
    console.log(`la balise ${b} apparaît ${a[b]} fois  ` );
  }
}


Parcours du dom

ES2015
Before ES2015
byTagName = (node, tagName) => {
    const found = [];
    tagName = tagName.toUpperCase();
   
   _explore = (node) => {
      for (let elt of node.childNodes) {
     
          if (elt.nodeType == document.ELEMENT_NODE)
            if (elt.nodeName == tagName)
             found.push(elt);
            _explore(elt);
      }
    }

    _explore(node);
    return found;
}
  function byTagName(node, tagName) {
    var found = [];
    tagName = tagName.toUpperCase();

    function explore(node) {
      for (var i = 0; i < node.childNodes.length; i++) {
        var child = node.childNodes[i];
        if (child.nodeType == document.ELEMENT_NODE)
          if (child.nodeName == tagName)
            found.push(child);
          explore(child);
      }
    }

    explore(node);
    return found;
  }

code fichierJS Bin on jsbin.com

Amélioration du code

code fichierJS Bin on jsbin.com

test fonction fléchée (pas de fonction flechée dans class)

En action


Nous allons étudier différents codes ! Coller les différentes version de js




HTML

<img src="http://www.exisoftware.com/thumbnail_generator/sample-galleries/basic-web-photo-gallery/thumbs/tn_IMG_0001.jpg" data-larger="http://www.exisoftware.com/thumbnail_generator/sample-galleries/basic-web-photo-gallery/images/IMG_0001.JPG"

alt="jolie" />


CSS


body, html
{
width: 100%; height: 100%;
  overflow : hidden;
}

img{
   padding: 10px;
   width : 100px;
}

.overlay{
    opacity : 0.8;
    color : red;
    position: fixed;
    width: 100%;
    height: 100%;
    top: 0;
    bottom: 0px;
    left: 0px;
    right: 0px;
    padding: 0 8px;
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    background-color: #000;
    overflow: hidden;

}
.overlayimg
{
    width: 60%;
    margin: auto;
    text-align: center;
    position: fixed;
    z-index: 3;
    top: 0;
    bottom: 0px;
    left: 0px;
    right: 0px;
    padding: 0px 10px 10px;

}

JS

class imgHandler {

     constructor(el) { // like array img
          this.el= el;
     }

     init = () => {
          for(let img of this.el) {
             img.addEventListener('click',() => this._action(img));
          }
     }

     _action = (photo) => {

            let overlay = document.createElement("div");
            overlay.setAttribute("id","overlay");
            overlay.classList.add("overlay");

            document.body.appendChild(overlay);

            let img = document.createElement("img");

            img.setAttribute("id","img");
 // el
             img.src = photo.dataset.larger;

             img.classList.add("overlayimg");

             img.addEventListener('click',this._restore);
             document.body.appendChild(img);
  
           

    }

    _restore = () => {
         console.log("stop");
         document.body.removeChild(document.getElementById("overlay"));
         document.body.removeChild(document.getElementById("img"));
    }

};


var imgs = new imgHandler(document.querySelectorAll('img'));

imgs.init();


version ES6


class imgHandler {



     constructor(el) { // array like

          this.el= el;

     }

    init = () => {

      Array.from(this.el, (img) => img.addEventListener('click',() => this._action(img))); //es6 array like
      
     }
    
    _action = (el) => {

            let overlay = document.createElement("div");
            overlay.setAttribute("id","overlay");
            overlay.classList.add("overlay");
  
            document.body.appendChild(overlay);
  
            let img = document.createElement("img");

            img.setAttribute("id","img");
  
         // console.log(el)
             img.src = el.dataset.larger;
  
             img.classList.add("overlayimg");

             img.addEventListener('click',this._restore(img));
             document.body.appendChild(img);

         
           
    }

    _restore = (photo) => {
      return function(){
         console.log("stop");
         document.body.removeChild(document.getElementById("overlay"));
         document.body.removeChild(document.getElementById("img"));
      }
    }

};


var imgs = new imgHandler(document.querySelectorAll('img'));

imgs.init();


version : For of

class imgHandler {

     constructor(el) { // like array img
          this.el= el;
     }

     init = () => {
          let self = this; // this=self=objet imgHandler
          for(let img of this.el) {
                img.addEventListener('click', () => {
                    console.log(self === this); // oui
                    self._action(img);
                })
          }
     }
 
     _action = (el) => {
     
           let overlay = document.createElement("div");
            overlay.setAttribute("id","overlay");
            overlay.classList.add("overlay");

            document.body.appendChild(overlay);

            let img = document.createElement("img");

            img.setAttribute("id","img");
 // el
             img.src = el.dataset.larger;

             img.classList.add("overlayimg");

             img.addEventListener('click',this._restore);
             document.body.appendChild(img);

    }

    _restore = () => {
         console.log("stop");
         document.body.removeChild(document.getElementById("overlay"));
         document.body.removeChild(document.getElementById("img"));
    }

};


var imgs = new imgHandler(document.querySelectorAll('img'));

imgs.init();


Autre version :



class imgHandler {



     constructor(el) { // array like

          this.el= el;

     }



    init = () => {


      Array.from(this.el, (img) => img.addEventListener('click',this._action(img))); //es6 array like
      
     }
    
    _action = (el) => {
            self = this;
            return function(){
                let overlay = document.createElement("div");
            overlay.setAttribute("id","overlay");
            overlay.classList.add("overlay");
  
            document.body.appendChild(overlay);
  
            let img = document.createElement("img");

            img.setAttribute("id","img");
  
         // console.log(el)
             img.src = el.dataset.larger;
  
             img.classList.add("overlayimg");

             img.addEventListener('click',self._restore(img));
             document.body.appendChild(img);

            }
         
           
    }

    _restore = (photo) => {
      return function(){
         console.log("stop");
         document.body.removeChild(document.getElementById("overlay"));
         document.body.removeChild(document.getElementById("img"));
      }
    }

};


var imgs = new imgHandler(document.querySelectorAll('img'));

imgs.init();

Autre version

class imgHandler {

     constructor(el) { // pas de fx arrow
          this.el= el;
     }

    init = () => {
          let self = this;
          for(let img of this.el) {
                img.addEventListener('click', function(){
                    console.log(self === this); //false
                    self._action(img);
                    //self._action(this);
//self = Object imghandler et this = img courante
                })
          }
     }
    
    _action = (el) => {
           console.log("click");
           let overlay = document.createElement("div");
            overlay.setAttribute("id","overlay");
            overlay.classList.add("overlay");
  
            document.body.appendChild(overlay);
  
            let img = document.createElement("img");

            img.setAttribute("id","img");
  
         // console.log(el)
             img.src = el.dataset.larger;
  
             img.classList.add("overlayimg");

             img.addEventListener('click',this._restore(img));
             document.body.appendChild(img);

    }

    _restore = (photo) => {
      return function(){
         console.log("stop");
         document.body.removeChild(document.getElementById("overlay"));
         document.body.removeChild(document.getElementById("img"));
      }
    }

};


var imgs = new imgHandler(document.querySelectorAll('img'));

imgs.init();


autre version : closure

class imgHandler {

     constructor(el) { // pas de fx arrow
          this.el= el;
     }

    init = () => {

      for(let i=0; i<this.el.length ; i++) {
       this.el[i].addEventListener('click',this._action(this.el[i]))
      }

      
     }
    
    _action = (el) => {
       let self = this;
       return function(){
       
           console.log( this); // img
           console.log(self); // imgHandler

           let overlay = document.createElement("div");
            overlay.setAttribute("id","overlay");
            overlay.classList.add("overlay");
  
            document.body.appendChild(overlay);
  
            let img = document.createElement("img");

            img.setAttribute("id","img");
  
         // console.log(el)
             img.src = el.dataset.larger;
  
             img.classList.add("overlayimg");

             img.addEventListener('click',self._restore(img));
             document.body.appendChild(img);

       }
           
    }

    _restore = (photo) => {
      return function(){
         console.log("stop");
         document.body.removeChild(document.getElementById("overlay"));
         document.body.removeChild(document.getElementById("img"));
      }
    }

};


var imgs = new imgHandler(document.querySelectorAll('img'));

imgs.init();


version ! 


class imgHandler {

     constructor(el) { // pas de fx arrow
          this.el= el;
     }

    init = () => {

      for(let i=0; i<this.el.length ; i++) {
       this.el[i].addEventListener('click',this._action())
      }

   
     }
 
    _action = () => {
   
       let self = this;
   
       return function(){
         
           console.log(this); // img
           console.log(self); // imgHandler
       
           let overlay = document.createElement("div");
            overlay.setAttribute("id","overlay");
            overlay.classList.add("overlay");

            document.body.appendChild(overlay);

            let img = document.createElement("img");

            img.setAttribute("id","img");

         // console.log(this)
             img.src = this.dataset.larger;

             img.classList.add("overlayimg");

             img.addEventListener('click',self._restore(img));
             document.body.appendChild(img);

       }
         
    }

    _restore = (photo) => {
      return function(){
         console.log("stop");
         document.body.removeChild(document.getElementById("overlay"));
         document.body.removeChild(document.getElementById("img"));
      }
    }

};


var imgs = new imgHandler(document.querySelectorAll('img'));

imgs.init();



itérateurs sur un objet !

class Log{
  constructor(){
    this.messages = [];
  }
  add(message){
    this.messages.push({message, timestamp : new Date()});
  }
  [Symbol.iterator]() {
    //return this.messages.values();
    let i=0;
    const messages = this.messages;
    return {
      next() {
        if ( i >= messages.length)
          return { value : undefined, done: true};
        return { value: `N°${i} : ${messages[i].message} @ ${messages[i++].timestamp}`, done: false};
      }
    }
  }
}

const log = new Log();
log.add("premier");
log.add("second");

console.log([...log]);

code source


JS Bin on jsbin.com

Itérateurs

let elements = document.querySelectorAll("div"),
    callback = (el) => { console.log(el.name); };

elements[Symbol.iterator] = function () {
  let i = 0;
  const Max = 2;

  return { 
    next () {
      if ( i > Max ) 
        return { value : undefined, done: true };
       return { value : `\nLe ${elements[i].nodeName} N°${i} \t a pour texte ${elements[i++].textContent}`, done: false};
    }
  };
};

console.log([...elements]);



JS Bin on jsbin.com

itérations sur les nodeList

let elements = document.querySelectorAll("div"),
    callback = (el) => { console.log(el.name); };

// Spread operator
[...elements].forEach(callback);

// Array.from()
Array.from(elements).forEach(callback);

// for...of statement
for (let div of elements) callback(div);

fichier code

JS Bin on jsbin.com

//itérator
elements[Symbol.iterator]();
elements.forEach(callback)

console.log("-----");
elements[Symbol.iterator] = function* () {
    yield "un nd";
    yield 2;
    yield "fin";
};

console.log([...elements]);

var dans les boucles !



let tab = ["a","b","c"];

var printI = function(){
     console.log(tab[i]);
};

for (var i=0; i<tab.length;i++){
    setInterval(printI, 1000*(i+1));
}
let tab = ["a","b","c"];
var i; // i sera égal à  3 lors des appels
var printI = function(){
     console.log(tab[i]);
};

for (i=0; i<tab.length;i++){
    setInterval(printI, 1000*(i+1));
}

for (var i=0; i<tab.length;i++){
     setTimeout(function(){
       console.log("in call back " + i);
     }, 3000*(i+1));
}

Correction avec closure

"use strict";

var _loop = function _loop(i) {
    setTimeout(function () {
        console.log("in call back " + tab[i]);
    }, 1000 * (i + 1));
};

for (var i = 0; i < tab.length; i++) {
    _loop(i);
}


Correction  : 

for (let i=0; i<tab.length;i++){
    setTimeout(function(){
        console.log("in call back " + tab[i]);
    }, 1000*(i+1));
}




nous sommes editables
C'est moi le plus grand !
Ecrivez ici des mots

... en action


Voici un élégant moyen de remplacer concat.

const T1 = ["Dupont", "Whells", "toto"];

const T2 = ["Dupond", "Whells", "titi"];

console.log(T1);
console.log(...T1);
console.log( [...T1 , ...T2] );



const promos = [
  { promo: "L3miage", etudiants: ["Dupont", "Whells", "Toto"]},
  { promo: "L2miage", etudiants: ["Dupond", "Pathé"]},
  { promo: "M1miage", etudiants: ["Audu", "Baby"]},
]

const tousEtudiants = promos.reduce(function(prev, curr) {
  return [...prev, ...curr.etudiants];
},[]);

console.log(tousEtudiants.sort());

transposé !



const A = [
  [1,3,5],
  [2,4,6]
];

let At = A[0].map( (_,col) => A.map( (lig,_) =>lig[col]));

console.log(`|${A.join("|\n|")}| `) ;

console.log(`|${At.join("|\n|")}| `) ;

Création d'un objet

class elHandler {

     constructor(el) { // pas de fx arrow
          this.el= el;
          
          this.init();
     }

    init = () => {
      this.el.addEventListener("click",
                event => this._action(event.type,this.el), false);
      return this;
     }
    
    _action = (type,el) => {
       console.log(` Handling + ${type} for ${el.id} `);
       el.classList.toggle("red");
       return this;
    }

};


let objDiv = new elHandler(document.getElementById("para1"));




Remarque :

Examiner le code pour

class elHandler { constructor(el) { // pas de fx arrow this.el= el; this.init(); } init(){ this.el.addEventListener("click", event => this._action(event.type,this.el), false); return this; } _action = (type,el) => { console.log(` Handling + ${type} for ${el.id} `); el.classList.toggle("red"); return this; } }; var objDiv = new elHandler(document.getElementById("para1")); Et finalement

class elHandler { constructor(el) { // pas de fx arrow this.el = el; this.init(); } init() { this.el.addEventListener("click", function(event) { document.body.insertAdjacentHTML('beforeend', `<div id="two">this.ed = ${this.el}</div>`); this._action(event.type, this.el) }, false); return this; } _action = (type, el) => { el.classList.toggle("red"); return this; } };

Plus de perte du this au passage d'argument : fonction flèchées

Lire article

En Javascript, quand on passe une méthode en argument, on perd le contexte. 


  1. class Person{
  2.   constructor(age){
  3.     this.age = age;
  4.   }

  5.   birthday(){
  6.     this.age++;
  7.   }
  8. }

  9. let denis = new Person(50);
  10. console.log(denis.age);

  11. // passage fonction en argument 

  12. let test = (methode) =>  methode();

  13. test(denis.birthday.bind(denis));

Exit !

coucou
Stop

all objet

var map = ["#####",
           "#   #",
           "# o #",
           "#   #",
           "#####"];

class BouncingCritter {
  constructor (){
    this.direction = randomElement(directionNames);
  }

  act(view) {
     //console.log("reche dans la dir = " + this.direction);
    if (view.look(this.direction) != " "){
    //console.log(" cherche");
    this.direction = view.find(" ") || "s";
    //console.log("dir trouve espace  = " + this.direction);
  }

  return {type: "move", direction: this.direction};
  }
}




class Wall {

}


class Vector {
  constructor (x, y){
    this.x = x;
    this.y = y;
  }

  plus (other) { return new Vector(this.x + other.x, this.y + other.y);}

}
class Grid {
  constructor (W, H){
    this.width = W;
    this.height = H;
    this.space = Array.from(new Array(this.height*this.width));
  }
  getS (vector) {return this.space[vector.x + this.width * vector.y];}
  getSpace () {return this.space;}
  setS (vector, value){this.space[vector.x + this.width * vector.y] = value;}
  map (f) {
    //console.log(this.space.map(f));
    return this.space.map(f);}
  isInside (vector) {return vector.x >= 0 && vector.x < this.width &&
         vector.y >= 0 && vector.y < this.height;}
  forEach(f) {
    //console.log("foreach cool");
    this.space.forEach((elt,i) => {
       if (elt != null){
          //console.log(i%this.width+ " " +Math.floor(i/this.width));
          f(elt, new Vector(i%this.width,Math.floor(i/this.width)));
       }
     });

  }
}
function elementFromChar(legend, ch) {
  if (ch == " ")
    return null;
  //console.log(legend);
  var element = new legend[ch]();
  element.originChar = ch;
  return element;
}
function charFromElement(element) {
  if (element == null)
    return " ";
  else
    return element.originChar;
}
class World {
  constructor (map,legend){
    this.grid = new Grid(map[0].length, map.length);
    this.legend = legend;
  }
  setS (){
    map.forEach( (line,y) => {
      line.split("").forEach( (char,x) => {
           //console.log(x + " " + " " + y + " " +char + " " +elementFromChar(this.legend,char));
           this.grid.setS(new Vector(x,y),elementFromChar(this.legend,char));
      });
    });
  }
  toString () {
     return (
    this.grid.getSpace().map( (elt) => charFromElement(elt))
                        .reduce((p,n,i) => (i%this.grid.width===0) ? (p+"\n"+n) : (p+n))
  );
  }

  turn () {
  //console.log("turn");
  var acted = [];
  this.grid.forEach( (critter, vector) => {
    if (critter.act && acted.indexOf(critter) == -1) {
      acted.push(critter);
      this.letAct(critter, vector);
    }
  });
  }

  letAct(critter, vector) {
  //console.log(critter);
  //console.log(vector);
  var action = critter.act(new View(this, vector));
  if (action && action.type == "move") {
    var dest = this.checkDestination(action, vector);
    if (dest && this.grid.getS(dest) == null) {
      this.grid.setS(vector, null);
      this.grid.setS(dest, critter);
    }
  }
  }

  checkDestination(action, vector) {
  if (directions.hasOwnProperty(action.direction)) {
    var dest = vector.plus(directions[action.direction]);
    if (this.grid.isInside(dest))
      return dest;
  }
  }

}




var directions = {
  "n":  new Vector( 0, -1),
  "ne": new Vector( 1, -1),
  "e":  new Vector( 1,  0),
  "se": new Vector( 1,  1),
  "s":  new Vector( 0,  1),
  "sw": new Vector(-1,  1),
  "w":  new Vector(-1,  0),
  "nw": new Vector(-1, -1)
};


function randomElement(array) {
  return array[Math.floor(Math.random() * array.length)];
}

var directionNames = "n ne e se s sw w nw".split(" ");
//console.log(directionNames);

class View {
  constructor (world, vector){
    this.world = world;
    this.vector = vector;
  }

  look(dir) {
  var target = this.vector.plus(directions[dir]);
  //console.log(target);
  if (this.world.grid.isInside(target))
    return charFromElement(this.world.grid.getS(target));
  else
    return "#";
  }

  findAll(ch) {
  var found = [];
  for (var dir in directions){
    if (this.look(dir) == ch){
      //console.log('ch' + ch);
      found.push(dir);
    }
  }
  return found;
  }

  find(ch) {
  //console.log("ds find ch= " + ch);
     var found = this.findAll(ch);
  //console.log("ds find" + found);
     if (found.length == 0) return null;
     return randomElement(found);
  }

}





var world = new World(map,
                   {"#" : Wall,
                    "o" : BouncingCritter});
 world.setS();
for (var i = 0; i < 1; i++) {
  world.turn();
  console.log(world.toString());
}

etape2

JS Bin on jsbin.com

var map = ["#####",
           "#   #",
           "# o #",
           "#   #",
           "#####"];

function BouncingCritter() {
  this.direction = randomElement(directionNames);
  //console.log(this.direction);
}

BouncingCritter.prototype.act = function(view) {

  //console.log("reche dans la dir = " + this.direction);
  if (view.look(this.direction) != " "){
    //console.log(" cherche");
    this.direction = view.find(" ") || "s";
    //console.log("dir trouve espace  = " + this.direction);
  }
 
  return {type: "move", direction: this.direction};
};

function Wall() {};



class Vector {
  constructor (x, y){
    this.x = x;
    this.y = y;
  }

  plus (other) { return new Vector(this.x + other.x, this.y + other.y);}

}
class Grid {
  constructor (W, H){
    this.width = W;
    this.height = H;
    this.space = Array.from(new Array(this.height*this.width));
  }
  getS (vector) {return this.space[vector.x + this.width * vector.y];}
  getSpace () {return this.space;}
  setS (vector, value){this.space[vector.x + this.width * vector.y] = value;}
  map (f) {
    //console.log(this.space.map(f));
    return this.space.map(f);}
  isInside (vector) {return vector.x >= 0 && vector.x < this.width &&
         vector.y >= 0 && vector.y < this.height;}
  forEach(f) {
    //console.log("foreach cool");
    this.space.forEach((elt,i) => {
       if (elt != null){
          //console.log(i%this.width+ " " +Math.floor(i/this.width));
          f(elt, new Vector(i%this.width,Math.floor(i/this.width)));
       }
     });

  }
}
function elementFromChar(legend, ch) {
  if (ch == " ")
    return null;
  //console.log(legend);
  var element = new legend[ch]();
  element.originChar = ch;
  return element;
}
function charFromElement(element) {
  if (element == null)
    return " ";
  else
    return element.originChar;
}
class World {
  constructor (map,legend){
    this.grid = new Grid(map[0].length, map.length);
    this.legend = legend;
  }
  setS (){
    map.forEach( (line,y) => {
      line.split("").forEach( (char,x) => {
           //console.log(x + " " + " " + y + " " +char + " " +elementFromChar(this.legend,char));
           this.grid.setS(new Vector(x,y),elementFromChar(this.legend,char));
      });
    });
  }
  toString () {
     return (
    this.grid.getSpace().map( (elt) => charFromElement(elt))
                        .reduce((p,n,i) => (i%this.grid.width===0) ? (p+"\n"+n) : (p+n))
  );
  }
}
World.prototype.turn = function() {
  //console.log("turn");
  var acted = [];
  this.grid.forEach( (critter, vector) => {
    if (critter.act && acted.indexOf(critter) == -1) {
      acted.push(critter);
      this.letAct(critter, vector);
    }
  });
};


World.prototype.letAct = function(critter, vector) {
  //console.log(critter);
  //console.log(vector);
  var action = critter.act(new View(this, vector));
  if (action && action.type == "move") {
    var dest = this.checkDestination(action, vector);
    if (dest && this.grid.getS(dest) == null) {
      this.grid.setS(vector, null);
      this.grid.setS(dest, critter);
    }
  }
};

World.prototype.checkDestination = function(action, vector) {
  if (directions.hasOwnProperty(action.direction)) {
    var dest = vector.plus(directions[action.direction]);
    if (this.grid.isInside(dest))
      return dest;
  }
};

var directions = {
  "n":  new Vector( 0, -1),
  "ne": new Vector( 1, -1),
  "e":  new Vector( 1,  0),
  "se": new Vector( 1,  1),
  "s":  new Vector( 0,  1),
  "sw": new Vector(-1,  1),
  "w":  new Vector(-1,  0),
  "nw": new Vector(-1, -1)
};


function randomElement(array) {
  return array[Math.floor(Math.random() * array.length)];
}

var directionNames = "n ne e se s sw w nw".split(" ");
//console.log(directionNames);



function View(world, vector) {
  //console.log(vector);
  this.world = world;
  this.vector = vector;
}
View.prototype.look = function(dir) {
  var target = this.vector.plus(directions[dir]);
  //console.log(target);
  if (this.world.grid.isInside(target))
    return charFromElement(this.world.grid.getS(target));
  else
    return "#";
};
View.prototype.findAll = function(ch) {
  var found = [];
  for (var dir in directions){
    if (this.look(dir) == ch){
      //console.log('ch' + ch);
      found.push(dir);
    }
  }
  return found;
};
View.prototype.find = function(ch) {
  //console.log("ds find ch= " + ch);
  var found = this.findAll(ch);
  //console.log("ds find" + found);
  if (found.length == 0) return null;
  return randomElement(found);
};



var world = new World(map,
                   {"#" : Wall,
                    "o" : BouncingCritter});
 world.setS();
for (var i = 0; i < 10; i++) {
  world.turn();
  console.log(world.toString());
}