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

обратная связь: t.me/dmorenogogoleva
Download Telegram
глобальный объект предоставляет переменные и функции, доступные в любом месте программы. По умолчанию это те, что встроены в язык или среду исполнения.

в браузере он называется window, в Node.js — global, в другой среде исполнения может называться иначе.

недавно globalThis был добавлен в язык как стандартизированное имя для глобального объекта, которое должно поддерживаться в любом окружении.
декоратор это специальная функция, которая принимает другую функцию и изменяет её поведение.
let user = {
firstName: "Маша",
sayHi() {
alert(`Привет, ${this.firstName}!`);
}
};

this передается в функцию только при следующей комбинации - obj.func(), причем должны быть одновременно все элемены в одном месте и в этом же порядке, т.е. объект перед точкой, после точки имя функции (метода) и после имени метода обязательно сразу же круглые скобки. Если хоть чего то нет - this не передается и теряется. Соответсвенно если user.sayHi (нет скобок) или просто sayHi() (нет объекта перед точкой) или например передали функцию как аргумент function (user.sayHi) {...... user.sayHi()}, а потом вызвали ее внутри функции (при передаче через аргумент this уже потерялся) - везде везде потяря this. Решают проблему явная передача/прикрепление this с помощью call/apply, bind
Стрелочные функции:

- Не имеют this.
- Не имеют arguments.
- Не могут быть вызваны с new.
Помимо значения value, свойства объекта имеют три специальных атрибута (так называемые «флаги»).

writable – если true, свойство можно изменить, иначе оно только для чтения.

enumerable – если true, свойство перечисляется в циклах, в противном случае циклы его игнорируют.

configurable – если true, свойство можно удалить, а эти атрибуты можно изменять, иначе этого делать нельзя.

Описание свойства называется дескриптор и позволяет получить полную информацию о свойстве

Дескриптор можно получить вот так:
const user = {
name: "Маша"
};

const descriptor = Object.getOwnPropertyDescriptor(user, 'name');

JSON.stringify(descriptor)

{
"value": "Маша",
"writable": true,
"enumerable": true,
"configurable": true
}



Вот так можно создать свойство, доступное только для чтения:
const user = {
name: "Маша"
};

Object.defineProperty(user, "name", {
writable: false
});

user.name = 'Саша'

user.name
//"Маша"
Геттеры и сеттеры

это свойства-аксессоры (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