SlideShare une entreprise Scribd logo
1  sur  55
Télécharger pour lire hors ligne
Metaprogramowanie w JS
Spojrzenie na interesujące wewnętrzne mechanizmy
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Achtung! Danger! Uwaga!
Metaprogramowanie w JS
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Zajawka
Metaprogramowanie w JS
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Zajawka
Metaprogramowanie w JS
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Zajawka
Metaprogramowanie w JS
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Zajawka
Metaprogramowanie w JS
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Zajawka
Metaprogramowanie w JS
What the Hack? 

Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
What the Hack?
What the Hack?
What the Hack?
Agenda
Metaprogramowanie w JS
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Czym jest metaprogramowanie?
• Metaprogramming API
• Podstawowe symbole
• Proxy
Czym jest metaprogramowanie?
Czyli kilka słów teorii
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Why do JS developers wear glasses?
Because they don’t C#
Definicja
Czym jest metaprogramowanie?
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Program, który tworzy lub modyfikuje inny program - metaprogram
• Program, który modyfikuje samego siebie
Definicja
Czym jest metaprogramowanie?
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Program, który tworzy lub modyfikuje inny program - metaprogram
• Kompilatory - np. parsowanie i optymalizacja kodu
• Transpilery - np. modyfikacja kodu żeby był zgodny z urządzeniem
• IDE - np. analiza JSDoc
• Program, który modyfikuje samego siebie
• Mechanizmy refleksji
Definicja
Czym jest metaprogramowanie?
• Program, który tworzy lub modyfikuje inny program - metaprogram
• Kompilatory - np. parsowanie i optymalizacja kodu
• Transpilery - np. modyfikacja kodu żeby był zgodny z urządzeniem
• IDE - np. analiza JSDoc
• Program, który modyfikuje samego siebie
• Mechanizmy refleksji
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Modyfikacja programu innym programem
Czym jest metaprogramowanie?
• Program, który tworzy lub modyfikuje inny program - metaprogram
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
#define true false
#define private public
Robienie zamieszania w C dzięki makrom / Zły kod nie zależy od języka
Programowanie refleksyjne
Czym jest metaprogramowanie?
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Introspekcja - czytanie struktury programu
• Modyfikacja - zmiana struktury programu
• Intercesja - „wchodzenie pomiędzy” - zmiana semantyki języka/programu
Przykłady metaprogramowania
Co możemy dzięki temu osiągnąć?
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
SQL query goes into a bar, walks up to

two tables and asks "Can I join you?"
Przeciążanie operatorów
Przykłady metaprogramowania
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
// Ruby
class X
attr_reader :order
def +(y)
y + 2
end
def <=>(other)
self.order <=> other.order
end
end
instance = X.new
instance + 3 // => 5
// C++
struct X {
int operator+(int y) {
return y + 2;
}
};
int main () {
X instance;
std::cout << instance + 3; // => 5
return 0;
}
Destruktory
Przykłady metaprogramowania
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
// Python
class X:
def __del__(self):
self.connection.close()
// PHP
class X
{
private function __destruct()
{
$this->connection->close();
}
}
Obsługa dynamicznych pól
Przykłady metaprogramowania
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
// PHP
class X
{
public function __get($field)
{
return $field . " value";
}
}
// Ruby
class X
def method_missing(m, *args, &block)
"#{m} value"
end
end
Adnotacje i dekoratory
Przykłady metaprogramowania
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
// Java
@Entity
public class X {
@Id @GeneratedValue
@Column(name = "id")
private int id;
public X() {}
}
// JavaScript
class X {
@emitOnEnd("someEvent")
doSomething () {
console.log("Something there")
}
}
Prywatne wartości
Przykłady metaprogramowania
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
// PHP
class X
{
private $name;
}
// C++
class X {
private:
string name;
}
Imitowanie tablicy
Przykłady metaprogramowania
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
// PHP
class X implements ArrayAccess
{
public function offsetExists ($o) {}
public function offsetGet ($o) {}
public function offsetSet ($o, $v) {}
public function offsetUnset ($o) {}
}
$instance = new X();
$instance["key"];
$instance[0];
// JavaScript
// Array-like object
const a = {
0: 1,
1: 4943,
2: 2213,
length: 3
}
a[0];
Przeciążanie metod/klas
Przykłady metaprogramowania
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
// Ruby
class X
def something
'hello!'
end
end
class X
def somethingElse
'hello 2!'
end
end
instance = X.new
instance.print // => "hello!"
instance.printSomething // => "hello 2!"
// JavaScript
// Works pretty good!
function X () {}
X.prototype.something = function () {

return "hello!"
}
X.prototype.somethingElse = function () {
return "hello 2!"
}
instance = new X()
instance.print() // => "hello!"
instance.printSomething() // => "hello 2!”
Metaprogramming API
Podstawowe możliwości w JavaScript
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
I've got a really good UDP joke to tell you,
but I don't know if you'll get it
Na co nam pozwala podstawowe API?
Metaprogramming API
• Analiza i modyfikacja struktury obiektów
• Czytanie informacji o funkcjach
• Zarządzanie łańcuchem prototypów
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Analiza i modyfikacja obiektów
Metaprogramming API
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Czytanie podstawowej struktury obiektów
• Zarządzanie stałością obiektów (mutability)
• Łańcuch prototypów
Object.getPrototypeOf(obj)
Object.setPrototypeOf(obj, null)
Object.hasOwnProperty("key") // => true Object.getOwnPropertyNames(obj)
Object.keys(obj) // => [ "key" ]
Object.preventExtensions(obj) Object.isExtensible(obj) // => false
Object.seal(obj) Object.isSealed(obj) // => true
Object.freeze(obj) Object.isFrozen(obj) // => true
Funkcje
Metaprogramming API
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Wykonywanie funkcji
• Czytanie struktury funkcji
• Tworzenie funkcji
Math.max.call(Math, 10, 20) // => 20
Math.max.apply(Math, [ 10, 20 ]) // => 20
const func = Array.prototype.concat.bind([ 10, 30 ], 20)
func(40) // => [ 10, 30, 20, 40 ]
function test (a, b) {} test.length // => 2
test.toString() // => "function test (a, b) {}"
function test2 (a, ...args) {} test2.length // => 1
const sum = new Function("a", "b", "return a + b")
sum(10, 20) // => 30
Reflect API
Metaprogramming API
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
// Function options wrappers
Reflect.apply(Math.max, null, [ 5, 15 ])
Reflect.construct(X, [ "John" ])
// Language wrappers
Reflect.has(…) // „in” operator
Reflect.deleteProperty(…) // „delete”
Reflect.get(…) // access property
Reflect.set(…) // set property value
// Object methods wrappers
Reflect.defineProperty(…)
Reflect.getOwnPropertyDescriptor(…)
Reflect.ownKeys(…)
Reflect.preventExtensions(…)
Reflect.isExtensible(…)
Reflect.getPrototypeOf(…)
Reflect.setPrototypeOf(…)
• Elastyczniejsze API do wielu metod:
• API funkcji
• Operacje języka
• Refleksja obiektów
Przykłady użycia
Metaprogramming API
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Dependency Injection (użyte podobnie w AngularJS)
function test ($m, $s) { const fnRegex = /function[s]+[^(]+(([^)]+))/
return $m.pow($s.points, 2) const args = test.toString().match(fnRegex)[1]

} args.split(/[s]*,[s]*/) // [ "$a", "$b" ]
const object = { "key": "value" } // Object.create(object)
function HiddenObject () { }
HiddenObject.prototype = object
const hiddenObject = new HiddenObject()
HiddenObject.prototype = null
hiddenObject // => { "prototype": null }
hiddenObject.key // => "value"
Object.getPrototypeOf(hiddenObject) // => { "key": "value" }
• Ukrywanie prototypu
Deskryptor pola - z czego się może składać?
Metaprogramming API
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
const object = {}
Object.defineProperty(object, "key", {
value: "Field Value",
// writable: false,
// get: () => "Field Value",
set: function (value) {
this.x = value + "abc"
},
configurable: true,
enumerable: false
}
Object.keys(object) // => []
object.key // => "Field value"
object.x // => undefined
object.key = "Def"
object.key // "Field value"
object.x // => "Defabc"
• Wartość pola - value
• Getter / Setter - get/set
• Można przypisać wartość? - writable
• Definicja może się zmienić? - configurable
• Pole powinno być widoczne? - enumerable
• writable || set
• value || get
Dekoratory pól
Metaprogramming API
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
function readOnly (
target,
propertyName,
descriptor
) {
descriptor.writable = false
}
const object = {
@readOnly
field: "value"
}
object.field // => "value"
object.field = "something"
object.field // => "value"
• Dekoratory mogę zmienić deskryptor pola:
• Mogą nadpisać jego wartość
• Zmienić gettery/settery
• Zapisać informację jako efekt uboczny
Dekoratory klas
Metaprogramming API
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
function Serializable (Cls) {
Cls.prototype.toString = function () {
const str = JSON.stringify(this)
return Cls.name + ": " + str
}
}
@Serializable
class Point {
constructor (x, y) {
this.x = x
this.y = y
}
}
const point = new Point(1, 5)
console.log(point.toString())
// "Point: {"x":1,"y":5}"
• W klasie dekoratory mogą nadpisać klasę

lub edytować jej prototyp w dowolny sposób
Dekoratory klas: przykład
Metaprogramming API
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
@Entity()
class User extends BaseEntity {
@PrimaryGeneratedColumn()
id: number;
@Column()
firstName: string;
@Column()
lastName: string;
@Column()
age: number;
}
• ActiveRecord / ORM
• Przykład z TypeORM

https://github.com/typeorm/typeorm
Podstawowe symbole
Zmiana semantyki działania programu
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Why do programmers confuse
Halloween with Christmas?
Because OCT 31 = DEC 25.
Czym są symbole?
Podstawowe symbole
// Declare standard symbol
const internal = Symbol()
const symbol = Symbol()
symbol == internal // => false
• Używane jako unikalna wartość
• Nie kolidują z innymi typami
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Czym są symbole?
Podstawowe symbole
// Declare standard symbol
const internal = Symbol()
const symbol = Symbol()
symbol == internal // => false
// Prepare example object
const object = {}
// Set up some value in object
object[internal] = "value"
object[internal] + "s" // => "values"
Object.keys(object) // => []
• Używane jako unikalna wartość
• Nie kolidują z innymi typami
• Mogą być używane jako klucz obiektu
• Ukryte w obiekcie

poza getOwnPropertySymbols i Reflect.ownKeys
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Czym są symbole?
Podstawowe symbole
// Declare standard symbol
const internal = Symbol.for("debug")

const symbol = Symbol.for("debug")



internal == symbol // => true
Symbol.keyFor(internal) // => „debug"
• Mogą mieć swój identyfikator
• Do pobrania przez Symbol.keyFor
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Well-known symbols
Podstawowe symbole
class Something {
// getter in constructor
static get [Symbol.isMagical] () {
return true
}
// getter for instance
get [Symbol.isMagicDone] () {
return "Magic has been done"
}
// method for instance
[Symbol.makeMagic] () {
// Poof!
}
}
• Dostępne w przestrzeni Symbol
• Przykłady Symbol.iterator, Symbol.species
• Przypisane do prototypu lub bezpośrednio

do konstruktora
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Symbol.iterator
Podstawowe symbole
class Range {
constructor (from, to) {
this.from = from
this.to = to
}
*[Symbol.iterator] () {
let i = this.from
while (i <= this.to) {
yield i
i++
}
}
}
const range = [ ...new Range(1, 5) ]
console.log(range) // [ 1, 2, 3, 4, 5 ]
• Pozwala na implementację iteratora
• for…of loop
• spread operator - [ …arr ]
• Array.from
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Symbol.toPrimitive
Podstawowe symbole
const person = {
name: "John Doe",
[Symbol.toPrimitive] (hint) {
if (hint === "string") {
return this.name
} else if (hint === "number") {
return this.name.length
}
// "default"
return "Hi, I am " + this.name
}
}

`${person}` // => "John Doe"
+person // => 8
person + "" // => "Hi, I am John Doe"
person + 3 // => "Hi, I am John Doe3"
• Zmiana zachowania przy zrzucaniu do typu
• Rozróżnia prymitywne typy
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Symbol.hasInstance
Podstawowe symbole
const notNode = x => !(x instanceof Node)
class Node {}
class NodeList extends Array {
static get [Symbol.hasInstance] (o) {
const proto = Object.getPrototypeOf(o)
const c = proto.constructor
if (c === NodeList) { return true }
if (!Array.isArray(o)) { return false }
return o.findIndex(notNode) === -1
}
}
const node = new Node()
[ 1 ] instanceof NodeList // => false
[ node ] instanceof NodeList // => true
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Definiuje działanie instanceof
• Sprawdza czy obiekt jest „instancją” klasy
• Sugar syntax:

obj instanceof Iterable wygląda lepiej niż:

isIterable(obj) czy Symbol.iterator in obj
Symbol.species
Podstawowe symbole
// Standard behavior
class TimeoutPromise extends Promise {}
const self = x => x
const promise = new TimeoutPromise(self)
promise.then(x => x) // => TimeoutPromise
// Modified behavior
class TimeoutPromise extends Promise {
static get [Symbol.species] () {
return Promise
}
}
const self = x => x
const promise = new TimeoutPromise(self)
promise.then(x => x) // => Promise
• Zmienia zwracany typ z podstawowych metod
• Przydatny jeśli chcemy przejść do standardu
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Symbol.isConcatSpreadable
Podstawowe symbole
// Standard behavior
const o = {
0: "a",
1: "b",
length: 2
}
[ 1 ].concat(o) // => [ 1,{0:"a",1:"b"} ]
// Modified behavior

const o = {
0: "a",
1: "b",
length: 2,
[Symbol.isConcatSpreadable]: true
}
[ 1 ].concat(o) // => [ 1, "a", "b" ]
• Definiuje zachowanie funkcji concat
• Decyduje czy obiekt ma być spłaszczony
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Symbol.match, replace, split i search
Podstawowe symbole
const str = "<strong>Success</strong>"
class Tag {
constructor (name) {
this.name = name
}
[Symbol.search] (str) {
return str.indexOf(
"<" + this.name + ">"
)
}
}
str.search(new Tag("strong")) // => 0
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
• Definiują działanie obiektu w kilku metodach
• string.split(object)
• string.search(object)
• string.replace(object, replacement)
• string.match(object)
Symbol.toStringTag
Podstawowe symbole
// Standard behavior
const object = {}
"" + object // => "[object Object]"
// Modified behavior
const object = {
[Symbol.toStringTag]: "X"
}
"" + object // => "[object X]"
• Definiuje podstawowy tag nazwy obiektu
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Symbol.unscopables
Podstawowe symbole
// Declare object
const object = {
txt1: "value",
txt2: "value2",
[Symbol.unscopables]: { "txt2": true }
}
with (object) {
console.log(txt1) // => "value"
console.log(txt2) // ReferenceError
}
• Blokuje pola dla konstrukcji with {}
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Proxy
Podsłuchujemy i przejmujemy aplikację!
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
- Knock knock.
- Race condition.
- Who’s there?
Jak działa proxy?
Proxy
function SomeObject () {
this.pre = "Something "
}
const object = new SomeObject()
const proxy = new Proxy(object, {
get (target, property) {
return target.pre + property
}
})
proxy.special // "Something special"
proxy.funny // "Something funny"
Object.getPrototypeOf(proxy).constructor
// SomeObject
• Ustawia pułapki („traps”) na akcje
• Pozwala dynamicznie na zmiany zachowania
• Ma dostęp do prototypu i konstruktora
• Ma dostęp do pól
• Niezmienione akcje zachowują się tak samo
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
Gdzie możemy postawić „pułapki”?
Proxy
• Zmiana i pobranie parametru
• Konstrukcja obiektu, wykonanie funkcji
• Zmiana i pobranie prototypu
• Operatory in, delete
• Pobranie kluczy obiektu
• Więcej: http://bit.ly/mdnproxy
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
function Something () {
this.pre = "Something "
}
const object = new X()
const proxy = new Proxy(object, {
get (target, property) {
return target.pre + property
},
set (target, property, value) {
throw new Error("You can't change!")
}
})
Object.getPrototypeOf(proxy) // Something
proxy.special // "Something special"
proxy.special = "xyz" // Error
Przykład: Dependency Injection
Proxy
• Po prawej szkic DI
• brak obsługi błędów
• brak poprawnego cache
• niezoptymalizowane
• nie działa poprawnie „in” czy „getKeys”
• Dynamiczne przypisanie danych
• Możliwość "lazy loadingu"
• Przykład: github.com/rangoo94/easen-di
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
function Di (dependencies = {}) {
const cache = {}
this.proxy = new Proxy(dependencies, {
set (deps, prop, value) {
if (typeof value !== "function") {
throw new TypeError()
}
deps[prop] = value
},
get (deps, prop) {
if (!deps[prop]) {
throw new ReferenceError()
}
if (!cache[prop]) {
cache[prop] = deps[prop]()
}
return cache[prop]
}
})
}
const di = new Di({ x: () => "Hello" })
di.proxy.x // "Hello"
Przykład: Automatyczna walidacja na osobnej warstwie
Proxy
• Walidacja niezależna od obiektu końcowego
• Możemy mieć jeden obiekt, ale N walidacji
• Walidacja zależna od miejsca zmiany
• Przykład - jeden model User zamiast:
• CreatedUser
• PostUser
• AdminUser
• RegularUser
• StaffUser
• SomeWeirdUser
• …
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
function Point (x, y) {
this.x = x
this.y = y
}
function assertNumber (x) {
if (typeof x !== "number") {
throw new Error("Incorrect number")
}
}
const checks = {
x: assertNumber,
y: assertNumber
}
function createPoint (...args) {
return new Proxy(new Point(...args), {
set (target, key, value) {
const v = checks[key] || (x => x)
v(value, target)
target[key] = value
}
})
}
Przykład: Prywatne wartości
Proxy
• Brak dostępu do wartości
• Bez użycia domknięć
• http://bit.ly/privatejs
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
function User (name, password) {
this.name = name
this.password = password

}
User.prototype.login = function () {
console.log(this.name, this.password)
}
function createUser (...args) {
const priv = [ "password" ]
return new Proxy(new User(...args), {
get (target, key) {
return priv.includes(key) ?
undefined : target[key]
},
ownKeys (target) {
return Reflect.ownKeys(target)
.filter(key => !priv.includes(key))
}
})
}
const user = createUser("name", "pass")
Object.keys(user) // [ "name" ]
user.login() // "name" undefined
Przykład: Prywatne wartości
Proxy
• Brak dostępu do wartości
• Bez użycia domknięć
• „this” kieruje na proxy, jako metoda proxy
• http://bit.ly/privatejs
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
User.prototype.login = function () {
console.log(this.name, this.password)
}
get (target, key) {
return priv.includes(key) ?
undefined : target[key]
}
function User (name, password) {
this.name = name
this.password = password

}
User.prototype.login = function () {
console.log(this.name, this.password)
}
function createUser (...args) {
const priv = [ "password" ]
return new Proxy(new User(...args), {
get (target, key) {
return priv.includes(key) ?
undefined : target[key]
},
ownKeys (target) {
return Reflect.ownKeys(target)
.filter(key => !priv.includes(key))
}
})
}
const user = createUser("name", "pass")
Object.keys(user) // [ "name" ]
user.login() // "name" undefined
Przykład: Prywatne wartości
Proxy
• Brak dostępu do wartości
• Bez użycia domknięć
• „this” kieruje na proxy, jako metoda proxy
• http://bit.ly/privatejs
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
function User (name, password) {
this.name = name
this.password = password

}
/* User.prototype.login as before */
function createUser (...args) {
const priv = [ "password" ]
return new Proxy(new User(...args), {
get (t, key) {
if (typeof t[key] === "function") {
return (...args) => {
return t[key](...args)
}
}
return priv.includes(key) ?
undefined : t[key]
},
ownKeys (target) {
return Reflect.ownKeys(target)
.filter(key => !priv.includes(key))
}
})
}
Przykład: QueryBuilder/DSL
Proxy
• Dynamiczne łańcuchy funkcjonalności
Dawid Rusnak

www.drcode.pl / GitHub: @rangoo94
function QueryBuilder () {
return new Proxy([], {
get (parts, prop, proxy) {
if (prop === "value") {
return parts.join(" ")
}
prop = prop.toUpperCase()
return arg => {
parts.push(`${prop} ${arg}`)
return proxy
}
}
})
}
new QueryBuilder()
.select("*")
.from("articles")
.where("user_id = 10")
.and("visible = true")
.value
// "SELECT * FROM articles
WHERE user_id = 10 AND visible = true"
Dziękuję za uwagę!
dawid@drcode.pl
www.drcode.pl
github.com/rangoo94
linkedin.com/in/dawidrusnak
http://bit.ly/metaprogramowaniejs

Contenu connexe

Tendances

Uruchomienie i praca z laravel w wirtualnym kontenerze docker'a
Uruchomienie i praca z laravel w wirtualnym kontenerze docker'aUruchomienie i praca z laravel w wirtualnym kontenerze docker'a
Uruchomienie i praca z laravel w wirtualnym kontenerze docker'aLaravel Poland MeetUp
 
Laravel Poznań Meetup #3 - Uruchomienie i praca z Laravel w wirtualnym konten...
Laravel Poznań Meetup #3 - Uruchomienie i praca z Laravel w wirtualnym konten...Laravel Poznań Meetup #3 - Uruchomienie i praca z Laravel w wirtualnym konten...
Laravel Poznań Meetup #3 - Uruchomienie i praca z Laravel w wirtualnym konten...HighSolutions Sp. z o.o.
 
Webpack - Czym jest webpack i dlaczego chcesz go używać? - wersja krótka
Webpack - Czym jest webpack i dlaczego chcesz go używać? - wersja krótkaWebpack - Czym jest webpack i dlaczego chcesz go używać? - wersja krótka
Webpack - Czym jest webpack i dlaczego chcesz go używać? - wersja krótkaMarcin Gajda
 
Kubernetes (Canary) Deployments
Kubernetes (Canary) DeploymentsKubernetes (Canary) Deployments
Kubernetes (Canary) DeploymentsThe Software House
 
Ansible - Automatyzacja zadań IT
Ansible - Automatyzacja zadań ITAnsible - Automatyzacja zadań IT
Ansible - Automatyzacja zadań ITKamil Grabowski
 
[BDD] Introduction to Behat (PL)
[BDD] Introduction to Behat (PL)[BDD] Introduction to Behat (PL)
[BDD] Introduction to Behat (PL)Piotr Pelczar
 
Sekrety magicznego ogrodu Docker
Sekrety magicznego ogrodu DockerSekrety magicznego ogrodu Docker
Sekrety magicznego ogrodu DockerKamil Grabowski
 
Wprowadzenie do testów wydajnościowych w k6
Wprowadzenie do testów wydajnościowych w k6Wprowadzenie do testów wydajnościowych w k6
Wprowadzenie do testów wydajnościowych w k6The Software House
 
PHP@Docker - w produkcji
PHP@Docker - w produkcjiPHP@Docker - w produkcji
PHP@Docker - w produkcjiMarcin Kurzyna
 
Szybkie stawianie aplikacji z Elastic Beanstalk
Szybkie stawianie aplikacji z Elastic BeanstalkSzybkie stawianie aplikacji z Elastic Beanstalk
Szybkie stawianie aplikacji z Elastic BeanstalkThe Software House
 
Ruby, Ruby on Rails 2010
Ruby, Ruby on Rails 2010Ruby, Ruby on Rails 2010
Ruby, Ruby on Rails 2010Natalia Stanko
 
Jak poprawić Core Web Vitals w aplikacji Next.js
Jak poprawić Core Web Vitals w aplikacji Next.jsJak poprawić Core Web Vitals w aplikacji Next.js
Jak poprawić Core Web Vitals w aplikacji Next.jsThe Software House
 
Deployment kodu z Capistrano
Deployment kodu z CapistranoDeployment kodu z Capistrano
Deployment kodu z CapistranoMichał Szajbe
 
Automatyzacja utrzymania jakości w środowisku PHP
Automatyzacja utrzymania jakości w środowisku PHPAutomatyzacja utrzymania jakości w środowisku PHP
Automatyzacja utrzymania jakości w środowisku PHPLaravel Poland MeetUp
 
Shall we play a game? PL version
Shall we play a game? PL versionShall we play a game? PL version
Shall we play a game? PL versionMaciej Lasyk
 
DynamoDB – podstawy modelowania danych dla opornych
DynamoDB – podstawy modelowania danych dla opornychDynamoDB – podstawy modelowania danych dla opornych
DynamoDB – podstawy modelowania danych dla opornychThe Software House
 

Tendances (20)

Infrastructure As Code
Infrastructure As CodeInfrastructure As Code
Infrastructure As Code
 
Rundeck & Ansible
Rundeck & AnsibleRundeck & Ansible
Rundeck & Ansible
 
Uruchomienie i praca z laravel w wirtualnym kontenerze docker'a
Uruchomienie i praca z laravel w wirtualnym kontenerze docker'aUruchomienie i praca z laravel w wirtualnym kontenerze docker'a
Uruchomienie i praca z laravel w wirtualnym kontenerze docker'a
 
Laravel Poznań Meetup #3 - Uruchomienie i praca z Laravel w wirtualnym konten...
Laravel Poznań Meetup #3 - Uruchomienie i praca z Laravel w wirtualnym konten...Laravel Poznań Meetup #3 - Uruchomienie i praca z Laravel w wirtualnym konten...
Laravel Poznań Meetup #3 - Uruchomienie i praca z Laravel w wirtualnym konten...
 
Webpack - Czym jest webpack i dlaczego chcesz go używać? - wersja krótka
Webpack - Czym jest webpack i dlaczego chcesz go używać? - wersja krótkaWebpack - Czym jest webpack i dlaczego chcesz go używać? - wersja krótka
Webpack - Czym jest webpack i dlaczego chcesz go używać? - wersja krótka
 
Kubernetes (Canary) Deployments
Kubernetes (Canary) DeploymentsKubernetes (Canary) Deployments
Kubernetes (Canary) Deployments
 
Monitoring sieci
Monitoring sieciMonitoring sieci
Monitoring sieci
 
Ansible - Automatyzacja zadań IT
Ansible - Automatyzacja zadań ITAnsible - Automatyzacja zadań IT
Ansible - Automatyzacja zadań IT
 
[BDD] Introduction to Behat (PL)
[BDD] Introduction to Behat (PL)[BDD] Introduction to Behat (PL)
[BDD] Introduction to Behat (PL)
 
Ansible w praktyce
Ansible w praktyceAnsible w praktyce
Ansible w praktyce
 
Sekrety magicznego ogrodu Docker
Sekrety magicznego ogrodu DockerSekrety magicznego ogrodu Docker
Sekrety magicznego ogrodu Docker
 
Wprowadzenie do testów wydajnościowych w k6
Wprowadzenie do testów wydajnościowych w k6Wprowadzenie do testów wydajnościowych w k6
Wprowadzenie do testów wydajnościowych w k6
 
PHP@Docker - w produkcji
PHP@Docker - w produkcjiPHP@Docker - w produkcji
PHP@Docker - w produkcji
 
Szybkie stawianie aplikacji z Elastic Beanstalk
Szybkie stawianie aplikacji z Elastic BeanstalkSzybkie stawianie aplikacji z Elastic Beanstalk
Szybkie stawianie aplikacji z Elastic Beanstalk
 
Ruby, Ruby on Rails 2010
Ruby, Ruby on Rails 2010Ruby, Ruby on Rails 2010
Ruby, Ruby on Rails 2010
 
Jak poprawić Core Web Vitals w aplikacji Next.js
Jak poprawić Core Web Vitals w aplikacji Next.jsJak poprawić Core Web Vitals w aplikacji Next.js
Jak poprawić Core Web Vitals w aplikacji Next.js
 
Deployment kodu z Capistrano
Deployment kodu z CapistranoDeployment kodu z Capistrano
Deployment kodu z Capistrano
 
Automatyzacja utrzymania jakości w środowisku PHP
Automatyzacja utrzymania jakości w środowisku PHPAutomatyzacja utrzymania jakości w środowisku PHP
Automatyzacja utrzymania jakości w środowisku PHP
 
Shall we play a game? PL version
Shall we play a game? PL versionShall we play a game? PL version
Shall we play a game? PL version
 
DynamoDB – podstawy modelowania danych dla opornych
DynamoDB – podstawy modelowania danych dla opornychDynamoDB – podstawy modelowania danych dla opornych
DynamoDB – podstawy modelowania danych dla opornych
 

Similaire à Metaprogramowanie w JS

Modularny JavaScript - meet.js
Modularny JavaScript - meet.jsModularny JavaScript - meet.js
Modularny JavaScript - meet.jsPatryk Jar
 
Mvc frontend-trug-02-2011
Mvc frontend-trug-02-2011Mvc frontend-trug-02-2011
Mvc frontend-trug-02-2011Rafal Piekarski
 
[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariować[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariowaćJakub Marchwicki
 
Nowości w Javie 8 okiem programisty
Nowości w Javie 8 okiem programistyNowości w Javie 8 okiem programisty
Nowości w Javie 8 okiem programistyMarcinStachniuk
 
WordUp Trójmiasto - Sage 9 w praktyce
WordUp Trójmiasto - Sage 9 w praktyceWordUp Trójmiasto - Sage 9 w praktyce
WordUp Trójmiasto - Sage 9 w praktyceDawid Urbański
 
Testowanie bezpieczeństwa aplikacji dedykowanych na platformę Android
Testowanie bezpieczeństwa aplikacji dedykowanych na platformę AndroidTestowanie bezpieczeństwa aplikacji dedykowanych na platformę Android
Testowanie bezpieczeństwa aplikacji dedykowanych na platformę AndroidSecuRing
 
AADays 2015 - Jak to zrobic w JavaScript
AADays 2015 - Jak to zrobic w JavaScriptAADays 2015 - Jak to zrobic w JavaScript
AADays 2015 - Jak to zrobic w JavaScriptJacek Okrojek
 
Michał Dec - Quality in Clouds
Michał Dec - Quality in CloudsMichał Dec - Quality in Clouds
Michał Dec - Quality in Cloudskraqa
 
Using Red Gate SQL Doc for database documentation
Using Red Gate SQL Doc for database documentationUsing Red Gate SQL Doc for database documentation
Using Red Gate SQL Doc for database documentationMariusz Koprowski
 
RxJS okiem doświadczonego inżyniera - Angular Warsaw #13
RxJS okiem doświadczonego inżyniera - Angular Warsaw #13RxJS okiem doświadczonego inżyniera - Angular Warsaw #13
RxJS okiem doświadczonego inżyniera - Angular Warsaw #13Piotr Kowalski
 
4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski
4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski
4Developers 2015: Property-based testing w języku Scala - Paweł GrajewskiPROIDEA
 
[Quality Meetup #9] TestOps, QAOps - czy ktoś taki istnieje? - Aleksandra Kor...
[Quality Meetup #9] TestOps, QAOps - czy ktoś taki istnieje? - Aleksandra Kor...[Quality Meetup #9] TestOps, QAOps - czy ktoś taki istnieje? - Aleksandra Kor...
[Quality Meetup #9] TestOps, QAOps - czy ktoś taki istnieje? - Aleksandra Kor...Future Processing
 
Confitura 2018 - Sekretne życie jobów Sparkowych
Confitura 2018 - Sekretne życie jobów SparkowychConfitura 2018 - Sekretne życie jobów Sparkowych
Confitura 2018 - Sekretne życie jobów SparkowychMarcin Jasiński
 
Jak nadążyć za światem front-endu - WordPress Training Day
Jak nadążyć za światem front-endu - WordPress Training DayJak nadążyć za światem front-endu - WordPress Training Day
Jak nadążyć za światem front-endu - WordPress Training DayTomasz Dziuda
 
Czym jest złożoność ?
Czym jest złożoność ?Czym jest złożoność ?
Czym jest złożoność ?GOG.com dev team
 
Jarorcon Sp
Jarorcon SpJarorcon Sp
Jarorcon Spjarorcon
 

Similaire à Metaprogramowanie w JS (20)

Mongodb with Rails
Mongodb with RailsMongodb with Rails
Mongodb with Rails
 
Refaktoryzacja
RefaktoryzacjaRefaktoryzacja
Refaktoryzacja
 
Modularny JavaScript - meet.js
Modularny JavaScript - meet.jsModularny JavaScript - meet.js
Modularny JavaScript - meet.js
 
Mvc frontend-trug-02-2011
Mvc frontend-trug-02-2011Mvc frontend-trug-02-2011
Mvc frontend-trug-02-2011
 
JavaScript, Moduły
JavaScript, ModułyJavaScript, Moduły
JavaScript, Moduły
 
[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariować[PL] Jak programować aby nie zwariować
[PL] Jak programować aby nie zwariować
 
Nowości w Javie 8 okiem programisty
Nowości w Javie 8 okiem programistyNowości w Javie 8 okiem programisty
Nowości w Javie 8 okiem programisty
 
WordUp Trójmiasto - Sage 9 w praktyce
WordUp Trójmiasto - Sage 9 w praktyceWordUp Trójmiasto - Sage 9 w praktyce
WordUp Trójmiasto - Sage 9 w praktyce
 
Testowanie bezpieczeństwa aplikacji dedykowanych na platformę Android
Testowanie bezpieczeństwa aplikacji dedykowanych na platformę AndroidTestowanie bezpieczeństwa aplikacji dedykowanych na platformę Android
Testowanie bezpieczeństwa aplikacji dedykowanych na platformę Android
 
AADays 2015 - Jak to zrobic w JavaScript
AADays 2015 - Jak to zrobic w JavaScriptAADays 2015 - Jak to zrobic w JavaScript
AADays 2015 - Jak to zrobic w JavaScript
 
Michał Dec - Quality in Clouds
Michał Dec - Quality in CloudsMichał Dec - Quality in Clouds
Michał Dec - Quality in Clouds
 
Using Red Gate SQL Doc for database documentation
Using Red Gate SQL Doc for database documentationUsing Red Gate SQL Doc for database documentation
Using Red Gate SQL Doc for database documentation
 
RxJS okiem doświadczonego inżyniera - Angular Warsaw #13
RxJS okiem doświadczonego inżyniera - Angular Warsaw #13RxJS okiem doświadczonego inżyniera - Angular Warsaw #13
RxJS okiem doświadczonego inżyniera - Angular Warsaw #13
 
4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski
4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski
4Developers 2015: Property-based testing w języku Scala - Paweł Grajewski
 
[Quality Meetup #9] TestOps, QAOps - czy ktoś taki istnieje? - Aleksandra Kor...
[Quality Meetup #9] TestOps, QAOps - czy ktoś taki istnieje? - Aleksandra Kor...[Quality Meetup #9] TestOps, QAOps - czy ktoś taki istnieje? - Aleksandra Kor...
[Quality Meetup #9] TestOps, QAOps - czy ktoś taki istnieje? - Aleksandra Kor...
 
Iron Python I Dlr
Iron Python I DlrIron Python I Dlr
Iron Python I Dlr
 
Confitura 2018 - Sekretne życie jobów Sparkowych
Confitura 2018 - Sekretne życie jobów SparkowychConfitura 2018 - Sekretne życie jobów Sparkowych
Confitura 2018 - Sekretne życie jobów Sparkowych
 
Jak nadążyć za światem front-endu - WordPress Training Day
Jak nadążyć za światem front-endu - WordPress Training DayJak nadążyć za światem front-endu - WordPress Training Day
Jak nadążyć za światem front-endu - WordPress Training Day
 
Czym jest złożoność ?
Czym jest złożoność ?Czym jest złożoność ?
Czym jest złożoność ?
 
Jarorcon Sp
Jarorcon SpJarorcon Sp
Jarorcon Sp
 

Metaprogramowanie w JS

  • 1. Metaprogramowanie w JS Spojrzenie na interesujące wewnętrzne mechanizmy Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 2. Achtung! Danger! Uwaga! Metaprogramowanie w JS Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 3. Zajawka Metaprogramowanie w JS Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 4. Zajawka Metaprogramowanie w JS Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 5. Zajawka Metaprogramowanie w JS Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 6. Zajawka Metaprogramowanie w JS Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 7. Zajawka Metaprogramowanie w JS What the Hack? 
 Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 What the Hack? What the Hack? What the Hack?
  • 8. Agenda Metaprogramowanie w JS Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Czym jest metaprogramowanie? • Metaprogramming API • Podstawowe symbole • Proxy
  • 9. Czym jest metaprogramowanie? Czyli kilka słów teorii Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 Why do JS developers wear glasses? Because they don’t C#
  • 10. Definicja Czym jest metaprogramowanie? Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Program, który tworzy lub modyfikuje inny program - metaprogram • Program, który modyfikuje samego siebie
  • 11. Definicja Czym jest metaprogramowanie? Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Program, który tworzy lub modyfikuje inny program - metaprogram • Kompilatory - np. parsowanie i optymalizacja kodu • Transpilery - np. modyfikacja kodu żeby był zgodny z urządzeniem • IDE - np. analiza JSDoc • Program, który modyfikuje samego siebie • Mechanizmy refleksji
  • 12. Definicja Czym jest metaprogramowanie? • Program, który tworzy lub modyfikuje inny program - metaprogram • Kompilatory - np. parsowanie i optymalizacja kodu • Transpilery - np. modyfikacja kodu żeby był zgodny z urządzeniem • IDE - np. analiza JSDoc • Program, który modyfikuje samego siebie • Mechanizmy refleksji Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 13. Modyfikacja programu innym programem Czym jest metaprogramowanie? • Program, który tworzy lub modyfikuje inny program - metaprogram Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 #define true false #define private public Robienie zamieszania w C dzięki makrom / Zły kod nie zależy od języka
  • 14. Programowanie refleksyjne Czym jest metaprogramowanie? Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Introspekcja - czytanie struktury programu • Modyfikacja - zmiana struktury programu • Intercesja - „wchodzenie pomiędzy” - zmiana semantyki języka/programu
  • 15. Przykłady metaprogramowania Co możemy dzięki temu osiągnąć? Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 SQL query goes into a bar, walks up to
 two tables and asks "Can I join you?"
  • 16. Przeciążanie operatorów Przykłady metaprogramowania Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 // Ruby class X attr_reader :order def +(y) y + 2 end def <=>(other) self.order <=> other.order end end instance = X.new instance + 3 // => 5 // C++ struct X { int operator+(int y) { return y + 2; } }; int main () { X instance; std::cout << instance + 3; // => 5 return 0; }
  • 17. Destruktory Przykłady metaprogramowania Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 // Python class X: def __del__(self): self.connection.close() // PHP class X { private function __destruct() { $this->connection->close(); } }
  • 18. Obsługa dynamicznych pól Przykłady metaprogramowania Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 // PHP class X { public function __get($field) { return $field . " value"; } } // Ruby class X def method_missing(m, *args, &block) "#{m} value" end end
  • 19. Adnotacje i dekoratory Przykłady metaprogramowania Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 // Java @Entity public class X { @Id @GeneratedValue @Column(name = "id") private int id; public X() {} } // JavaScript class X { @emitOnEnd("someEvent") doSomething () { console.log("Something there") } }
  • 20. Prywatne wartości Przykłady metaprogramowania Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 // PHP class X { private $name; } // C++ class X { private: string name; }
  • 21. Imitowanie tablicy Przykłady metaprogramowania Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 // PHP class X implements ArrayAccess { public function offsetExists ($o) {} public function offsetGet ($o) {} public function offsetSet ($o, $v) {} public function offsetUnset ($o) {} } $instance = new X(); $instance["key"]; $instance[0]; // JavaScript // Array-like object const a = { 0: 1, 1: 4943, 2: 2213, length: 3 } a[0];
  • 22. Przeciążanie metod/klas Przykłady metaprogramowania Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 // Ruby class X def something 'hello!' end end class X def somethingElse 'hello 2!' end end instance = X.new instance.print // => "hello!" instance.printSomething // => "hello 2!" // JavaScript // Works pretty good! function X () {} X.prototype.something = function () {
 return "hello!" } X.prototype.somethingElse = function () { return "hello 2!" } instance = new X() instance.print() // => "hello!" instance.printSomething() // => "hello 2!”
  • 23. Metaprogramming API Podstawowe możliwości w JavaScript Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 I've got a really good UDP joke to tell you, but I don't know if you'll get it
  • 24. Na co nam pozwala podstawowe API? Metaprogramming API • Analiza i modyfikacja struktury obiektów • Czytanie informacji o funkcjach • Zarządzanie łańcuchem prototypów Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 25. Analiza i modyfikacja obiektów Metaprogramming API Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Czytanie podstawowej struktury obiektów • Zarządzanie stałością obiektów (mutability) • Łańcuch prototypów Object.getPrototypeOf(obj) Object.setPrototypeOf(obj, null) Object.hasOwnProperty("key") // => true Object.getOwnPropertyNames(obj) Object.keys(obj) // => [ "key" ] Object.preventExtensions(obj) Object.isExtensible(obj) // => false Object.seal(obj) Object.isSealed(obj) // => true Object.freeze(obj) Object.isFrozen(obj) // => true
  • 26. Funkcje Metaprogramming API Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Wykonywanie funkcji • Czytanie struktury funkcji • Tworzenie funkcji Math.max.call(Math, 10, 20) // => 20 Math.max.apply(Math, [ 10, 20 ]) // => 20 const func = Array.prototype.concat.bind([ 10, 30 ], 20) func(40) // => [ 10, 30, 20, 40 ] function test (a, b) {} test.length // => 2 test.toString() // => "function test (a, b) {}" function test2 (a, ...args) {} test2.length // => 1 const sum = new Function("a", "b", "return a + b") sum(10, 20) // => 30
  • 27. Reflect API Metaprogramming API Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 // Function options wrappers Reflect.apply(Math.max, null, [ 5, 15 ]) Reflect.construct(X, [ "John" ]) // Language wrappers Reflect.has(…) // „in” operator Reflect.deleteProperty(…) // „delete” Reflect.get(…) // access property Reflect.set(…) // set property value // Object methods wrappers Reflect.defineProperty(…) Reflect.getOwnPropertyDescriptor(…) Reflect.ownKeys(…) Reflect.preventExtensions(…) Reflect.isExtensible(…) Reflect.getPrototypeOf(…) Reflect.setPrototypeOf(…) • Elastyczniejsze API do wielu metod: • API funkcji • Operacje języka • Refleksja obiektów
  • 28. Przykłady użycia Metaprogramming API Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Dependency Injection (użyte podobnie w AngularJS) function test ($m, $s) { const fnRegex = /function[s]+[^(]+(([^)]+))/ return $m.pow($s.points, 2) const args = test.toString().match(fnRegex)[1]
 } args.split(/[s]*,[s]*/) // [ "$a", "$b" ] const object = { "key": "value" } // Object.create(object) function HiddenObject () { } HiddenObject.prototype = object const hiddenObject = new HiddenObject() HiddenObject.prototype = null hiddenObject // => { "prototype": null } hiddenObject.key // => "value" Object.getPrototypeOf(hiddenObject) // => { "key": "value" } • Ukrywanie prototypu
  • 29. Deskryptor pola - z czego się może składać? Metaprogramming API Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 const object = {} Object.defineProperty(object, "key", { value: "Field Value", // writable: false, // get: () => "Field Value", set: function (value) { this.x = value + "abc" }, configurable: true, enumerable: false } Object.keys(object) // => [] object.key // => "Field value" object.x // => undefined object.key = "Def" object.key // "Field value" object.x // => "Defabc" • Wartość pola - value • Getter / Setter - get/set • Można przypisać wartość? - writable • Definicja może się zmienić? - configurable • Pole powinno być widoczne? - enumerable • writable || set • value || get
  • 30. Dekoratory pól Metaprogramming API Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 function readOnly ( target, propertyName, descriptor ) { descriptor.writable = false } const object = { @readOnly field: "value" } object.field // => "value" object.field = "something" object.field // => "value" • Dekoratory mogę zmienić deskryptor pola: • Mogą nadpisać jego wartość • Zmienić gettery/settery • Zapisać informację jako efekt uboczny
  • 31. Dekoratory klas Metaprogramming API Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 function Serializable (Cls) { Cls.prototype.toString = function () { const str = JSON.stringify(this) return Cls.name + ": " + str } } @Serializable class Point { constructor (x, y) { this.x = x this.y = y } } const point = new Point(1, 5) console.log(point.toString()) // "Point: {"x":1,"y":5}" • W klasie dekoratory mogą nadpisać klasę
 lub edytować jej prototyp w dowolny sposób
  • 32. Dekoratory klas: przykład Metaprogramming API Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 @Entity() class User extends BaseEntity { @PrimaryGeneratedColumn() id: number; @Column() firstName: string; @Column() lastName: string; @Column() age: number; } • ActiveRecord / ORM • Przykład z TypeORM
 https://github.com/typeorm/typeorm
  • 33. Podstawowe symbole Zmiana semantyki działania programu Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 Why do programmers confuse Halloween with Christmas? Because OCT 31 = DEC 25.
  • 34. Czym są symbole? Podstawowe symbole // Declare standard symbol const internal = Symbol() const symbol = Symbol() symbol == internal // => false • Używane jako unikalna wartość • Nie kolidują z innymi typami Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 35. Czym są symbole? Podstawowe symbole // Declare standard symbol const internal = Symbol() const symbol = Symbol() symbol == internal // => false // Prepare example object const object = {} // Set up some value in object object[internal] = "value" object[internal] + "s" // => "values" Object.keys(object) // => [] • Używane jako unikalna wartość • Nie kolidują z innymi typami • Mogą być używane jako klucz obiektu • Ukryte w obiekcie
 poza getOwnPropertySymbols i Reflect.ownKeys Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 36. Czym są symbole? Podstawowe symbole // Declare standard symbol const internal = Symbol.for("debug")
 const symbol = Symbol.for("debug")
 
 internal == symbol // => true Symbol.keyFor(internal) // => „debug" • Mogą mieć swój identyfikator • Do pobrania przez Symbol.keyFor Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 37. Well-known symbols Podstawowe symbole class Something { // getter in constructor static get [Symbol.isMagical] () { return true } // getter for instance get [Symbol.isMagicDone] () { return "Magic has been done" } // method for instance [Symbol.makeMagic] () { // Poof! } } • Dostępne w przestrzeni Symbol • Przykłady Symbol.iterator, Symbol.species • Przypisane do prototypu lub bezpośrednio
 do konstruktora Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 38. Symbol.iterator Podstawowe symbole class Range { constructor (from, to) { this.from = from this.to = to } *[Symbol.iterator] () { let i = this.from while (i <= this.to) { yield i i++ } } } const range = [ ...new Range(1, 5) ] console.log(range) // [ 1, 2, 3, 4, 5 ] • Pozwala na implementację iteratora • for…of loop • spread operator - [ …arr ] • Array.from Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 39. Symbol.toPrimitive Podstawowe symbole const person = { name: "John Doe", [Symbol.toPrimitive] (hint) { if (hint === "string") { return this.name } else if (hint === "number") { return this.name.length } // "default" return "Hi, I am " + this.name } }
 `${person}` // => "John Doe" +person // => 8 person + "" // => "Hi, I am John Doe" person + 3 // => "Hi, I am John Doe3" • Zmiana zachowania przy zrzucaniu do typu • Rozróżnia prymitywne typy Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 40. Symbol.hasInstance Podstawowe symbole const notNode = x => !(x instanceof Node) class Node {} class NodeList extends Array { static get [Symbol.hasInstance] (o) { const proto = Object.getPrototypeOf(o) const c = proto.constructor if (c === NodeList) { return true } if (!Array.isArray(o)) { return false } return o.findIndex(notNode) === -1 } } const node = new Node() [ 1 ] instanceof NodeList // => false [ node ] instanceof NodeList // => true Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Definiuje działanie instanceof • Sprawdza czy obiekt jest „instancją” klasy • Sugar syntax:
 obj instanceof Iterable wygląda lepiej niż:
 isIterable(obj) czy Symbol.iterator in obj
  • 41. Symbol.species Podstawowe symbole // Standard behavior class TimeoutPromise extends Promise {} const self = x => x const promise = new TimeoutPromise(self) promise.then(x => x) // => TimeoutPromise // Modified behavior class TimeoutPromise extends Promise { static get [Symbol.species] () { return Promise } } const self = x => x const promise = new TimeoutPromise(self) promise.then(x => x) // => Promise • Zmienia zwracany typ z podstawowych metod • Przydatny jeśli chcemy przejść do standardu Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 42. Symbol.isConcatSpreadable Podstawowe symbole // Standard behavior const o = { 0: "a", 1: "b", length: 2 } [ 1 ].concat(o) // => [ 1,{0:"a",1:"b"} ] // Modified behavior
 const o = { 0: "a", 1: "b", length: 2, [Symbol.isConcatSpreadable]: true } [ 1 ].concat(o) // => [ 1, "a", "b" ] • Definiuje zachowanie funkcji concat • Decyduje czy obiekt ma być spłaszczony Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 43. Symbol.match, replace, split i search Podstawowe symbole const str = "<strong>Success</strong>" class Tag { constructor (name) { this.name = name } [Symbol.search] (str) { return str.indexOf( "<" + this.name + ">" ) } } str.search(new Tag("strong")) // => 0 Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 • Definiują działanie obiektu w kilku metodach • string.split(object) • string.search(object) • string.replace(object, replacement) • string.match(object)
  • 44. Symbol.toStringTag Podstawowe symbole // Standard behavior const object = {} "" + object // => "[object Object]" // Modified behavior const object = { [Symbol.toStringTag]: "X" } "" + object // => "[object X]" • Definiuje podstawowy tag nazwy obiektu Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 45. Symbol.unscopables Podstawowe symbole // Declare object const object = { txt1: "value", txt2: "value2", [Symbol.unscopables]: { "txt2": true } } with (object) { console.log(txt1) // => "value" console.log(txt2) // ReferenceError } • Blokuje pola dla konstrukcji with {} Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 46. Proxy Podsłuchujemy i przejmujemy aplikację! Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 - Knock knock. - Race condition. - Who’s there?
  • 47. Jak działa proxy? Proxy function SomeObject () { this.pre = "Something " } const object = new SomeObject() const proxy = new Proxy(object, { get (target, property) { return target.pre + property } }) proxy.special // "Something special" proxy.funny // "Something funny" Object.getPrototypeOf(proxy).constructor // SomeObject • Ustawia pułapki („traps”) na akcje • Pozwala dynamicznie na zmiany zachowania • Ma dostęp do prototypu i konstruktora • Ma dostęp do pól • Niezmienione akcje zachowują się tak samo Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94
  • 48. Gdzie możemy postawić „pułapki”? Proxy • Zmiana i pobranie parametru • Konstrukcja obiektu, wykonanie funkcji • Zmiana i pobranie prototypu • Operatory in, delete • Pobranie kluczy obiektu • Więcej: http://bit.ly/mdnproxy Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 function Something () { this.pre = "Something " } const object = new X() const proxy = new Proxy(object, { get (target, property) { return target.pre + property }, set (target, property, value) { throw new Error("You can't change!") } }) Object.getPrototypeOf(proxy) // Something proxy.special // "Something special" proxy.special = "xyz" // Error
  • 49. Przykład: Dependency Injection Proxy • Po prawej szkic DI • brak obsługi błędów • brak poprawnego cache • niezoptymalizowane • nie działa poprawnie „in” czy „getKeys” • Dynamiczne przypisanie danych • Możliwość "lazy loadingu" • Przykład: github.com/rangoo94/easen-di Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 function Di (dependencies = {}) { const cache = {} this.proxy = new Proxy(dependencies, { set (deps, prop, value) { if (typeof value !== "function") { throw new TypeError() } deps[prop] = value }, get (deps, prop) { if (!deps[prop]) { throw new ReferenceError() } if (!cache[prop]) { cache[prop] = deps[prop]() } return cache[prop] } }) } const di = new Di({ x: () => "Hello" }) di.proxy.x // "Hello"
  • 50. Przykład: Automatyczna walidacja na osobnej warstwie Proxy • Walidacja niezależna od obiektu końcowego • Możemy mieć jeden obiekt, ale N walidacji • Walidacja zależna od miejsca zmiany • Przykład - jeden model User zamiast: • CreatedUser • PostUser • AdminUser • RegularUser • StaffUser • SomeWeirdUser • … Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 function Point (x, y) { this.x = x this.y = y } function assertNumber (x) { if (typeof x !== "number") { throw new Error("Incorrect number") } } const checks = { x: assertNumber, y: assertNumber } function createPoint (...args) { return new Proxy(new Point(...args), { set (target, key, value) { const v = checks[key] || (x => x) v(value, target) target[key] = value } }) }
  • 51. Przykład: Prywatne wartości Proxy • Brak dostępu do wartości • Bez użycia domknięć • http://bit.ly/privatejs Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 function User (name, password) { this.name = name this.password = password
 } User.prototype.login = function () { console.log(this.name, this.password) } function createUser (...args) { const priv = [ "password" ] return new Proxy(new User(...args), { get (target, key) { return priv.includes(key) ? undefined : target[key] }, ownKeys (target) { return Reflect.ownKeys(target) .filter(key => !priv.includes(key)) } }) } const user = createUser("name", "pass") Object.keys(user) // [ "name" ] user.login() // "name" undefined
  • 52. Przykład: Prywatne wartości Proxy • Brak dostępu do wartości • Bez użycia domknięć • „this” kieruje na proxy, jako metoda proxy • http://bit.ly/privatejs Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 User.prototype.login = function () { console.log(this.name, this.password) } get (target, key) { return priv.includes(key) ? undefined : target[key] } function User (name, password) { this.name = name this.password = password
 } User.prototype.login = function () { console.log(this.name, this.password) } function createUser (...args) { const priv = [ "password" ] return new Proxy(new User(...args), { get (target, key) { return priv.includes(key) ? undefined : target[key] }, ownKeys (target) { return Reflect.ownKeys(target) .filter(key => !priv.includes(key)) } }) } const user = createUser("name", "pass") Object.keys(user) // [ "name" ] user.login() // "name" undefined
  • 53. Przykład: Prywatne wartości Proxy • Brak dostępu do wartości • Bez użycia domknięć • „this” kieruje na proxy, jako metoda proxy • http://bit.ly/privatejs Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 function User (name, password) { this.name = name this.password = password
 } /* User.prototype.login as before */ function createUser (...args) { const priv = [ "password" ] return new Proxy(new User(...args), { get (t, key) { if (typeof t[key] === "function") { return (...args) => { return t[key](...args) } } return priv.includes(key) ? undefined : t[key] }, ownKeys (target) { return Reflect.ownKeys(target) .filter(key => !priv.includes(key)) } }) }
  • 54. Przykład: QueryBuilder/DSL Proxy • Dynamiczne łańcuchy funkcjonalności Dawid Rusnak
 www.drcode.pl / GitHub: @rangoo94 function QueryBuilder () { return new Proxy([], { get (parts, prop, proxy) { if (prop === "value") { return parts.join(" ") } prop = prop.toUpperCase() return arg => { parts.push(`${prop} ${arg}`) return proxy } } }) } new QueryBuilder() .select("*") .from("articles") .where("user_id = 10") .and("visible = true") .value // "SELECT * FROM articles WHERE user_id = 10 AND visible = true"