index.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. // ООП: Прототипы и ES6 классы
  2. // задание 1 Store Class
  3. {
  4. class Store {
  5. #reducer;
  6. #state;
  7. #cbs = [];
  8. constructor(reducer, state) {
  9. this.#reducer = reducer;
  10. this.#state = state;
  11. }
  12. get state() {
  13. return this.#state;
  14. }
  15. dispatch(action) {
  16. this.#state = this.#reducer(this.#state, action);
  17. this.#cbs.forEach((cb) => cb());
  18. }
  19. subscribe(cb) {
  20. this.#cbs.push(cb);
  21. return () => (this.#cbs = this.#cbs.filter((c) => c !== cb));
  22. }
  23. }
  24. const reducer = (state, action) => {
  25. // обработка action и возврат нового состояния
  26. return newState;
  27. };
  28. const store = new Store(reducer, {});
  29. store.subscribe(() => {
  30. console.log('Изменено состояние:', store.state);
  31. });
  32. store.dispatch({ type: 'INCREMENT' }); // Изменено состояние: { count: 1 }
  33. store.dispatch({ type: 'DECREMENT' }); // Изменено состояние: { count: 0 }
  34. }
  35. // задание 2 Password Class
  36. {
  37. class Password {
  38. #input;
  39. #checkbox;
  40. constructor(parent, open = false) {
  41. this.#input = document.createElement('input');
  42. this.#input.type = open ? 'text' : 'password';
  43. this.#input.addEventListener('input', () => this.onChange(this.#input.value));
  44. this.#checkbox = document.createElement('input');
  45. this.#checkbox.type = 'checkbox';
  46. this.#checkbox.checked = open;
  47. this.#checkbox.addEventListener('change', () => this.setOpen(this.#checkbox.checked));
  48. parent.append(this.#input, this.#checkbox);
  49. }
  50. setValue(value) {
  51. this.#input.value = value;
  52. }
  53. getValue() {
  54. return this.#input.value;
  55. }
  56. setOpen(open) {
  57. this.#input.type = open ? 'text' : 'password';
  58. this.#checkbox.checked = open;
  59. this.onOpenChange(open);
  60. }
  61. getOpen() {
  62. return this.#checkbox.checked;
  63. }
  64. }
  65. }
  66. // задание 3 StoreThunk Class ???
  67. {
  68. class StoreThunk extends Store {
  69. constructor(reducer) {
  70. super(reducer);
  71. }
  72. dispatch(action) {
  73. if (typeof action === 'function') {
  74. return action(this.dispatch.bind(this), this.getState.bind(this));
  75. }
  76. return super.dispatch(action);
  77. }
  78. }
  79. }
  80. // или (не уверен какой из вариантов правильный)
  81. {
  82. class StoreThunk extends Store {
  83. constructor(reducer, state) {
  84. super(reducer, state);
  85. }
  86. dispatch(action) {
  87. if (typeof action === 'function') {
  88. action(this.dispatch.bind(this), this.getState.bind(this));
  89. } else {
  90. super.dispatch(action);
  91. }
  92. }
  93. }
  94. const storeThunk = new StoreThunk(reducer, {});
  95. storeThunk.subscribe(() => {
  96. console.log('State updated:', storeThunk.state);
  97. });
  98. storeThunk.dispatch({ type: 'INCREMENT' }); // State updated: { count: 1 }
  99. storeThunk.dispatch((dispatch, getState) => {
  100. setTimeout(() => {
  101. dispatch({ type: 'DECREMENT' });
  102. }, 1000);
  103. }); // State updated: { count: 0 } after 1 second
  104. }
  105. // задание 4 RGB Class
  106. {
  107. class RGB {
  108. constructor(r, g, b) {
  109. this.#r = r;
  110. this.#g = g;
  111. this.#b = b;
  112. }
  113. get r() {
  114. return this.#r;
  115. }
  116. set r(value) {
  117. this.#r = value;
  118. }
  119. get g() {
  120. return this.#g;
  121. }
  122. set g(value) {
  123. this.#g = value;
  124. }
  125. get b() {
  126. return this.#b;
  127. }
  128. set b(value) {
  129. this.#b = value;
  130. }
  131. get rgb() {
  132. return `rgb(${this.#r}, ${this.#g}, ${this.#b})`;
  133. }
  134. set rgb(value) {
  135. const match = value.match(
  136. /^(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])\)?)$/,
  137. );
  138. if (match) {
  139. this.#r = match[2];
  140. this.#g = match[4];
  141. this.#b = match[6];
  142. }
  143. }
  144. get hex() {
  145. return `#${this.#r.toString(16).padStart(2, '0')}${this.#g
  146. .toString(16)
  147. .padStart(2, '0')}${this.#b.toString(16).padStart(2, '0')}`;
  148. }
  149. set hex(value) {
  150. const match = value.match(/^#([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})([0-9A-Fa-f]{2})$/);
  151. if (match) {
  152. this.#r = parseInt(match[1], 16);
  153. this.#g = parseInt(match[2], 16);
  154. this.#b = parseInt(match[3], 16);
  155. }
  156. }
  157. }
  158. }
  159. // задание 5 RGBA Class
  160. {
  161. class RGBA extends RGB {
  162. #a = 1;
  163. get a() {
  164. return this.#a;
  165. }
  166. set a(value) {
  167. if (value >= 0 && value <= 1) {
  168. this.#a = value;
  169. } else {
  170. throw new Error('Invalid value for a. Must be between 0 and 1');
  171. }
  172. }
  173. get hex() {
  174. return `#${super.hex.slice(1)}${Math.round(this.#a * 255)
  175. .toString(16)
  176. .padStart(2, '0')}`;
  177. }
  178. set hex(value) {
  179. if (value.length === 9) {
  180. super.hex = value.slice(0, 7);
  181. this.#a = parseInt(value.slice(7), 16) / 255;
  182. } else {
  183. super.hex = value;
  184. this.#a = 1;
  185. }
  186. }
  187. get rgba() {
  188. return `rgba(${this.#r}, ${this.#g}, ${this.#b}, ${this.#a})`;
  189. }
  190. set rgba(value) {
  191. const match = value.match(
  192. /^rgba\((\d{1,3}),\s*(\d{1,3}),\s*(\d{1,3}),\s*([0-9]*\.[0-9]+|[0-9]+)\)$/,
  193. );
  194. if (match) {
  195. super.rgb = `rgb(${match[1]}, ${match[2]}, ${match[3]})`;
  196. this.#a = parseFloat(match[4]);
  197. }
  198. }
  199. set color(value) {
  200. if (value.startsWith('#')) {
  201. this.hex = value;
  202. } else if (value.startsWith('rgb')) {
  203. super.rgb = value;
  204. this.#a = 1;
  205. } else if (value.startsWith('rgba')) {
  206. this.rgba = value;
  207. }
  208. }
  209. }
  210. }
  211. {
  212. const rgba = new RGBA(0, 0, 0, 0);
  213. rgba.hex = '#80808080';
  214. console.log(rgba.a); // 0.5
  215. console.log(rgba.rgba); // rgba(128,128,128,0.5)
  216. rgba.r = 192;
  217. rgba.a = 0.25;
  218. console.log(rgba.hex); // #C0808040
  219. rgba.color = 'rgba(1,2,3,0.70)';
  220. rgba.b *= 10;
  221. console.log(rgba.hex); // #01021EB3
  222. }