Прототип
Я вирішив поговорити про це, оскільки вважаю, що це одна з найбільш заплутаних тем в JS. У середньому, під час кожного інтерв'ю, принаймні одне запитання обов'язково стосується цієї теми.
Прототип
Примітка: "Прототип" - це спеціальне властивість, доступна лише для об'єктів-функцій.
Ця властивість автоматично надається функціям при їх запуску.
Майже кожен об'єкт пов'язаний з іншим об'єктом. Ця зв'язок встановлюється за допомогою прототипу. Об'єкти успадковують методи та властивості батьківського об'єкта через прототип.
Властивість prototype
є в самій функції (Animal
), а не в її екземплярах (Dog
).
Щоб краще зрозуміти, давайте спробуємо розібрати наступний приклад крок за кроком:
Спершу подивимося, що відбувається при виконанні першого рядка:
Коли функція виконується, до Animal
(ознаки того, що вона оголошена з ключовим словом function) автоматично додається властивість.
Що стається, коли створюється об'єкт Dog?
- Тригерується
Animal.prototype.constructor
і створюється новий об'єкт. - Новий об'єкт призначається змінній Dog. (
Dog = {}
) - Створюється властивість
Dog
, яка вказує на__proto__
батьківського прототипу. (Dog.__proto__ === Animal.prototype
)
Додатково, давайте додамо до Animal
властивістьcolor
Оскільки у Dog
немає властивості кольору, то властивість Dog.__proto__
буде шукати її та поверне після знаходження.
Прототип: proto проти [[Prototype]]
Що таке
[[Prototype]]
? (Приватне)
Це приватний об'єкт, який використовується JavaScript на задньому плані ( недоступний розробнику ), що показує прототип об'єкту.
Що таке
__proto__
? (Публічне)
Це внутрішній властивість, яка обов'язково присутня в кожному об'єкті.
[[Prototype]]
Оскільки ми не можемо звертатися до нього напряму, для цього ми користуємося властивістю
__proto__
може бути або Object, або Null.
Як ми можемо створити об'єкт без прототипу?
Загалом, кожен об'єкт в JS успадковує Object, а Object.prototype завжди є Null.
Object.create(null)
ПРИМІТКА: Пряме встановлення proto вже не рекомендується JavaScript. (Doberman.proto = Dog)
УСТАРІЛЕ. Це наведено лише для прикладу. НЕ РОБІТЬ ТАК у реальному коді. //джерело: Mozilla
Pрототипна Ланцюг
Усі об'єкти в JS є екземплярами Object .
Кожен об'єкт може успадковувати лише один об'єкт одночасно.
Об'єкти
Як шукати будь-яке поле об'єкта?
- Спочатку поле
object
шукається у ньому самому, якщо знайдено, воно повертається,
якщо не знайдено, шукається також object.__proto__
.
Якщо його ще не знайдено, воно шукається в object.__proto__.__proto__
Процес продовжується в такому порядку (object.__proto__.__proto__.__proto__
) до досягнення Глобального Об'єкту
- Якщо в кінці не можна знайти результат, повертається
undefined
.
У прикладі нижче, успадковані поля (code, name
) не знаходяться всередині District
, тому вони повертаються зсередини District.__proto__
.
Масиви та функції
Давайте розглянемо, що успадковується при створенні масиву:
- Перший успадковує властивості від
Array.prototype
, тому має методи, такі якforEach
,join
. - Потім успадковує властивості від
Object.prototype
, тому об'єкт має методи, такі якtoString
,keys
.
Щодо функцій:
- Перша успадковує властивості від
Function.prototype
, тому має методи, такі якcall
,bind
. - Потім успадковує властивості від
Object.prototype
, тому об'єкт має методи, такі якtoString
,keys
.
З допомогою Object.create()
Метод Object.create()
дозволяє створити новий об'єкт з використанням існуючого, створюючи ланцюг прототипів.
Значення null
означає відсутність прототипу.
У випадку видалення b.id
з b
, id
залишається в a
, оскільки id
є в b.__proto__
.
Якщо було б видалено a.id
, це призвело б до видалення з обох.
Методи-доступу та задавачі
Як бачимо з прикладу, методи setColor
та getColor
належать об'єкту Dog
. Оскільки ми успадкували Doberman
від Dog
, ці методи вже існують в Dog
.
Зверніть увагу, що методи setColor
та getColor
змінюють лише властивість об'єкта, з якими вони взаємодіють.
Ітерація
Для перебору властивостей успадкованого об'єкта також використовується цикл For in.
Для кожного класу наслідника, такого як Dog та Cat, також буде доступна властивість color, оскільки всі об'єкти успадковують тип Object.
Глобальний об'єкт як функція
Глобальний об’єкт може бути викликаний як функція, що означає, що глобальний об’єкт фактично є функцією. Тому він має властивість prototype.
Усі об'єкти успадковують тип Object, у тому числі Dog та Cat.
Це означає, що Dog.proto та Cat.proto також мають властивість color.
Оператор "instanceof"
Припустимо, у нас є об'єкт dog і ми хочемо перевірити, чи належить він класу Dog. Ми можемо використовувати оператор instanceof наступним чином:
Завершивши розгляд методів, можна подивитися на процес з діаграмою:
Для більш чіткого уявлення, можна переглянути діаграму за посиланням:
[Посилання на діаграму:](https://viewer.diagrams.net/?tags=%7B%7D&highlight=0000ff&edit=_blank&layers=1&nav=1&title=Untitled+Diagram.
На чому зображені дві діаграми зображуючі структуру даних мережі, і синтаксичну модель, співвідношення між даними та сервером (Server-Data Relationship), і інші концепції. Обидві діаграми можна переглянути за посиланням вище.
Перекладено з: proto, prototype, [[Prototype]], Prototype Chain
Примітки:
Що таке ланцюг прототипів (prototype chain) в javascript?
Ланцюг прототипів (prototype chain) в JavaScript - це механізм, за допомогою якого об'єкти в JavaScript успадковують властивості та методи від інших об'єктів. Кожен об'єкт має внутрішню властивість [[Prototype]], яка є посиланням на інший об'єкт. Коли спроба отримати доступ до властивості, яка не існує в поточному об'єкті, JavaScript автоматично шукає цю властивість в об'єкті [[Prototype]]. Цей процес продовжується до тих пір, поки JavaScript не знайде властивість або не досягне кінця ланцюга прототипів (як правило, це об'єкт Object.prototype), після чого повертає undefined. Ось простий приклад ланцюга прототипів в JavaScript:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return "Hello, I'm " + this.name;
}
function Employee(name, job) {
Person.call(this, name);
this.job = job;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.sayHello = function() {
return Person.prototype.sayHello.call(this) + ", and I'm a " + this.job;
}
var employee = new Employee("John", "developer");
console.log(employee.sayHello()); // "Hello, I'm John, and I'm a developer"
У цьому прикладі, Employee
успадковує властивості та методи від Person
через ланцюг прототипів. Коли викликається метод sayHello
на об'єкті employee
, JavaScript спочатку шукає цей метод в об'єкті employee
. Не знайшовши його там, він переходить до прототипу employee
, який є об'єктом Employee.prototype
, і знаходить метод там.
Що таке прототип об'єкта JS?
Прототип об'єкта в JavaScript - це об'єкт, який використовується для успадкування властивостей та методів іншими об'єктами. Кожен об'єкт в JavaScript має внутрішню властивість [[Prototype]], яка є посиланням на інший об'єкт. Цей інший об'єкт називається прототипом об'єкта. Коли спроба отримати доступ до властивості, яка не існує в поточному об'єкті, JavaScript автоматично шукає цю властивість в прототипі об'єкта. Цей процес продовжується до тих пір, поки JavaScript не знайде властивість або не досягне кінця ланцюга прототипів (як правило, це об'єкт Object.prototype), після чого повертає undefined. Ось простий приклад прототипу об'єкта в JavaScript:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return "Hello, I'm " + this.name;
}
var person = new Person("John");
console.log(person.sayHello()); // "Hello, I'm John"
У цьому прикладі, Person.prototype
є прототипом об'єкта Person
, і він успадковується об'єктом person
. Коли викликається метод sayHello
на об'єкті person
, JavaScript спочатку шукає цей метод в об'єкті person
. Якщо він не знайдений, він шукає його в прототипі об'єкта Person
, і викликає його, якщо він знайдений.
Що таке конструктор JS?
Конструктор в JavaScript - це функція, яка використовується для створення нових об'єктів. Конструктори в JavaScript використовуються для створення нових об'єктів з однаковою структурою та методами. Конструктори в JavaScript можуть бути викликані за допомогою ключового слова new
, яке створює новий об'єкт на основі конструктора. Ось приклад конструктора в JavaScript:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return "Hello, I'm " + this.name;
}
var person = new Person("John");
console.log(person.sayHello()); // "Hello, I'm John"
У цьому прикладі, Person
є конструктором, який створює нові об'єкти з властивістю name
та методом sayHello
. Коли викликається конструктор Person
за допомогою ключового слова new
, створюється новий об'єкт person
з властивістю name
та методом sayHello
.
Prototype в JS
Прототип в JavaScript - це об'єкт, який використовується для успадкування властивостей та методів іншими об'єктами. Кожен об'єкт в JavaScript має внутрішню властивість [[Prototype]], яка є посиланням на інший об'єкт. Цей інший об'єкт називається прототипом об'єкта. Коли спроба отримати доступ до властивості, яка не існує в поточному об'єкті, JavaScript автоматично шукає цю властивість в прототипі об'єкта. Цей процес продовжується до тих пір, поки JavaScript не знайде властивість або не досягне кінця ланцюга прототипів (як правило, це об'єкт Object.prototype), після чого повертає undefined. Ось простий приклад прототипу об'єкта в JavaScript:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return "Hello, I'm " + this.name;
}
var person = new Person("John");
console.log(person.sayHello()); // "Hello, I'm John"
У цьому прикладі, Person.prototype
є прототипом об'єкта Person
, і він успадковується об'єктом person
. Коли викликається метод sayHello
на об'єкті person
, JavaScript спочатку шукає цей метод в об'єкті person
. Якщо він не знайдений, він шукає його в прототипі об'єкта Person
, і викликає його, якщо він знайдений.
String prototype в js
String.prototype в JavaScript - це об'єкт, який містить методи для роботи з рядками. Кожен рядок в JavaScript є об'єктом типу String, який успадковує методи з String.prototype. String.prototype містить методи для роботи з рядками, такі як charAt
, charCodeAt
, concat
, indexOf
, lastIndexOf
, match
, replace
, search
, slice
, split
, substr
, substring
, toLowerCase
, toUpperCase
, trim
та багато інших. Ось приклад використання методів String.prototype в JavaScript:
var str = "Hello, World!";
console.log(str.charAt(0)); // "H"
console.log(str.indexOf("World")); // 7
console.log(str.toUpperCase()); // "HELLO, WORLD!"
У цьому прикладі, str
є рядком, який успадковує методи з String.prototype. Коли викликаються методи charAt
, indexOf
та toUpperCase
на рядку str
, JavaScript використовує методи з String.prototype для виконання відповідних операцій.
Наслідування в JS
Наслідування в JavaScript - це механізм, за допомогою якого об'єкти успадковують властивості та методи від інших об'єктів. Кожен об'єкт в JavaScript має внутрішню властивість [[Prototype]], яка є посиланням на інший об'єкт. Коли спроба отримати доступ до властивості, яка не існує в поточному об'єкті, JavaScript автоматично шукає цю властивість в прототипі об'єкта. Цей процес продовжується до тих пір, поки JavaScript не знайде властивість або не досягне кінця ланцюга прототипів (як правило, це об'єкт Object.prototype), після чого повертає undefined. Ось простий приклад наслідування в JavaScript:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return "Hello, I'm " + this.name;
}
function Employee(name, job) {
Person.call(this, name);
this.job = job;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.sayHello = function() {
return Person.prototype.sayHello.call(this) + ", and I'm a " + this.job;
}
var employee = new Employee("John", "developer");
console.log(employee.sayHello()); // "Hello, I'm John, and I'm a developer"
У цьому прикладі, Employee
успадковує властивості та методи від Person
через ланцюг прототипів. Коли викликається метод sayHello
на об'єкті employee
, JavaScript спочатку шукає цей метод в об'єкті employee
. Не знайшовши його там, він переходить до прототипу employee
, який є об'єктом Employee.prototype
, і знаходить метод там.
Що таке this в JS
Ключове слово this
в JavaScript вказує на поточний об'єкт, в якому викликається функція. Значення this
залежить від контексту виклику функції. Якщо функція викликається як метод об'єкта, this
вказує на цей об'єкт. Якщо функція викликається як функція, this
вказує на глобальний об'єкт (наприклад, window
в браузері). Якщо функція викликається за допомогою call
, apply
або bind
, this
вказує на об'єкт, який передається як перший аргумент цих методів. Ось приклади використання this
в JavaScript:
var person = {
name: "John",
sayHello: function() {
return "Hello, I'm " + this.name;
}
};
console.log(person.sayHello()); // "Hello, I'm John"
function greet() {
return "Hello, I'm " + this.name;
}
var person = {
name: "John"
};
console.log(greet.call(person)); // "Hello, I'm John"
У першому прикладі, this
вказує на об'єкт person
, оскільки метод sayHello
викликається як метод об'єкта. У другому прикладі, this
вказує на об'єкт, який передається методом call
, тобто об'єкт person
.
Прототипне успадкування в js
Прототипне наслідування в JavaScript - це механізм, за допомогою якого об'єкти успадковують властивості та методи від інших об'єктів. Кожен об'єкт в JavaScript має внутрішню властивість [[Prototype]], яка є посиланням на інший об'єкт. Коли спроба отримати доступ до властивості, яка не існує в поточному об'єкті, JavaScript автоматично шукає цю властивість в прототипі об'єкта. Цей процес продовжується до тих пір, поки JavaScript не знайде властивість або не досягне кінця ланцюга прототипів (як правило, це об'єкт Object.prototype), після чого повертає undefined. Ось простий приклад прототипного наслідування в JavaScript:
function Person(name) {
this.name = name;
}
Person.prototype.sayHello = function() {
return "Hello, I'm " + this.name;
}
function Employee(name, job) {
Person.call(this, name);
this.job = job;
}
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;
Employee.prototype.sayHello = function() {
return Person.prototype.sayHello.call(this) + ", and I'm a " + this.job;
}
var employee = new Employee("John", "developer");
console.log(employee.sayHello()); // "Hello, I'm John, and I'm a developer"
У цьому прикладі, Employee
успадковує властивості та методи від Person
через ланцюг прототипів. Коли викликається метод sayHello
на об'єкті employee
, JavaScript спочатку шукає цей метод в об'єкті employee
. Не знайшовши його там, він переходить до прототипу employee
, який є об'єктом Employee.prototype
, і знаходить метод там.
Типи даних в js
В JavaScript є кілька типів даних, включаючи примітивні типи даних та об'єктові типи даних. Примітивні типи даних включають number
, string
, boolean
, null
, undefined
, symbol
та bigint
. Об'єктові типи даних включають object
, function
, array
, date
, regexp
та інші. Ось приклади використання різних типів даних в JavaScript:
var number = 42;
var string = "Hello, World!";
var boolean = true;
var nullValue = null;
var undefinedValue = undefined;
var symbolValue = Symbol("foo");
var bigintValue = 9007199254740991n;
var object = {
key: "value"
};
function func() {
return "Hello, World!";
}
var array = [1, 2, 3];
var date = new Date();
var regexp = /hello/g;
У цьому прикладі, number
, string
, boolean
, null
, undefined
, symbol
та bigint
є примітивними типами даних, а object
, function
, array
, date
та regexp
є об'єктовими типами даних.
Замикання в JS
Замикання в JavaScript - це механізм, за допомогою якого функція зберігає доступ до змінних з області видимості, в якій вона була створена. Замикання в JavaScript дозволяють створювати функції, які зберігають доступ до змінних, навіть після того, як вони вийшли з області видимості. Ось приклад використання замикань в JavaScript:
function createCounter() {
var count = 0;
return function() {
count++;
return count;
};
}
var counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
У цьому прикладі, функція createCounter
створює замикання, яке зберігає доступ до змінної count
. Кожного разу, коли викликається функція counter
, вона збільшує значення count
на одиницю та повертає його.