JS-2

JS-2

JavaScript Part 2

Какво ще разгледаме днес:

Scope в JavaScript

В JavaScript има функционален scope. Тоест:

Scope в JavaScript - Demo

var x = 3, y = 5;
function test (){
  if (true) {
    var y = 6;
  }
  console.log(y); // 6
  z = 8;

  for (var i = 0; i < 10; i++){
    // do something
  }
  console.log(i); // 10
}
test();
console.log(i); // undefined
console.log(x, y, z); // 3 5 8

What is this?

What is this? - Call and Apply

window.name = "Super Window";
var pesho = {age: 22, name: "Pesho"};
var gosho = {age: 21, name: "Gosho"};
var ivan = {age: 23, name: "Ivan"};
var sayHi = function () {
  return "Hi, I am " + this.name;
};
pesho.sayHi = sayHi;
pesho.sayHi.toString();   // function () { return "Hi, I am " + this.name; }
sayHi();                  // Hi, I am Super Window
pesho.sayHi();            // Hi, I am Pesho
sayHi.call(gosho);        // Hi, I am Gosho
pesho.sayHi.call(gosho);  // the same
sayHi.apply(ivan);        // Hi, I am Ivan

What is this? - Bind

var id = document.getElementById;
id('test'); // 'TypeError: Illegal invocation' - getElementById needs a context
id.call(document, 'test'); // works

// Binding it to always use document
id = document.getElementById.bind(document);
id('test'); // works

// Option 2:
id = function (id) { return document.getElementById(id); };

Patterns

Patterns - Demo

// Namespace
var ns = {
  property: "someValue",
  method: function () { alert("So Long, and Thanks for All the Fish"); }
};
// Self Invoking Anonymous Function (SIAF or IIFE)
(function(){
  for (var i = 0; i < 10; i++)
    console.log(i);
})();
// Namespace with 'private' vars
var basketModule = (function () {
  var basket = []; // 'private'
  return {
    addItem: function (item) { basket.push(item); },
    getItemCount: function() { return basket.length; }
  };
})();

ES5 Features

Някои неща, които пропуснахме миналия път

// localStorage - object that persists trough shutdown
localStorage.setItem('foo', 'bar');
localStorage.getItem('foo');

// define dynamic properties since ES5
function createDynamicProperty(obj, prop, handler) {
  var value;
  Object.defineProperty(obj, prop, {
    get: function () { return value; },
    set: function (newValue) { return handler(newValue), value = newValue; },
    enumerable: true,           //                     ^ this looks strange,
    configurable: true          //                     | but is valid js...
  });                           //                     | don't do this
}

JQuery

This is a div with id = my-id
$('#my-id')
//.val()        // returns element.value (for input tags)
//.text()       // returns element.textContent
//.html()       // returns element.innerHTML
  .html('test') // same as element.innerHTML = value
//.css('font-size') // returns 10px
  .css('font-size', '20px')
  .css({color: 'lime', background: 'midnightblue'})
//.attr('class')             // gets the attribute
  .attr('class', 'my-class') // sets the attribute
  .hide().show()
  .slideUp(2000).slideDown(2000)
  .fadeOut(1000).fadeIn(1000)
  .on('click', logMe);      // a bit shorter than addEventListener

function logMe(event) { console.log(this, event); }

// bind a handler to the root but trigger only when the selector matches
$(document).on('click', 'button', logMe); // will work on buttons created later

JS is growing

ES6 Features

  1. let + const
  2. Arrow functions
  3. Default function params
  4. rest param, spread operator
  5. Template literals
  6. Destructuring operations
  7. Native promises
  8. Classes

ES6 - Let, Arrows, Rest, Spread

let addTwo = (x, y) => x + y;               // yay, arrow functions!
let logOne = value => console.log(value);   // with a single argument
let logMany = (x, ...rest) => {             // with a body
  console.log(x, ...rest);                  // we can still use return
};

[1, 2, 3, 4, 5, 6, 7, 8, 9]
  .filter(e => e % 2 == 0)    // [2, 4, 6, 8]
  .map(e => e * e)            // [4, 16, 36, 64]
  .reduce((a, b) => a + b)    // 120

 

Забележка - в arrow функциите `this` има стойността от момента на дефиниране

Като изключим това те имат същото поведение като нормални функции

ES6 - Const, Defaults, Templates

const friends = []; // we cannot change the reference, but we can mutate it

const meet = (name='partner', greeting='Howdy') => { // default params
  friends.push({name: name, greeting: greeting});

  return \`${greeting}, ${name}!\`;           // No need for + ' ' + stuff
};

let colors = ['#F00', '#00F']
let poem = `
  Roses are ${colors[0]},
  Violets are ${colors[1]}.
  Homeworks are rough,
  But at least we're tough!
`;

ES6 - Destructuring and Promises

// ES 5
var name = student.name;
var grade = student.grade;
var degree = student.degree;
var names = 'Ivan I. Petrov'.split(' ');
var first = names[0];
var last = names[2];

async1(input, function(data) {
  async2(data, function(data2) {
    async3(data2, function(data3) {
      async4(data3, function(data4) {
        // Welcome to Callback Hell
        darthVaderNoAudio.play();
      });
    });
  });
});
// ES 6
let {name, grade, degree} = student;

let [first, ,last] = 'Ivan I. Petrov'.split(' ');

let greetings = friends.map(
  ({name, greeting}) => \`${name}: ${greeting}\`
).join('\n');

let pay = new Promise((resolve, reject) => {...});

async1(input)    // many libraries use them
  .then(async2)
  .then(async3)
  .then(async4)
  .then(data => nyanCatAudio.play());

ES6 Classes

// ES 5
function Person(name) {
  this.name = name;
}

Person.prototype.greet = function() {
  return 'Hi, I am ' + this.name + '.';
};

function Student(name, fn) {
  Person.call(name);
  this.fn = fn;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;
Student.prototype.greet = function() {
  var old = Person.prototype.greet.call(this);
  return old + ' My fn is ' + this.fn;
};
// ES 6
class Person {
  constructor(name) {
    this.name = name;
  }

  greet() {
    return 'Hi, I am ' + this.name;
  }
}

class Student extends Person {
  constructor(name, fn) {
    super(name);
    this.fn = fn;
  }

  greet() {
    return super.greet() + ' My fn is ' + this.fn;
  }
}

Fetch API

fetch('users.json')
  .then(response => response.json())
  .then(function(data) {
    console.log('Request succeeded with JSON response', data);
  }).catch(function(error) {
    console.log('Request failed', error);
  });

Изисква браузъра да поддържа Promises и Fetch API (87% support)

NodeJS

  • const http = require('http');
    
    const handler = (request, response) => {
      console.log(request.url);
      response.end('Node.js Rocks!');
    };
    
    http.createServer(handler)
      .listen(4567, (err) => console.log(err || 'listening on :4567'));
  • Polyfills & Transpilers

    Babel transpiler

  • {
      "name": "Test",
      "version": "0.1.0",
      "devDependencies": {
        "babel-cli": "^6.0.0",
        "babel-preset-env": "^1.6.1"
      },
      "scripts": { "build": "babel src -d dist" },
      "babel": { "presets": ["env"] }
    }
  • Frameworks and Libs

    Задача

    Въпроси