Skip to content

Proxy and Reflect #206

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions 1-js/99-js-misc/01-proxy/01-error-nonexisting/solution.md
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@

```js run
let user = {
name: "John"
let uživatel = {
jméno: "Jan"
};

function wrap(target) {
return new Proxy(target, {
get(target, prop, receiver) {
if (prop in target) {
return Reflect.get(target, prop, receiver);
function obal(cíl) {
return new Proxy(cíl, {
get(cíl, vlastnost, příjemce) {
if (vlastnost in cíl) {
return Reflect.get(cíl, vlastnost, příjemce);
} else {
throw new ReferenceError(`Property doesn't exist: "${prop}"`)
throw new ReferenceError(`Vlastnost neexistuje: "${vlastnost}"`)
}
}
});
}

user = wrap(user);
uživatel = obal(uživatel);

alert(user.name); // John
alert(user.age); // ReferenceError: Property doesn't exist: "age"
alert(uživatel.jméno); // Jan
alert(uživatel.věk); // ReferenceError: Vlastnost neexistuje: "věk"
```
28 changes: 14 additions & 14 deletions 1-js/99-js-misc/01-proxy/01-error-nonexisting/task.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,32 @@
# Error on reading non-existent property
# Chyba při načítání neexistující vlastnosti

Usually, an attempt to read a non-existent property returns `undefined`.
Pokus o načtení neexistující vlastnosti zpravidla vrátí `undefined`.

Create a proxy that throws an error for an attempt to read of a non-existent property instead.
Vytvořte proxy, která při pokusu o načtení neexistující vlastnosti místo toho vyvolá chybu.

That can help to detect programming mistakes early.
To nám může pomoci dříve detekovat programátorské chyby.

Write a function `wrap(target)` that takes an object `target` and return a proxy that adds this functionality aspect.
Napište funkci `obal(cíl)`, která vezme objekt `cíl` a vrátí proxy, která přidá tento funkcionální aspekt.

That's how it should work:
Mělo by to fungovat takto:

```js
let user = {
name: "John"
let uživatel = {
jméno: "Jan"
};

function wrap(target) {
return new Proxy(target, {
function obal(cíl) {
return new Proxy(cíl, {
*!*
/* your code */
/* váš kód */
*/!*
});
}

user = wrap(user);
uživatel = obal(uživatel);

alert(user.name); // John
alert(uživatel.jméno); // Jan
*!*
alert(user.age); // ReferenceError: Property doesn't exist: "age"
alert(uživatel.věk); // ReferenceError: Vlastnost neexistuje: "věk"
*/!*
```
20 changes: 10 additions & 10 deletions 1-js/99-js-misc/01-proxy/02-array-negative/solution.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@

```js run
let array = [1, 2, 3];
let pole = [1, 2, 3];

array = new Proxy(array, {
get(target, prop, receiver) {
if (prop < 0) {
// even if we access it like arr[1]
// prop is a string, so need to convert it to number
prop = +prop + target.length;
pole = new Proxy(pole, {
get(cíl, vlastnost, příjemce) {
if (vlastnost < 0) {
// i když k poli přistupujeme přes pole[1],
// vlastnost je řetězec, takže jej musíme konvertovat na číslo
vlastnost = +vlastnost + cíl.length;
}
return Reflect.get(target, prop, receiver);
return Reflect.get(cíl, vlastnost, příjemce);
}
});


alert(array[-1]); // 3
alert(array[-2]); // 2
alert(pole[-1]); // 3
alert(pole[-2]); // 2
```
32 changes: 16 additions & 16 deletions 1-js/99-js-misc/01-proxy/02-array-negative/task.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,33 @@

# Accessing array[-1]
# Přístup k poli[-1]

In some programming languages, we can access array elements using negative indexes, counted from the end.
V některých programovacích jazycích můžeme přistupovat k prvkům pole pomocí záporných indexů, které se počítají od konce.

Like this:
Například:

```js
let array = [1, 2, 3];
let pole = [1, 2, 3];

array[-1]; // 3, the last element
array[-2]; // 2, one step from the end
array[-3]; // 1, two steps from the end
pole[-1]; // 3, poslední prvek
pole[-2]; // 2, jeden krok od konce
pole[-3]; // 1, dva kroky od konce
```

In other words, `array[-N]` is the same as `array[array.length - N]`.
Jinými slovy, `pole[-N]` je totéž jako `pole[pole.length - N]`.

Create a proxy to implement that behavior.
Vytvořte proxy, která bude toto chování implementovat.

That's how it should work:
Měla by fungovat takto:

```js
let array = [1, 2, 3];
let pole = [1, 2, 3];

array = new Proxy(array, {
/* your code */
pole = new Proxy(pole, {
/* váš kód */
});

alert( array[-1] ); // 3
alert( array[-2] ); // 2
alert( pole[-1] ); // 3
alert( pole[-2] ); // 2

// Other array functionality should be kept "as is"
// Ostatní funkcionalita pole by měla zůstat nezměněná
```
46 changes: 23 additions & 23 deletions 1-js/99-js-misc/01-proxy/03-observable/solution.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,40 @@
The solution consists of two parts:
Řešení se skládá ze dvou částí:

1. Whenever `.observe(handler)` is called, we need to remember the handler somewhere, to be able to call it later. We can store handlers right in the object, using our symbol as the property key.
2. We need a proxy with `set` trap to call handlers in case of any change.
1. Kdykoli je zavoláno `.pozoruj(handler)`, musíme si handler někde pamatovat, abychom jej mohli volat později. Handlery si můžeme ukládat rovnou do objektu a jako klíč vlastnosti použít náš symbol.
2. Potřebujeme proxy s pastí `set`, která v případě jakékoli změny zavolá handlery.

```js run
let handlers = Symbol('handlers');
let handlery = Symbol('handlery');

function makeObservable(target) {
// 1. Initialize handlers store
target[handlers] = [];
function učiňPozorovatelným(cíl) {
// 1. Inicializace skladu handlerů
cíl[handlery] = [];

// Store the handler function in array for future calls
target.observe = function(handler) {
this[handlers].push(handler);
// Uložíme funkci handleru do pole pro budoucí volání
cíl.pozoruj = function(handler) {
this[handlery].push(handler);
};

// 2. Create a proxy to handle changes
return new Proxy(target, {
set(target, property, value, receiver) {
let success = Reflect.set(...arguments); // forward the operation to object
if (success) { // if there were no error while setting the property
// call all handlers
target[handlers].forEach(handler => handler(property, value));
// 2. Vytvoříme proxy pro zpracování změn
return new Proxy(cíl, {
set(cíl, vlastnost, hodnota, příjemce) {
let úspěch = Reflect.set(...arguments); // předáme operaci objektu
if (úspěch) { // pokud při nastavování vlastnosti nedošlo k chybě,
// zavoláme všechny handlery
cíl[handlery].forEach(handler => handler(vlastnost, hodnota));
}
return success;
return úspěch;
}
});
}

let user = {};
let uživatel = {};

user = makeObservable(user);
uživatel = učiňPozorovatelným(uživatel);

user.observe((key, value) => {
alert(`SET ${key}=${value}`);
uživatel.pozoruj((klíč, hodnota) => {
alert(`SET ${klíč}=${hodnota}`);
});

user.name = "John";
uživatel.jméno = "Jan";
```
26 changes: 13 additions & 13 deletions 1-js/99-js-misc/01-proxy/03-observable/task.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@

# Observable
# Pozorovatelný objekt

Create a function `makeObservable(target)` that "makes the object observable" by returning a proxy.
Vytvořte funkci `učiňPozorovatelným(cíl)`, která „učiní objekt pozorovatelným“ tím, že vrátí proxy.

Here's how it should work:
Mělo by to fungovat takto:

```js run
function makeObservable(target) {
/* your code */
function učiňPozorovatelným(cíl) {
/* váš kód */
}

let user = {};
user = makeObservable(user);
let uživatel = {};
uživatel = učiňPozorovatelným(uživatel);

user.observe((key, value) => {
alert(`SET ${key}=${value}`);
uživatel.pozoruj((klíč, hodnota) => {
alert(`SET ${klíč}=${hodnota}`);
});

user.name = "John"; // alerts: SET name=John
uživatel.jméno = "Jan"; // oznámí: SET jméno=Jan
```

In other words, an object returned by `makeObservable` is just like the original one, but also has the method `observe(handler)` that sets `handler` function to be called on any property change.
Jinými slovy, objekt vrácený funkcí `učiňPozorovatelným` je stejný jako původní, ale navíc obsahuje metodu `pozoruj(handler)`, která nastaví funkci `handler` tak, aby byla volána při každé změně vlastnosti.

Whenever a property changes, `handler(key, value)` is called with the name and value of the property.
Kdykoli se změní některá vlastnost, je zavolán `handler(klíč, hodnota)` s jejím názvem a hodnotou.

P.S. In this task, please only take care about writing to a property. Other operations can be implemented in a similar way.
P.S. V této úloze se postarejte jen o zápis do vlastnosti. Ostatní operace mohou být implementovány podobně.
Loading