// ООП: Прототипы и ES6 классы // задание 1 Store Class { class Store { #reducer; #state; #cbs = []; constructor(reducer, state) { this.#reducer = reducer; this.#state = state; } get state() { return this.#state; } dispatch(action) { this.#state = this.#reducer(this.#state, action); this.#cbs.forEach((cb) => cb()); } subscribe(cb) { this.#cbs.push(cb); return () => (this.#cbs = this.#cbs.filter((c) => c !== cb)); } } const reducer = (state, action) => { // обработка action и возврат нового состояния return newState; }; const store = new Store(reducer, {}); store.subscribe(() => { console.log('Изменено состояние:', store.state); }); store.dispatch({ type: 'INCREMENT' }); // Изменено состояние: { count: 1 } store.dispatch({ type: 'DECREMENT' }); // Изменено состояние: { count: 0 } } // задание 2 Password Class { class Password { #input; #checkbox; constructor(parent, open = false) { this.#input = document.createElement('input'); this.#input.type = open ? 'text' : 'password'; this.#input.addEventListener('input', () => this.onChange(this.#input.value)); this.#checkbox = document.createElement('input'); this.#checkbox.type = 'checkbox'; this.#checkbox.checked = open; this.#checkbox.addEventListener('change', () => this.setOpen(this.#checkbox.checked)); parent.append(this.#input, this.#checkbox); } setValue(value) { this.#input.value = value; } getValue() { return this.#input.value; } setOpen(open) { this.#input.type = open ? 'text' : 'password'; this.#checkbox.checked = open; this.onOpenChange(open); } getOpen() { return this.#checkbox.checked; } } } // задание 3 StoreThunk Class ??? { class StoreThunk extends Store { constructor(reducer) { super(reducer); } dispatch(action) { if (typeof action === 'function') { return action(this.dispatch.bind(this), this.getState.bind(this)); } return super.dispatch(action); } } } // или (не уверен какой из вариантов правильный) { class StoreThunk extends Store { constructor(reducer, state) { super(reducer, state); } dispatch(action) { if (typeof action === 'function') { action(this.dispatch.bind(this), this.getState.bind(this)); } else { super.dispatch(action); } } } const storeThunk = new StoreThunk(reducer, {}); storeThunk.subscribe(() => { console.log('State updated:', storeThunk.state); }); storeThunk.dispatch({ type: 'INCREMENT' }); // State updated: { count: 1 } storeThunk.dispatch((dispatch, getState) => { setTimeout(() => { dispatch({ type: 'DECREMENT' }); }, 1000); }); // State updated: { count: 0 } after 1 second } // задание 4 RGB Class { class RGB { constructor(r, g, b) { this.#r = r; this.#g = g; this.#b = b; } get r() { return this.#r; } set r(value) { this.#r = value; } get g() { return this.#g; } set g(value) { this.#g = value; } get b() { return this.#b; } set b(value) { this.#b = value; } get rgb() { return `rgb(${this.#r}, ${this.#g}, ${this.#b})`; } set rgb(value) { const match = value.match( /^(rgb)?\(?([01]?\d\d?|2[0-4]\d|25[0-5])(\W+)([01]?\d\d?|2[0-4]\d|25[0-5])\W+(([01]?\d\d?|2[0-4]\d|25[0-5])\)?)$/, ); if (match) { this.#r = match[2]; this.#g = match[4]; this.#b = match[6]; } } get hex() { return `#${this.#r.toString(16).padStart(2, '0')}${this.#g .toString(16) .padStart(2, '0')}${this.#b.toString(16).padStart(2, '0')}`; } set hex(value) { const match = value.match(/^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/); if (match) { this.#r = parseInt(match[1], 16); this.#g = parseInt(match[2], 16); this.#b = parseInt(match[3], 16); } } } } // задание 5 RGBA Class { class RGBA extends RGB { #a = 1; get a() { return this.#a; } set a(value) { if (value >= 0 && value <= 1) { this.#a = value; } else { throw new Error('Invalid value for a. Must be between 0 and 1'); } } get hex() { return `#${super.hex.slice(1)}${Math.round(this.#a * 255) .toString(16) .padStart(2, '0')}`; } set hex(value) { if (value.length === 9) { super.hex = value.slice(0, 7); this.#a = parseInt(value.slice(7), 16) / 255; } else { super.hex = value; this.#a = 1; } } get rgba() { return `rgba(${this.#r}, ${this.#g}, ${this.#b}, ${this.#a})`; } set rgba(value) { const match = value.match( /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*([0-9]*\.[0-9]+|[0-9]+)\)$/, ); if (match) { super.rgb = `rgb(${match[1]}, ${match[2]}, ${match[3]})`; this.#a = parseFloat(match[4]); } } set color(value) { if (value.startsWith('#')) { this.hex = value; } else if (value.startsWith('rgb')) { super.rgb = value; this.#a = 1; } else if (value.startsWith('rgba')) { this.rgba = value; } } } } { const rgba = new RGBA(0, 0, 0, 0); rgba.hex = '#80808080'; console.log(rgba.a); // 0.5 console.log(rgba.rgba); // rgba(128,128,128,0.5) rgba.r = 192; rgba.a = 0.25; console.log(rgba.hex); // #C0808040 rgba.color = 'rgba(1,2,3,0.70)'; rgba.b *= 10; console.log(rgba.hex); // #01021EB3 }