// 1) get + set
const target = {
name: 'John Smith',
age: 30,
};
const handler = {
get: function (target, prop) {
console.log(`Getting the property ${prop}`);
return target[prop];
},
set: function (target, prop, value) {
console.log(`Setting the property ${prop} to ${value}`);
target[prop] = value;
},
};
const proxy = new Proxy(target, handler);
// 2) with validator fn aka encapsulation
const withValidators = person => {
const handler = {
set: function (target, prop, value) {
if ((prop === 'age' && value < 0) || value > 120) {
throw new Error('Invalid age');
return;
}
target[prop] = value;
},
};
return new Proxy(person, handler);
};
const person = withValidators({
name: 'John Smith',
age: 30,
});
// 3) caching, proxy wrap only function
const cache = {};
const getWeather = (city) => {
return "fetch -> city -> " + city
};
const proxiedGetWeather = new Proxy(getWeather, {
apply(target, thisArg, args) {
const city = args[0];
if (cache[city]) {
console.log('Loading weather data from cache...');
return cache[city];
}
cache[city] = target.apply(thisArg, args);
return cache[city];
},
});
console.log(proxiedGetWeather('San Francisco'))
console.log(proxiedGetWeather('San Francisco')) // console.log('Loading weather data from cache...');
console.log(proxiedGetWeather('San Francisco')) // console.log('Loading weather data from cache...');
// 4) cannot delete
const handler = {
deleteProperty(target, key) {
if (key.startsWith('_')) {
throw new Error(`Cannot delete internal property '${key}'`);
}
delete target[key];
return true;
},
};
const user = {
name: 'John Smith',
_ssn: 'XXX-YY-ZZZ',
};
const protectedUser = protectInternalProps(user);
// Throw error `Cannot delete internal property '_ssn'`
delete protectedUser._ssn;
// 5 cannot iterate
const handler = {
ownKeys(target) {
return Object.keys(target).filter(key => !key.startsWith('_'));
},
};
const user = {
name: "John Smith",
_ssn: "XXX-YY-ZZZ",
};
const protectedUser = protectInternalProps(user);
console.log(Object.keys(protectedUser)); // ['name']
for (let key in protectedUser) {
console.log(key);
}
// ['name']
// 6) private props in class before exists #privateProps
// https://phuoc.ng/collection/javascript-proxy/implement-private-properties-in-a-javascript-class/
const handler = {
get(target, key) {
if (key.startsWith('_')) {
throw new Error(`Cannot access private property '${key}'`);
}
return target[key];
},
set(target, key, value) {
if (key.startsWith('_')) {
throw new Error(`Cannot modify private property '${key}'`);
}
target[key] = value;
return true;
},
};
class ProtectedPerson {
constructor(name, age, ssn) {
this.name = name;
this.age = age;
this._ssn = ssn;
return new Proxy(this, handler);
}
getSsn() {
return this._ssn;
}
}
// failed
const person = new ProtectedPerson('John Smith', 42, '123-45-6789');
// Uncaught Error: Cannot access private property '_ssn'
person.getSsn();
// lets improve
const handler = {
get(target, key) {
if (key.startsWith('_')) {
throw new Error(`Cannot access private property '${key}'`);
}
const value = target[key];
return typeof value === 'function' ? value.bind(target) : value;
},
};
const person = new ProtectedPerson('John Smith', 42, '123-45-6789');
console.log(person.getSsn()); // 123-45-6789
// 7) exists 'in'
const handler = {
has(target, key) {
console.log(`Checking for ${key} property...`);
return key in target;
},
};
const person = {
name: 'John Smith',
age: 42,
occupation: 'developer',
};
const proxy = new Proxy(person, handler);
// Logs "Checking for name property..." and returns `true`
console.log('name' in proxy);
// Logs "Checking for email property..." and returns `false`
console.log('email' in proxy);
// 9) Reflect API
// AND rest articles and more robust solutions we can found
// https://phuoc.ng/collection/javascript-proxy/
const user = {
a: 'A',
b: {
c: "C",
d: "D"
},
x: {
y: {
z: {
first: "first nested",
second: "second nested"
}
}
}
}
const createNestedProxy = (obj) => {
return new Proxy(obj, {
get(target, prop) {
const props = prop.split('.');
let value = target;
for (const p of props) {
value = value[p];
if (value === undefined) return undefined;
}
return value;
}
});
};
const nestedUser = createNestedProxy(user);
console.log(nestedUser["b.c"]); // Vypíše: "C"
console.log(nestedUser["x.y.z.first"]); // Vypíše: "first nested"
// One storage for all ...
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
function increment() {
count.value++;
}
return { count, increment };
});
// Dynamic storage = each components get its own
export function useCounterStore(key) {
return defineStore(key, () => {
const count = ref(0);
function increment() {
count.value++;
}
return { count, increment };
})();
}
//And more ES6 style
export const useCounterStore = key => defineStore(key, () => {
const count = ref(0);
const increment = () => {
count.value++;
};
return { count, increment };
})();
// neni nutne vracet new Promise jak je vsude v prikladech
// 1
async function test () {
let resolve, reject;
const promise = new Promise((res, rej) => {
resolve = res;
reject = rej;
});
setTimeout(() => {
Math.random() > 0.5 ? resolve("ok") : reject("not ok");
}, 1500)
return promise
}
test().then(res => console.log(res)).catch(err => console.log(err))
// 2
const { promise, resolve, reject } = Promise.withResolvers();
Math.random() > 0.5 ? resolve("ok") : reject("not ok");
// https://stackoverflow.com/questions/44106907/when-to-mark-function-as-async
async function fnUsingAsync() {
// Synchronously throw half of the time
if (Math.random() < .5)
throw new Error('synchronous error')
// Return fulfilled/rejected promises half of the time
return Math.random() < .5 ?
Promise.resolve('success') :
Promise.reject(new Error('asynchronous error');
}
function fnNotUsingAsync(x) {
// Use the exact same body here than function above
}
// when using the async keyword, the function always returns a promise
// which can be fulfilled or rejected.
// No need for try-catch!
fnUsingAsync()
.then(result => /* result === 'success' */)
.catch(error => /* catch both synchronous and asynchronous error */);
// Otherwise, you will need to use a try-catch statement, because
// the exception won't be converted to a rejected promise.
try {
fnNotUsingAsync()
.then(result => /* result === 'success' */)
.catch(error => /* catch asynchronous error only */)
}
catch (error) {
/* catch synchronous error only */
}
class Test {
constructor(el, options) {
this.el = el;
const defaultOptions = {
onHover: (element, e) => {
console.log(':)))', element, e);
},
};
this.options = { ...defaultOptions, ...options };
this.mouseOverHandler = this.handleMouseOver.bind(this); // Vytvoření odkazu na metodu handleMouseOver
}
init() {
this.el.addEventListener('mouseover', this.mouseOverHandler); // Přidání posluchače události
}
destroy() {
this.el.removeEventListener('mouseover', this.mouseOverHandler); // Odstranění posluchače události
}
handleMouseOver(e) {
if (this.options.onHover) {
this.options.onHover(this.el, e);
}
}
}
/* 1 */
var item = document.getElementById("hi");
console.log(item);
item.data = {getType: function(){return this.TYPE},TYPE:"winner"};
var out = item.data.getType();
console.log("out", out);
var two = document.getElementById("hi")
console.log("should say 'winner': ", two.data.getType());
/* 2 */
window.$ = {
data: function(obj, key, val) {
if(!obj) {
return this._data;
} else if(!key) {
if(!(obj in this._data)) {
return {};
}
return this._data[obj];
} else if(arguments.length < 3) {
if(!(obj in this._data)) {
return undefined;
}
return this._data[obj][key];
} else {
if(!(obj in this._data)) {
this._data[obj] = {};
}
this._data[obj][key] = val;
}
},
_data: {}
};
$.data(document.body); // Returns {} because no data has been set for this object
$.data(document.body, 'lastUpdate', new Date());//Sets 'lastUpdate' of obj to current time
$.data(document.body, 'lastUpdate'); // Gets previously set time
$.data(document.body); // Gets object of all data, including 'lastUpdate' time
$.data(document.body, 'nonexistant'); // Returns undefined because property was never set
$.data(); // Returns all metadata
/* 3*/
/** A storage solution aimed at replacing jQuerys data function.
* Implementation Note: Elements are stored in a (WeakMap)[https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap].
* This makes sure the data is garbage collected when the node is removed.
*/
window.dataStorage = {
_storage: new WeakMap(),
put: function (element, key, obj) {
if (!this._storage.has(element)) {
this._storage.set(element, new Map());
}
this._storage.get(element).set(key, obj);
},
get: function (element, key) {
return this._storage.get(element).get(key);
},
has: function (element, key) {
return this._storage.has(element) && this._storage.get(element).has(key);
},
remove: function (element, key) {
var ret = this._storage.get(element).delete(key);
if (!this._storage.get(element).size === 0) {
this._storage.delete(element);
}
return ret;
}
}
var myElement = document.getElementById("myId");
dataStorage.put(myElement, "myKey", "myValue");
<!-- Parent -->
<template>
<CommonInput v-model="inputValue" />
</template>
<script setup lang="ts">
import { ref } from "vue";
const inputValue = ref();
</script>
<!-- Child -->
<template>
<input
:value="props.modelValue"
@input="emit('update:modelValue', $event.target.value)"
/>
</template>
<script setup lang="ts">
const props = defineProps(["modelValue"]);
const emit = defineEmits(["update:modelValue"]);
</script>
<!-- **************** With defineModel **************** -->
<!-- https://javascript.plainenglish.io/understanding-vue-3s-definemodel-for-two-way-binding-streamline-your-code-with-this-guide-ac970f365e4a -->
<!-- Parent -->
<template>
<CommonInput v-model="inputValue" />
</template>
<script setup lang="ts">
import { ref } from "vue";
const inputValue = ref();
</script>
<!-- Child -->
<template>
<input v-model="model" />
</template>
<script setup lang="ts">
// declares "modelValue" prop, consumed by parent via v-model
const model = defineModel();
// emits "update:modelValue" when mutated
model.value = "hello";
</script>
<!-- **************** Without defineModel **************** -->
<!-- Child -->
<template>
<input v-model="props.modelValue" />
</template>
<script setup lang="ts">
import { defineProps, defineEmits } from 'vue';
const props = defineProps(["modelValue"]);
const emit = defineEmits(["update:modelValue"]);
</script>
<!-- OR with computed, probably better-->
<!-- Child -->
<template>
<input v-model="inputValue" />
</template>
<script setup lang="ts">
import { computed } from 'vue';
const props = defineProps(['modelValue']);
const emit = defineEmits(['update:modelValue']);
const inputValue = computed({
get: () => props.modelValue,
set: (value) => emit('update:modelValue', value),
});
</script>