Skip to content

Commit 852b9bf

Browse files
committed
proxy
1 parent 726f08a commit 852b9bf

File tree

20 files changed

+1074
-20
lines changed

20 files changed

+1074
-20
lines changed
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
2+
```js run
3+
let user = {
4+
name: "John"
5+
};
6+
7+
function wrap(target) {
8+
return new Proxy(target, {
9+
get(target, prop, receiver) {
10+
if (prop in target) {
11+
return Reflect.get(target, prop, receiver);
12+
} else {
13+
throw new ReferenceError(`Property doesn't exist: "${prop}"`)
14+
}
15+
}
16+
});
17+
}
18+
19+
user = wrap(user);
20+
21+
alert(user.name); // John
22+
alert(user.age); // Error: Property doesn't exist
23+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
2+
# Error on reading non-existant property
3+
4+
Create a proxy that throws an error for an attempt to read of a non-existant property.
5+
6+
That can help to detect programming mistakes early.
7+
8+
Write a function `wrap(target)` that takes an object `target` and return a proxy instead with that functionality.
9+
10+
That's how it should work:
11+
12+
```js
13+
let user = {
14+
name: "John"
15+
};
16+
17+
function wrap(target) {
18+
return new Proxy(target, {
19+
*!*
20+
/* your code */
21+
*/!*
22+
});
23+
}
24+
25+
user = wrap(user);
26+
27+
alert(user.name); // John
28+
*!*
29+
alert(user.age); // Error: Property doesn't exist
30+
*/!*
31+
```
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
2+
```js run
3+
let array = [1, 2, 3];
4+
5+
array = new Proxy(array, {
6+
get(target, prop, receiver) {
7+
if (prop < 0) {
8+
// even if we access it like arr[1]
9+
// prop is a string, so need to convert it to number
10+
prop = +prop + target.length;
11+
}
12+
return Reflect.get(target, prop, receiver);
13+
}
14+
});
15+
16+
17+
alert(array[-1]); // 3
18+
alert(array[-2]); // 2
19+
```
+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
# Accessing array[-1]
3+
4+
In some languages, we can access array elements using negative indexes, counted from the end.
5+
6+
Like this:
7+
8+
```js
9+
let array = [1, 2, 3];
10+
11+
array[-1]; // 3, the last element
12+
array[-2]; // 2, one step from the end
13+
array[-3]; // 1, two steps from the end
14+
```
15+
16+
In other words, `array[-N]` is the same as `array[array.length - N]`.
17+
18+
Create a proxy to implement that behavior.
19+
20+
That's how it should work:
21+
22+
```js
23+
let array = [1, 2, 3];
24+
25+
array = new Proxy(array, {
26+
/* your code */
27+
});
28+
29+
alert( array[-1] ); // 3
30+
alert( array[-2] ); // 2
31+
32+
// Other array functionality should be kept "as is"
33+
```
+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
The solution consists of two parts:
2+
3+
1. Whenever `.observe(handler)` is called, we need to remember the handler somewhere, to be able to call it later. We can store it right in the object, using our symbol as the key.
4+
2. We need a proxy with `set` trap to call handlers in case of any change.
5+
6+
```js run
7+
let handlers = Symbol('handlers');
8+
9+
function makeObservable(target) {
10+
// 1. Initialize handlers store
11+
target[handlers] = [];
12+
13+
// Store the handler function in array for future calls
14+
target.observe = function(handler) {
15+
this[handlers].push(handler);
16+
};
17+
18+
// 2. Create a proxy to handle changes
19+
return new Proxy(target, {
20+
set(target, property, value, receiver) {
21+
let success = Reflect.set(...arguments); // forward the operation to object
22+
if (success) { // if there were no error while setting the property
23+
// call all handlers
24+
target[handlers].forEach(handler => handler(property, value));
25+
}
26+
return success;
27+
}
28+
});
29+
}
30+
31+
let user = {};
32+
33+
user = makeObservable(user);
34+
35+
user.observe((key, value) => {
36+
alert(`SET ${key}=${value}`);
37+
});
38+
39+
user.name = "John";
40+
```
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
2+
# Observable
3+
4+
Create a function `makeObservable(target)` that "makes the object observable" by returning a proxy.
5+
6+
Here's how it should work:
7+
8+
```js run
9+
function makeObservable(target) {
10+
/* your code */
11+
}
12+
13+
let user = {};
14+
user = makeObservable(user);
15+
16+
user.observe((key, value) => {
17+
alert(`SET ${key}=${value}`);
18+
});
19+
20+
user.name = "John"; // alerts: SET name=John
21+
```
22+
23+
In other words, an object returned by `makeObservable` has the method `observe(handler)`.
24+
25+
Whenever a property changes, `handler(key, value)` is called with the name and value o the property.
26+
27+
28+
P.S. In this task, please handle only writing to a property. Other operations can be implemented in a similar way.
29+
P.P.S. You might want to introduce a global variable or a global structure to store handlers. That's fine here. In real life, such function lives in a module, that has its own global scope.

0 commit comments

Comments
 (0)