Beautiful JavaScript

ECMAScript 2015 / ES6

code.ryan.lee@gmail.com

Introduction

그럼에도 불구하고

  • cross browsing

  • transpiler

2009.12 ES5

2015.06 ES6

2016.06 ES7

2017.06 ES8

Introduction

아름다운 코드에 대한 열망

Introduction

precondition

  • Server-side JavaScirpt

  • Node.js

Background

JavaScript Engine

 JavaScript로 작성된 코드를 해석하고 실행하는 인터프리터

console.log('hi');

어휘 분석

구문 분석 실행

Background

V8 Engine

 Open source high-performance JavaScript engine by Google.

Written in C++

Background

Overall

  1. Engine: JavaScript로 작성된 스크립트를 기계 실행 가능하게 변경. 구문 분석 및 JIT 컴파일
  2. Runtime : 실행 중 프로그램에서 사용할 수있는 기본 라이브러리를 제공

 

Chrome and Node.js therefore share the same engine (Google’s V8), but they have different runtime (execution) environments.

window.alert('hi');

console.log(__dirname);

Beautiful Code

Short

Simple

Small

Stupid

Destructuring Assignment

 ES5

var name = req.body.name
var age = req.body.age
var email = req.body.email

 ES6

const {name, age, email} = req.body

Object Initialize

 ES5

var name = 'hak'
var age = 27
var email = 'code.ryan.lee@gmail.com'

var datas = {
    name: name,
    age: age,
    email: email
}

 ES6

let name = 'hak'
let age = 27
let email = 'code.ryan.lee@gmail.com'

let datas = {name, age, email}

let datas2 = {username: name, age, email}

Template Literals

 ES5

var username = req.body.username
if ( !username ) {
    throw "'username' must required. Your input: " + username  + "."
}

 ES6

let {username} = req.body
if ( !username ) {
    throw `'username' must required. Your input: ${username}.`
}

Default Parameters

 ES5

var greeting = function(username, date, message) {
    username = typeof username !== 'undefined' ? username : 'anonymous'
    date     = typeof date     !== 'undefined' ? date     : new Date()
    message  = typeof message  !== 'undefined' ? message  : 'hello'

    return message + ' ' +  username + ' at ' + date
}

 ES6

const greeting = (username='anonymous', date=new Date(), message='hello') => {
    return `${message} ${username} at ${date}`
}

Promise - Co - async/await 

Callback Hell!!

callback -> async.js -> promise -> generator -> async/await

Now

Future

Callback

function time() {
    setTimeout(function() {
        return 'time!';
    }, 1000);
}


var a = time(); // undefined
function time(callback) {
    setTimeout(function() {
        callback('time!');
    }, 1000);
}

var a;
time(function(r) {
    a = r;
});

Promise

Promise is built-in from ECMAScript 2015

const getName = (user_id) => {
    return new Promise( (resolve, reject) => {
        if ( !user_id ) {
            return reject('user_id must be required.')
        }

        Model.select('table_users', user_id)
        .then( result => {
            resolve( result.username )
        })
        .catch( err => {
            reject( err )
        })
    });
}

Rule : Make all asynchronous functions return Promise!

Generator - Co

Generator was added from ECMAScript 2015

const gen = (a, b, c, conn) => {
    return new Promise( (resolve, reject) => {
	return co(function* () {
	    try {
		yield async1(a);
		yield async2(b);
		yield async3(c);

		resolve(true);
	    } catch (e) {
		reject(e);
	    } finally {
                conn = null;
	    }
	});
    });
};

The yieldable objects currently supported are: Promise

async/await

async/await was added from ECMAScript 2017

When an async function is called, it returns a Promise.

function resolveAfter2Seconds(x) {
  return new Promise(resolve => {
    setTimeout(() => {
      resolve(x);
    }, 2000);
  });
}


async function add1(x) {
  const a = await resolveAfter2Seconds(20);
  const b = await resolveAfter2Seconds(30);
  return x + a + b;
}

add1(10).then(v => {
  console.log(v);  // prints 60 after 4 seconds.
});

async/await

Big picture

// ES6 - Generator
const bigPicture = function* () {
    let awesome = yield beautiful()
}

// ES8 - async/await
const bigPicture = async function() {
    let awesome = await beautiful()
}

Beautifier

function f(){
    fs.readFile('one.js', function(e1, d1) {
        fs.readFile('two.js', function(e2, d2) {
            fs.readFile('three.js', function(e3, d3) {
            // Done!!
            });
        });
    });
}
function f(){
    fun1.then(function(d1){
        return func2;
    }, function(e1){
        // error func1
    }).then(function(d2){
        return func3;
    }, function(e2){
        // error func2
    }).then(function(d3){
        // Done!!
    }, function(e3){
        // error func3
    });
}
function f(){
    co(function* () {
        try {
            let d1 = yield fun1();
            let d2 = yield fun2();
            let d3 = yield fun3();
        } catch (e) {

        }
    });
}
async function f() {
    try {
        let d1 = await fun1();
        let d2 = await fun2();
        let d3 = await fun3();
    } catch (e) {

    }
}

callback

promise

generator

async/await

if-else 

const error = (name, age, email) => {
    if ( name && name.length > 3 ) {
        // something
        // ...
        if ( age < 30 ) {
            // something
            // ...
            if ( /이메일정규식/.test(email) ) {
                // something
                // ...
                return true
            } else {
                return false
            }
        } else {
            return false
        }
    } else {
        return false
    }
}
const error = (name, age, email) => {
    if ( !name || name.length < 4 ) {
        return false
    }
    // something
    // ...

    if ( age >= 30 ) {
        return false
    }
    // something
    // ...

    if ( !/이메일정규식/.test(email) ) {
        return false
    }
    // something
    // ...

    return true
}

Bad case - Non Error First

 

Good case - Error First

 

if-else 

const makeError = (a, b) => {
    return new Promise( (resolve, reject) => {
	return co(function* () {
	    try {
		const val1 = yield async1(a);
                if ( val1 > 10 ) throw 'Error!';

		const val2 = yield async2(b);

		resolve( val1 + val2 );
	    } catch (e) {
		reject(e); // 'Error!'
	    }
	});
    });
};

underscore.js

const users = [
    {
        name: 'lsh',
        age: 27,
        job: 'Programmer'
    },
    {
        name: 'Kendrick',
        age: 30,
        job: 'Rapper'
    },
    {
        name: 'statham',
        age: 50,
        job: 'Actor'
    }
]
_.pluck(users, 'name');
// =>['lsh', 'Kendrick', 'statham']


_.pluck(users, 'job');
// =>['Programmer', 'Rapper', 'Actor']

underscore.js

_.groupBy(['one', 'two', 'three'], 'length');
=> {3: ["one", "two"], 5: ["three"]}

_.contains([1, 2, 3], 3);
=> true

_.compact([0, 1, false, 2, '', 3]);
=> [1, 2, 3]
_.pairs({one: 1, two: 2, three: 3});
=> [["one", 1], ["two", 2], ["three", 3]]

_.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age');
=> {name: 'moe', age: 50}

_.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid');
=> {name: 'moe', age: 50}

Conclusion

태양처럼 너는 밝고 아리따워
여름처럼 너는 밝고 아리따워
beautiful beautiful
찾아봐요 당신만의 아리따움

Beautiful JavaScript

By SangHak Lee

Beautiful JavaScript

ECMAScript 2015 / ES6

  • 34,668