code_notes
71 subscribers
136 photos
1 video
134 links
учусь делать веб

обратная связь: t.me/dmorenogogoleva
Download Telegram
Геттеры и сеттеры

это свойства-аксессоры (accessor properties). По своей сути это функции, которые используются для присвоения и получения значения, но во внешнем коде они выглядят как обычные свойства объекта

как они используются в реальной жизни:
1. создаем объект с геттерами и сеттерами
const user = {
_name: 'Марина',
_surname: 'Цветаева',
get fullName() {
return `${this._name} ${this._surname}`
},
set poem(value) {
if (value.length < 4) {
throw Error('слишком короткое значение')
}
this._poem = value
},
get curPoem() {
return this._poem
}
}

2. получаем значение из геттера
user.fullName
// "Марина Цветаева"

можно даже так:
const { fullName } = user
// fullName "Марина Цветаева"

3. устанавливаем значение в сеттер
user.poem = 'Го'
Uncaught Error: слишком короткое значение

user.poem = 'Гора горевала что только грустью'

4. получаем значение, которое только что установили
user.curPoem
//"Гора горевала что только грустью"

очень удобно:
1. все вычисления в одном месте, не будет разных значений fullName в разных местах приложения
2. внутренние свойства через нижеее подчёркивание(_) обретают истинный смысл — у них не будет случайных или неправильных значений
3. простой синтаксис
прототипное наследование

- объекты наследуются от других объектов
- каждый объект имеет прототип
- он записан в специальное скрытое свойство [[Prototype]]
- задать прототип можно через __proto__
- __proto__ это не [[Prototype]]. Это геттер/сеттер для него.

const animal = {
say: 'woff'
}

const dog = {
__proto__: animal
}

const cat = {
say: 'meow',
__proto__: animal
}

dog.say
// "woff"

cat.say
// "meow"

суть прототипного наследования в том, что если мы вызываем метод, которого нет в объекте, то он ищется по цепочке прототипов, пока не найдётся

наш самый верхний объект animal наследуется от Object.prototype, что добавляет всем нашим объектам методы типа toString() и hasOwnProperty()

Object.prototype в свою очередь наследуется от null (втф)
также мы можем создавать объекты через new F()

если в F.prototype содержится объект, оператор new устанавливает его в качестве [[Prototype]] для нового объекта

const animal = {
say: 'woff'
}

const Cat = function(name){
this.name = name
}

Cat.prototype = animal

const klyaksa = new Cat('klyaksa')

console.log(klyaksa.name) // "klyaksa"
console.log(klyaksa.say) // "woff"


Установка Cat.prototype = animal буквально говорит интерпретатору следующее: "При создании объекта через new Cat() запиши ему animal в [[Prototype]]
ахах, забудьте всё, что вы читали до этого, в 2019 объекты наследуются по-другому

- создать: Object.create(proto, [descriptors])
- узнать прототип: Object.getPrototypeOf(obj)
- установить прототип: Object.setPrototypeOf(obj, proto)
const animal = {
say: 'woff'
}

const catOfCats = {
say: 'meow'
}

const cat = Object.create(animal)

Object.getPrototypeOf(cat)
// {say: "woff"}

Object.setPrototypeOf(cat, catOfCats)

cat.say
// "meow"
можно делать так:

const klyaksa = Object.create(animal, {
color: {
value: 'white'
}
});


klyaksa.color
// "white"
классы

синтаксический сахар над функциями-конструкторами, но не совсем (различия тут https://learn.javascript.ru/class#ne-prosto-sintaksicheskiy-sahar)

функция-конструктор
const UserF = function(name) {

this.name = name

this.sayHi = () => `hi! my name is ${this.name}`
}


const Masha = new UserF('Masha')

Masha.sayHi()
// "hi! my name is Masha"

класс
class UserC{
constructor(name) {
this.name = name
}

sayHi() {
return`hi! my name is ${this.name}`
}
}

const Masha = new UserC('Masha')

Masha.sayHi()
// "hi! my name is Masha"
когда мы делаем class Cat extends Animal мы добавляем ссылку на [[Prototype]] из Cat.prototype в Animal.prototype

в реальной жизни мы используем это когда class User extends React.Component и получаем в нашем компоненте componentDidMount и проч. методы
через super можно вызвать родительский метод

class Animal {
constructor(name) {
this.name = name
}

say() {
console.log('animal ooo')
}
}

class Cat extends Animal {
say() {
super.say()
return 'meow'
}
}

const cat = new Cat('Клякса')

cat.say()
// animal ooo
// "meow"
если мы хотим добавить что-то в конструктор, нужно обязательно писать ключевое слово super(), пушто до вызова super() у нас нет this

class Cat extends Animal {

constructor(name, color) {
super(name);
this.color = color;
}
}
статические методы

при объявлении помечаются словом static

присваиваются не классу, а его prototype

class User {
static staticMethod() {
...
}
}

то же самое что
User.staticMethod = function() {
...
};
обычно статические методы используются для реализации функций, принадлежащих классу, но не к каким-то конкретным его объектам.

обычно вызываются из класса

class Article {
constructor(title, date) {
this.title = title;
this.date = date;
}

static createTodays() {
return new this("Сегодняшний дайджест", new Date());
}
}

let article = Article.createTodays();
из экземпляра класса этот метод вызвать нельзя
пример из реальной жизни

метод getInitialProps, который предоставляется фреймворком next
он выполняется на сервере и может снабдить нас полезнейшей информацией типа текущего урла

статейка о том, как можно побыстрее фетчить данные с помощью этого метода
https://nextjs.org/learn/basics/fetching-data-for-pages
приватные методы и свойства

для того, чтобы юзать свойство снаружи удобнее всего использовать get как геттер и функцию как сеттер
Чтобы поймать unhandledrejection нужно навесить обработчик на window

window.addEventListener('unhandledrejection', function(event) {
// объект события имеет два специальных свойства:
alert(event.promise); // [object Promise] - промис, который сгенерировал ошибку
alert(event.reason); // Error: Ошибка! - объект ошибки, которая не была обработана
});
статические методы промисов

1. Promise.all — принимает массив промисов (может принимать любой перебираемый объект, но обычно используется массив) и возвращает новый промис. Новый промис завершится, когда завершится весь переданный список промисов, и его результатом будет массив их результатов

Если любой из промисов завершится с ошибкой, то промис, возвращённый Promise.all, немедленно завершается с этой ошибкой.

2. Promise.allSettled !нужен полифил!
работает так же как Promise.all, но если один из промисов падает с ошибкой, то он не завершается с ошибкой, а просто передает в массив ответов ошибку вместо результата

3. Promise.race — очень похож на Promise.all, но ждёт только первый промис, из которого берёт результат (или ошибку).

4. Promise.resolve(value) — создаёт успешно выполненный промис с результатом value
let promise = new Promise(resolve => resolve(value));


5. Promise.reject — создаёт промис, завершённый с ошибкой error

let promise = new Promise((resolve, reject) => reject(error));

На практике этот метод почти никогда не используется.
// await будет ждать массив с результатами выполнения всех промисов
let results = await Promise.all([
fetch(url1),
fetch(url2),
...
]);
Генераторы могут генерировать бесконечно

Почему-то я была уверена, что знаю джаваскрипт. Если не глубоко, то хотя бы знаю про все сущности и их синтаксис. И тут я дочитала до главы про генераторы и ору.

Мне казалось, что генераторы это просто функции-фабрики и я их имплементировала уже пятьсот раз.
Но я ошибалась.

самый простой генератор выглядит так:
function* generateSequence() {
yield 1;
yield 2;
return 3;
}

🤨🤨🤨

а вот его использование:
let generator = generateSequence();

generator.next()
// {value: 1, done: false}

generator.next()
// {value: 2, done: false}

generator.next()
// {value: 3, done: true}

😐😐😐

первая ценность генераторов в том, что они являются перебираемыми объектами
function* generateSequence() {
yield 1;
yield 2;
yield 3;
}

let generator = generateSequence();

for (let value of generator) {
console.log(value)
}
// 1, 2, 3

из генератора можно сделать массив вот так:
[...generateSequence()]

// [1, 2, 3]

вторая ценность генераторов состоит в том, что их можно вкладывать друг в друга
это называется «композиция генераторов»
function* generateSequence(start, end) {
for (let i = start; i <= end; i++) yield i;
}

function* generatePasswordCodes() {

yield* generateSequence(48, 57);

yield* generateSequence(65, 90);

yield* generateSequence(97, 122);

}

let str = '';

for(let code of generatePasswordCodes()) {
str += String.fromCharCode(code);
}

// "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

третья ценность генераторов — способность обмениваться данными с вызывающим кодом
🤯🤯🤯

Чтобы это сделать, нам нужно вызвать generator.next(arg) с аргументом. Этот аргумент становится результатом yield.
function* gen() {
let ask1 = yield "2 + 2 = ?";

console.log(ask1); // 4

let ask2 = yield "3 * 3 = ?"

console.log(ask2); // 9
}

const generator = gen();

console.log(generator.next().value);

console.log(generator.next(4).value);

console.log(generator.next(9).done);