by lkokoszka@future-processing.com aka "Max"
var text = "𠮷"; // CJK UNIFIED IDEOGRAPH console.log(text.length); // 2 (surrogate pair) console.log(/^.$/.test(text)); // singe character test; false console.log(text.charAt(0)); // "" console.log(text.charAt(1)); // "" console.log(text.charCodeAt(0)); // 55362 console.log(text.charCodeAt(1)); // 57271
var text = "𠮷a"; console.log(text.charCodeAt(0)); // 55362 console.log(text.charCodeAt(1)); // 57271 console.log(text.charCodeAt(2)); // 97 console.log(text.codePointAt(0)); // 134071 console.log(text.codePointAt(1)); // 57271 console.log(text.codePointAt(2)); // 97
							console.log("\u0061");		// "a" - aktualny standard
console.log("\u20BB7");		// "₻7" - próba użycia znaku Non-BMP
console.log("\u{20BB7}");	// " " - ECMAScript 6
							
					/u - wymusza prace silnika wyrażeń regularnych w oparciu o znaki, nie "code units"
* wszystkie przyjmują parametr location, czyli punkt początkowy i zwracają wartość bool'owską
let oneLiner = `it is a one line`; // znak delimitacji ` let multiLiner_maybe_bad = `Multi // zachowuje się jak <pre> line text`; let multiLiner_maybe_good = ` // prosty trick Multi line text `.trim();
							let	what = 'dog',
	with = 'a long tail',
	// używamy zmiennych "osiągalnych" w scope'ie
	msg1 = `it is a ${what}`,
	msg2 = `it is a ${what} with ${with}`;
console.log(msg1);	// "it is a dog"
console.log(msg2);	// "it is a dog with a long tail"
							
												let	howMuch = 20,
	exchangeRate = 4,
	convert = function (eur, exRate) {
		return (eur * exRate).toFixed(2);
	},
	euro2pln = `it is ${(howMuch * exchangeRate).toFixed(2)} PLN`;
	euro2plnFn = `it is ${convert(howMuch,exchangeRate)} PLN`;
console.log(euro2pln);	// "it is 80.00 PLN"
console.log(euro2plnFn);	// "it is 80.00 PLN"
							
												tag`Hello ${name}`
							
												function extRangeTrans(literals, ...substitutions) {
	let result = "", i;
	for (i = 0; i < substitutions.length; i++) {
		result += literals[i];
		result += substitutions[i];
	}
	result += literals[literals.length - 1];
	return result;
}
let	pln = 20,
	exRate = 4.2,
	euro2pln = extRangeTrans`
		${eur} EUR (@ ${exRate}) is
		${(eur * exRate).toFixed(2)} PLN
	`.trim();
console.log(euro2pln); //20 EUR (@ ${exRate}) is 84.00 PLN
							
					`a\nb` // a // b String.raw`a\nb` //a\nb
var text = 'First line\nsecond line'; var regex = /(\S+) line\n?/y; var match = regex.exec(text); match[1] // 'First' regex.lastIndex // '11' var match2 = regex.exec(text); match2[1] // 'Second' regex.lastIndex // '22' var match3 = regex.exec(text); match3 === null // 'true'
							var re1 = /ab/i,
    re2 = new RegExp(re1, "g");
						
												var value1 = 0o71;   // 57
var value2 = 0b101;  // 5
parseInt("0o71");    // 0
parseInt("0b101");   // 0
Number("0o71");      // 57
Number("0b101");     // 5
						
												isFinite(25)              // true
isFinite("25")            // true
Number.isFinite(25)       // true
Number.isFinite("25")     // false
isNaN(NaN)                // true
isNaN("NaN")              // true
Number.isNaN(NaN)         // true
Number.isNaN("NaN")       // false
						
					Number.isInteger(25) // true Number.isInteger(25.0) // true Number.isInteger(25.1) // false Number.isSafeInteger(9007199254740991) // true Number.isSafeInteger(9007199254740992) // false
							let color = 'red';
if (true) {
	console.log(color) // ReferenceError
	let color = 'white';
	console.log(color) // "white"
}
console.log(color) // "red"
							
					użycie var
							var funcs = [];
for (var i = 0; i < 10; i++) {
	funcs.push( function () { console.log(i); });
}
funcs.forEach(function (func) {
	func();	// wypluje liczbę "10" 10x
});
							
							verte ↓
użycie let
							var funcs = [];
for (let i = 0; i < 10; i++) {
	funcs.push( function () { console.log(i); });
}
funcs.forEach(function (func) {
	func();	// wypluje liczbę "0", potem "1" itd.
});
							
					const MAX_SIZE = 'red';
							var sourceObject = {from: 1, to: 2}
function ECMAScript5 (sourceObject) {
	var	localFrom = sourceObject.from,
		localTo = sourceObject.to;
}
function ECMAScript6 (sourceObject) {
	let { from: localFrom, to: localTo } = sourceObject;
	console.log(localFrom, localTo); // :)
	// lub w przypadku mapowania nazwenictwa 1:1
	let { from, to } = sourceObject;
	console.log(from, to); // :D
}
							
							{ wlasciwoscObiektuZrodlowego: zmienneLokalna} = obiektZrodlowy
												var sourceObject = { from: 1, to: 2, more: { max: 3 } };
// później gdzieś w kodziwie...
let { from, to, more: { max }} = sourceObject;
console.log(from, to, max);
// :D - ! `more` nie zostanie zadeklarowane
							
					var kolory = ['red', 'green', 'blue']; // później gdzieś w kodziwie... let [firstColor, secondColor] = kolory; console.log(firstColor, secondColor) // :D[ pierwszyElement, drugiElement...] = tablicaZrodlowa
							var	sourceObject = { from: 1, to: 2, colors: [
		'red', 'green', 'blue'
	]};
// później gdzieś w kodziwie...
let {from, to, colors: [firstColor, secondColor]} = kolory;
console.log(from, to, firstColor, secondColor) // :D
let {from, to, colors} = kolory;
console.log(from, to, colors)
// :D - colors będzie referencją do sourceObject.colors
							
												function reload (what, in = 2000, then = function () {} ) { }
function defaultAddWhatValue () { return 0; }
function add (addTo, addWhat = defaultAddWhatValue() + 0) { }
							
														function sampleRest (param1, param2, ...options) {
	...
	console.log(options.length);
	// ^ == przekazane - zadeklarowane nazwane
}
							
														function destParams (param1, {setting1, setting2}, {setting3} = {}) {
	console.log(param1, setting1, setting2, setting3);
}
destParams(1); // error!
destParams(1, {setting1: 'a', setting2: 'b'});
							
														var params = ['a', 'b'];
function yYoOeE (param1, param2) { }
// zamiast
yYoOeE.apply(yYoOeE, params);
// szkrótem!
yYoOeE(...params);
							
														var doSomething = function doSomethingElse() { };
// doSomething.name == "doSomethingElse"
function doSomething () { }
// doSomething.name == "doSomething"
var doAnotherThing = function () { };
// doAnotherThing.name == "doAnotherThing"
var person = { get firstName () { }, sayName: function () { }};
// person.firstName.name == "get firstName"
// person.sayName.name == "sayName"
var test = doSomething.bind(null);
// test.name == "bound doSomething"
// (function () {}).name == "anonymous"
							
												"use strict";
if ( true ) {
	console.log( typeof doSomething); // "function"
	function doSomething() { }
}
console.log( typeof doSomething);
// "undefined"
							
												var justReturn = value => value;
// jest równoznaczne z:
var justReturn = function (value) { return value; };
[0,1,2].forEach(v => {
	results.push(v * 2);
});
							
												var test = () => 'test';
var add = (param1, param2) => { return param1 + param2 };
							
												var addFn = add() => { return add() };
							
							* wciąż dyskutowane
												let	local = 1,
	example = { local };
// example == { local: 1 };
							
												let example = {
	do() {
		//...
	}
}
// typeof example.local == 'function'
							
												let	errorSuffix = 'Error',
	errorSuffixProvider = () => 'Error',
	example = {
		['profile' + 'Error']: false,
		['user' + errorSuffix]: false,
		['network' + errorSuffixProvider()]: false
	};
// example = {
//	profileError: false, userError: false, networkError: false
// }
							
												let person = {
    getGreeting() { return "Hello"; }
};
let dog = {
    getGreeting() { return "Woof"; }
};
let friend = Object.create(person);
friend.getGreeting()                        // "Hello"
Object.getPrototypeOf(friend) === person  // true
Object.setPrototypeOf(friend, dog);
friend.getGreeting()                        // "Woof"
Object.getPrototypeOf(friend) === dog     // true
						
												// metoda getEmployer na instancji Developer
// którego prototypem jest Employee
getEmployer() {
	Developer.prototype.getEmployer.call(this);
	// lub
	this.__proto__.getEmployer.call(this)
	// lub
	Object.getPrototypeOf( this ).getEmployer.call( this );
	// lub w ECMAScript 6
	super.getEmployer(); // === super.getEmployer.call(this)
	// lub
	super()
}
							
					super referencja wprowadza konieczność zdefiniowana nowej ukrytej/wew. właściwiość funkcji/metody oznaczonej w dokumentacji jako [[HomeObject]]. Ta wskazuje na obiekt do którego dana funkcja/metoda należy i jest ustawiana w chwili definiowania funkcji.
To zmienia definicję metody w JS.
"ECMAScript 6 formally defines a method as a function that has an internal [[HomeObject]] property containing the object to which the method belongs."" zatem w każdym inny przypadku mamy doczynienia z funkcją!ponieważ [[HomeObject]] jest stricte związany z procesem definiowana funkcji, aby móc korzystać z dobordziejstw super referencji w przypadku nadpisywania metod obiektu w czasie jego życia, należy użyć nowej metody dostępnej dla każdej funkcji .toMethod(), która skonwertuje funkcję na metodę.
							let friend = {
	sayHi() {
		return "hi!";
	}
};
function sayHiAndYo () {
	return super.sayHi() + ", yo!";
}
friend.sayHi = sayHiAndYo;
friend.sayHi(); // error!
friend.sayHi = sayHiAndYo.toMethod(friend); // :)
							
												var	sym1 = Symbol(),
	sym2 = Symbol("foo"),
	sym3 = Symbol("foo"),
	sym4 = new Symbol(), // TypeError
	sym5 = Symbol.for('meta_data_storage');
	// pierwszy lookup utworzy nowy symbol o danym opisie/kluczu
	// typeof sym1 == "symbol"
	// typeof sym3 == "symbol"
	// typeof sym5 == "symbol"
							
							- symbol może zawierać opis/klucz (przechowywany wew.), który:
							w przypadku symboli globalnych może posłużyć do jego odszukania w rejestrze,
							w przypadku lokalnych może przydać się w procesie debuggowania
							- ponieważ Symbol nie jest konstruktorem nie można używać go z operatorem `new`
												var	sym = Symbol.for('meta_data_storage');
	// pierwszy lookup utworzy nowy symbol o danym opisie/kluczu
console.log(Symbol.keyFor(sym)); // "meta_data_storage"
							
							w przypadku użycia keyFor z symbolem lokalnym metoda zwróci undefined
					to lista symboli wykorzystywanych w silniku JS i opisanych w specyfikacji jako dostępnych dla programisty w celu umożliwenia zmian w część wewnętrznych zachowań języka. Spec. posługuje się notacją "@@nazwaSymbolu" dla odróżnienia symboli od innych danych
							function Person(name) {
	this.name = name;
}
Person.prototype[Symbol.toStringTag] = "Person";
Person.prototype.toString = function () {
	return this .name;
};
var me = new Person("Nicholas");
console.log(me.toString());	// "Nicholas"
console.log(Object.prototype.toString.call(me)); // "[object Person]
							
					ponieważ Object.getOwnPropertyNames nie zwróci właściwości zdefniowanych za pomocą symboli, aby uzyskać do nich dostęp należy użyć Object.getOwnPropertySymbols, który zwróci array symboli
							function createIterator(items) {
	var i = 0;
	return {
		next: function () {
			var	done = (i >= items.length),
				value = !done ? items[i++] : undefined;
			return { done: done, value: value };
		}
	};
}
var iterator = createIterator([1, 2, 3]);
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: 3, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }
							
						  definicja takiego iteratora jest możliwa już w ECMAScript 5, jedynie
						  ostatni przypadek jest szczególny i związany z oczekiwaniami ECMAScript 6
												// generator
function *createIterator() {
	yield 1;
	yield 2;
	yield 3;
}
							
												var obj = {
	es5: function * () {},
	*es6() {}
};
class A {
	*giveMe () {}
}
							
												// generator
function *createIterator() {
	yield 1;
	yield 2;
	yield 3;
}
let iterator = createIterator();
for ( let i of iterator ) {
	console.log(i);
}
							
												// generator
function *createIterator() {
	yield 1;
	return 100;
	yield 2;
	yield 3;
}
							
							to jednak zadziała tylko przy manualnej iteracji - for..of ignoruje zwróconą wartość
												function *createNumberIterator() {
	yield 1;
	yield 2;
}
function *createCombinedIterator() {
	yield *createNumberIterator();
	yield true ;
}
var iterator = createCombinedIterator();
console.log(iterator.next()); // "{ value: 1, done: false }"
console.log(iterator.next()); // "{ value: 2, done: false }"
console.log(iterator.next()); // "{ value: true, done: false }"
console.log(iterator.next()); // "{ value: undefined, done: true }"
							
												function *createIterator() {
	yield * "test";
}
							
												class Example extends AnotherExample {
	constructor () {
		super();
	}
	methodA () {}
	static methodB () {}
	*[Symbol.iterator]() {}
}
							
												var c = class C {};
							
												class Example {
	constructor () {
		this.property = true;
	}
	get property () {}
	set property () {}
}
							
							ES6 definuje domyślny konstruktor
												class Example {
	static test () {
		return 'test';
	}
}
Example.test();
							
												class Example extends AnotherExample {}
class Example extends combine(AnotherExample, BaseExample) {}
							
							można dziedziczyć po null jak i dowolnym obiekcie (nie koniecznie zdefiniowany z użyciem class; np. Array)
					ES6 wraz z obsługą klas wprowadza bardzo ważną zmianę związaną z tworzeniem ich instancji:instancja jest tworzona w najgłębiej położonym konstruktorze całego łańcucha dziedziczenia podczas gdy ES5 tworzył instancje zaraz po wywołaniu operatora new
verte ↓
to wymóg w przypadku wykorzystywania dziedziczenia
							class Example extends AnotherExample {
	constructor () {
		this.something = true; // ReferenceError
		super()
		// WYMAGANE WYWOŁANIE konstruktora klasy nadrzędnej
		// za pomocą "super referencji"
		this.something = true;
	}
}
							
					nowy "niejawny parametr" dostępna we wszystkich funkcjach. Dla konstruktorów klas jest ref. na funkcję wywołującą.`new.target` jest dla konstruktorów tym czym`this` jest dla funkcji
							class Example extends AnotherExample {
	constructor () {
		super()
		// `new.target` w AnotherExample wskazuje
		// na konstruktor Example
	}
}
							
							
								- new.target.prototype staję prototype tworzonej instacji dzięki czemu wszystkie
								egzotyczne "właściwości" mogą zostać prawidołow zainicjalizowane
								- w przypadku normalnych funkcji new.target == undefined, dla "arrow functions" new.target == new.target otaczającego scope'a
								[1]
							
					z zachowaniem ich "magicznych" właściwości jak np. Array
							class MyArray extends Array {
	constructor () {
		super()
	}
}
(new MyArray()).length // będzie działać prawidłowo!
							
							ten feature wymaga jednak zmian w silnikach JS!
					tj. nadpisanie konstruktora używanego przez metody zwracające nowe instancje, jak np. Array.prototype.map
							class MyArray1 extends Array { }
let result1 = new MyArray1().map(x => x);
result1 instanceof MyArray1 // true
class MyArray2 extends Array {
	static get [Symbol.species]() {
		return Array;
	}
}
let result2 = new MyArray2().map(x => x);
result2 instanceof MyArray2 // false
							
												var sample = new Set([1, "1", true, {}]); // iterable jako parametr
sample.size // 4
							
							z użyciem for..of lub forEach
												var obj = {},
	sample = new WeakSet([obj]); // iterable jako parametr
							
												var sample = new Map([["key1", "value1"], ["key2", "value2"]]);
sample.set("key3", "value3");
sample.get("key3");
							
							z użyciem for..of lub forEach
												var obj = {},
	sample = new WeakMap([[obj, 'test']]);
	// iterable jako parametr
							
												let	target = {},
	handler = {
		get (target, propKey, receiver) {
			console.log('get ' + propKey);
			return 123;
		},
		ownKeys (target) {
			console.log('ownKeys');
			return ['hello', 'world'];
		}
	},
	proxy = new Proxy(target, handler);
	proxy.foo // "get foo" -> 123
	Object.keys(proxy) // "ownKeys" -> "['hello', 'world']"
						
					pułapka get jest na swój sposób szczególna, przez nią bowiem przechodzi większość akcji wykonywanych na obiektach zatem można jej używać do całościowego przeciążania obiektów
								let proxy = new Proxy({
	a: true,
	b: function () {}
}, {
get(target, propKey, receiver) {
	console.log('get ' + propKey);
	return target[propKey];
}
});
proxy.a;	// "get a" + true
proxy.b();	// "get b" + 'call to b'
								
					proxy może zostać użyte jako prototyp obiektu, dzięki czemu można wyłapywać operacje, które nie zostały zaspokojony przez obiekt lub wymusiły lookup po łańcuchu prototypów
								let proto = new Proxy({}, {
	get(target, propertyKey, receiver) {
		console.log('GET ' + propertyKey);
		return target[propertyKey];
	}
});
let obj = Object.create(proto);
obj.bla; // GET bla
								
												let handler = {
	deleteProperty(target, propKey) {
		console.log('DELETE ' + propKey);
		return Reflect.deleteProperty(target, propKey);
	},
	has(target, propKey) {
		console.log('HAS ' + propKey);
		return Reflect.has(target, propKey);
	}
};
let proxy = new Proxy({}, handler);
delete proxy.test; // DELETE test
							
												var promise = new Promise(function (resolve, reject) {
	// tzw. "executor"
	resolve(); //jeśli poszło OK
	reject(); //jeśli coś poszło nie tak
});
							
												promise.then(r => 1).then(r => ({})).then(r => true);
							
												promise.then(r => 1).catch(e => ({})).then(r => true);
							
					Promise.all([promise1, promise2, promise3]); Promise.race([promiseDownload1, promiseDownload2, promiseDownload3]);
							// modules/A.js
export default function () {};
// modules/B.js
export function print() {};
// modules/C.js
import A from 'modules/A';
import {print} from 'modules/B';
export default function () {};
// modules/D.js
import C from 'modules/C';
C();
							
												// modules/A.js
export default function () {};
export function test() {};
export class testClass() {};
// modules/B.js
function doSomething() {}
export doSomething;
// modules/C.js
const MY_CONST = ...;
function myFunc() {}
export { MY_CONST, myFunc };
							
							moduły mogą wykonywać wiele nazwanych exportów i nie więcej niż jeden domyślny (via default).
								można łączyć eksport domyślny z nazwanymi w jednym module (świetnym przykładem wykorzystania mieszanego exportu są underscore.js i lodash.js)
							
												// modules/A.js
export function doSomething() {}
export {doSomething as justDo};
const MY_CONST = ...;
export { MYCONST as THATCONST };
// lub
export { MYCONST as default };
							
												import {default as theDefault} from 'modules/B';
// ==
import theDefault from 'modules/B';
// pozostałe możliwości
import theDefault, {named1, named2} from 'modules/B';
import { named1, named2 } from 'modules/B';
// aliasowanie / zmiana nazwy podczas importu
import { named1 as moduleBFn };
// importowanie modułu do obiektu/tworzenie "namespace"
import * as moduleB from 'modules/B';
// ładowanie bez importu
import 'modules/B';
							
												function add5(a) {
	   return a + 5;
}
function add10 (a){
	return add5(a); // tail call
	return 5 * add5(a); // a tutaj nie
	if (a > 5) {
		return add(10); // recursive tail call
	}
}
							
												function computeMaxCallStackSize() {
    try {
        return 1 + computeMaxCallStackSize();
    } catch (e) {
        // Call stack overflow
        return 1;
    }
}
function computeMaxCallStackSize(size) {
    size = size || 1;
    return computeMaxCallStackSize(size + 1);
}