Modern JavaScript

Jordan Kasper

jordan@jordankasper.com | @jakerella

You can view these slides at http://jordankasper.com/modern-js

ECMAScript vs JavaScript vs W3C recommendations

ECMAScript vs JavaScript vs W3C recommendations

ECMAScript vs JavaScript vs W3C recommendations

Strict Mode!

"use strict";

Use it inside a function block:

// non-strict code
function() {
  "use strict";
  // strict code only!
}
// more non-strict code

Better Object support:

var newInstance = new SomeObject();

var newInstance = Object.create(SomeObject.prototype);
newInstance.constructor();

Better Object support:

var dog = {
  name: "Vincent",
  age: 9,
  get humanYears() { return this.age * 7; },
  set humanYears(y) { this.age = y / 7; }
};
dog.humanYears; // 63
dog.humanYears = 70; // dog.age is now 10

Object.keys(dog); // ["name", "age", "humanYears"]

Better Arrays:

Array.isArray(someVar); // true/false
["a", "b", "c"].indexOf("b"); // 1
["a", "b", "c"].forEach(function(value, i, arr) {
  // ...
});
["a", "b", "c"].map(function(value, i, arr) { return "new value"; });
["a", "b", "c"].filter(function(value, i, arr) { return true; });

Integrated JSON Support:

FINALLY.

JSON.stringify({ one: "1", "two": 2 });
// "{"one":"1","two":2}"

JSON.parse("{ \"one\": \"1\", \"two\": 2 }");
// { one: "1", "two": 2 }

Integrated Function binding:

FINALLY.

var o = { one: "1", two: 2};
function whatIsOne() {
  return this.one;
}
whatIsOne(); // undefined, "this" is the window

whatIsOne.bind(o)(); // "1", "this" is o
whatIsOne(); // undefined again, binding is not persistent

(W3C)

Some of the current working recommendations...

  • embedded audio (draft)
  • embedded video (draft)
  • cross-domain AJAX (draft)
  • drag / drop events (draft)
  • File API (draft)
  • geolocation (candidate)
  • multimedia access (draft)
  • history management (candidate)
  • data storage (draft)
  • mutation observers (draft)
  • query selectors (recommendation)
  • web sockets (draft)
  • web workers (draft)
  • XMLHttpRequest2 (draft)

Audio & Video

<video id="myVid" src="myVideoFile.mp4" controls></video>
<audio id="mySong" src="myAudioFile.mp3" controls></audio>

<script>
document.getElementById("myVid").play();
document.getElementById("myVid").pause();
document.getElementById("myVid").addEventListener("pause", function() {
  // do stuff ...
});

</script>

Cross-Domain Requests

Uses the new "Cross Origin Resource Sharing" (CORS) specification.

$.ajax({
  url: "http://otherdomain.com/resource",
  ...
});

Request:
  GET http://otherdomain.com/resource/ HTTP/1.1
  Referer: http://mydomain.com/
  Origin: http://mydomain.com
  ...

Response:
  Access-Control-Allow-Origin: http://mydomain.com
  Content-Type: application/json
  ...

Drag 'n Drop

<p draggable="true">Some Text</p>

Not impressed yet?

Drag 'n Drop

<p id="dragger" draggable="true">Some Text</p>

document.getElementById("dropZone")
  .addEventListener("dragover", function(e) {
    // keep browser from being stupid...
    e.preventDefault();
  })

document.getElementById("dropZone")
  .addEventListener("drop", function(e) {
    e.target.innerHTML = document.getElementById("dragger").outerHTML;
  });

<div id="dropZone"></div>

File API

Choose a picture:


<input type="file" id="pic" />

<script>
document.getElementById("pic")
  .addEventListener("change", function(e) {
    var reader = new FileReader();

    reader.onload = function(readEvent) {
      $("#pic").before(
        "<img src='"+readEvent.target.result+"' width='50' />"
      );
    };

    reader.readAsDataURL(e.target.files[0]);
  });
</script>

Geolocation

navigator.geolocation.getCurrentPosition(
  function(position) {
    position.coords.latitude;
    position.coords.longitude;
  },
  function() {
    // error handler
    // (or the user didn't allow it)
  }
);

User Media

<video id="me"></video>

<script>
navigator.webkitGetUserMedia(
  {video: true, audio: false},
  function(stream) {
  
    document.getElementById("me").src = window.URL.createObjectURL(stream);

  },
  function(e) {
    // uh oh... failed
  }
);

// on button click
document.getElementById("me").play(); // or .pause()
</script>


History Management

No more URL hashes!

document.getElementById("someLink")
  .addEventListener("click", function(e) {
    history.pushState(
      "Some link clicked",
      "The New Page Title",
      "/new-url"
    );
  });

window.addEventListener("popstate", function(e) {
  // do something when the user hits the back button
  e.state; // "Some previous state"
});

Data Storage

Two types: sessionStorage and localStorage

sessionStorage: only lasts while the session is active
(usually meaning the browser window is open)

localStorage: lasts indefinitely
(until the user clears browser data)

Data Storage

Both types of storage only store strings!!

sessionStorage.foo = "bar";
localStorage.foo = "bar";

console.log(localStorage.foo); // "bar"

// Want to store bigger objects?
var options = {
  "username": "jakerella",
  "password": "correcthorsebatterystaple",
  "lastLoginTime": (new Date()).getTime()
};
localStorage.userOptions = JSON.stringify(options);

// later on...
var oldOptions = JSON.parse(localStorage.userOptions);

Mutation Observers

var observer = new WebKitMutationObserver(function(mutations) {
  mutations.forEach(function(mutation) {
    // handle mutation (or do nothing and move on to the next)
  })
});
observer.observe(document, { childList: true });

Query Selector

var nodes = document.querySelectorAll(".slide p strong, .dropZone");

var nodes = $(".slide p strong, .dropZone");

Query Selector

Web Sockets

http://takashi-matsuo.blogspot.com/2009/12/integrating-websockets-with-appengine.html

Web Sockets

var connection = new WebSocket(
  "ws://api.mydomain.com/chat", 
  ["xmpp"]
);

connection.onmessage = function(e) {
  e.data; // our new message!
}
connection.onerror = function(e) {
  // handle errors
}

...

connection.send("Hello World!");

Web Sockets

Don't forget the server!

Web Workers

For asynchronous actions that can happen in the background.

No access to the window or DOM (document).

Web Workers

// IN OUR MAIN SCRIPT
var worker = new Worker("some-code.js");
worker.addEventListener("message", function(e) {
  
  // handle the result of the work (e.data)

}, false);
worker.postMessage("Start!");


// IN THE WORKER
this.addEventListener("message", function(e) {
  
  // do some work, maybe use e.data passed in
  
  this.postMessage("I'm done!");
  
  this.close();
  // or you could leave it open to receive
  // more messages and do more work
}, false);

XMLHttpRequest - II (Revenge of the Ajax)

XMLHttpRequest - II

Getting binary data as a blob without workarounds...

var xhr = new XMLHttpRequest();
xhr.open("GET", "images/picard.jpg", true);
xhr.responseType = "blob";

xhr.onload = function(e) {
  if (this.status == 200) {
    var blob = new Blob([this.response], {type: "image/jpg"});
  }
};

xhr.send();

XMLHttpRequest - II

Sending files!! FINALLY.

document.getElementById("someFile")

  .addEventListener("change", function(e) {

    var formData = new FormData();
    // the magic:
    formData.append(this.files[0].name, this.files[0]);

    var xhr = new XMLHttpRequest();
    xhr.open("POST", "/some-script", true);
    xhr.onload = function(e) { ... };

    xhr.send(formData);
    // will switch to "multipart/form-data" automatically!

  });

XMLHttpRequest - II

Combine file uploads with better progress notification!

<progress min="0" max="100" value="0" id="upload"></progress>

document.getElementById("someFile")
  .addEventListener("change", function(e) {
    ...

    xhr.upload.onprogress = function(e) {
      if (e.lengthComputable) {
        document.getElementById("upload").value = 
                                (e.loaded / e.total) * 100);
      }
    };

    xhr.send(formData);
  });

ECMAScript 6

  • Some syntactic sugar for "classes"
  • Proper external modules and importing (see Node)
  • Constants
  • Default function arguments
  • Spread (...) operator
  • Proper iterators
  • Maps and Sets
  • yield (sort of)
  • Various other accoutrements

Modern JavaScript

Thank you!

Jordan Kasper

jordan@jordankasper.com | @jakerella

You can view these slides at http://jordankasper.com/modern-js

Some references