Гоголев Сергей
var student = {
type: 'human',
name: 'Daria',
getName: function () {
console.log(this.name);
},
sleep: function () {
console.log('zzZZZ ...');
}
}
student.getName();
// Daria
var lecturer = {
type: 'human',
name: 'Sergey',
getName: function () {
console.log(this.name);
}
talk: function () {}
}
var student = { type: 'human', name: 'Daria', getName: function() {}, sleep: function() {} }
var lecturer = { type: 'human', name: 'Sergey', getName: function() {} talk: function() {} }
Проблема: дублирование кода
Решение: выделить общие части
var person = {
type: 'human',
name: '?',
getName: function () {}
}
var student = {
name: 'Daria',
sleep: function () {}
}
var lecturer = {
name: 'Sergey',
talk: function () {}
}
var person = {
type: 'human',
getName: function () {}
}
Задача: научить student пользоваться общим кодом, который вынесли в person
person.getName.call(student);
// Daria
student.getName();
// Daria
Как мы можем связать объекты student и person, чтобы это было возможным?
var student = {
name: 'Daria',
sleep: function () {}
}
var student = {
name: 'Daria',
sleep: function () {},
[[Prototype]]: <ссылка на объект>
}
Мы можем связать два объекта, записав в [[Prototype]] одного объекта student ссылку на другой person
student['[[Prototype]]'] = person;
// Так не работает
student.__proto__ = person;
var student = {
name: 'Daria',
sleep: function () {},
[[Prototype]]: <ссылка на person>
}
var student = {
name: 'Daria',
sleep: function () {},
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
Объект, на который указывает ссылка [[Prototype]], называется прототипом.
«person послужил прототипом для student»
var student = {
name: 'Daria',
sleep: function () {},
[[Prototype]]: <person>
}
console.log(student.name); // Поле есть в объекте
// Daria
console.log(student.type); // Поля нет в объекте
// ???
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
Если поля у объекта нет, то интерпретатор будет искать его в прототипе
console.log(student.type);
// human
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {
console.log(this.name);
}
}
student.getName(); // Метод, которого нет у объекта
// Daria
this при этом будет ссылаться на student
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var lecturer = {
name: 'Sergey',
[[Prototype]]: <person>
}
var person = {
getName: function () {}
}
student.getName();
// Daria
lecturer.getName();
// Sergey
Интепретатор будет идти по цепочке прототипов
в поиске поля или метода, пока не встретит null
в поле [[Prototype]]
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
[[Prototype]]: null //?
}
Null ??? Не совсем так!
var person = {
type: 'human',
getName: function () {},
[[Prototype]]: <Object.prototype>
}
Object.prototype = {
toString: function () {
// Сильная магия
}
}
student.toString();
// [object Object]
console.log('Hello, ' + student);
// Hello, [object Object]
// :(
var student = {
name: 'Daria'
toString: function () {
return this.name;
}
}
student.toString();
// Daria
console.log('Hello, ' + student);
// Hello, Daria
// :)
Object.prototype = {
toString: function () {},
valueOf: function () {
// Пытается преобразовать в примитив
}
}
var width = { value: 30, units: 'px' }
width.valueOf();
// {value: 30, units: "px"}
width < 45
// false
var width = {
value: 30,
units: 'px',
valueOf: function () { return this.value; }
}
width.valueOf();
// 30
width < 45
// true
// :)
Object.prototype = {
toString: function () {},
valueOf: function () {},
hasOwnProperty: function () {}
}
hasOwnProperty - определяет, принадлежит ли поле объекту лично (а не его прототипу)
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
student.hasOwnProperty('name');
// true
student.hasOwnProperty('type');
// false
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
Задача перечислить поля объекта student
for (var key in student) console.log(key);
// 'name', 'type', 'getName'
// :(
*Оператор in проверяет наличие свойства не только у объекта, но и в цепочке прототипов
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
for (var key in student)
if (student.hasOwnProperty(key))
console.log(key);
// 'name'
// :/
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
// Получаем массив ключей
var keys = Object.keys(student);
console.log(keys);
// 'name'
// :)
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
[[Prototype]]: <Object.prototype>
}
Object.prototype = {
hasOwnProperty: function () {},
[[Prototype]]: null
}
Таким образом поиск всегда остановится?
var lecturer = { name: 'Sergey'}
var student = { name: 'Daria' }
lecturer.__proto__ = student;
student.__proto__ = lecturer;
console.log(lecturer.abrakadabra);
Uncaught TypeError: Cyclic __proto__ value
Неужели нет способа по удобнее?
student.__proto__ = person;
Цивилизованный способ связывать объекты
var student = {
name: 'Daria',
sleep: function () {}
}
var person = {
type: 'human',
getName: function () {}
}
Object.setPrototypeOf(student, person);
student.getName();
// Daira
var student = {
name: 'Daria',
sleep: function () {}
}
var person = {
type: 'human',
getName: function () {}
}
Object.setPrototypeOf(student, 42);
TypeError: Object prototype may only be an Object or null
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
Object.getPrototypeOf(student) === person;
// true
Object.getPrototypeOf(person) === Object.prototype;
// true
Object.getPrototypeOf(Object.prototype) === null;
// true
var fruits = ['Apple', 'Banana', 'Potato'];
Object.getPrototypeOf(fruits);
// Array.prototype;
Object.getPrototypeOf(Array.prototype)
// Object.prototype;
Array.prototype = {
concat: function () {},
slice: function () {},
splice: function () {},
forEach: function () {},
filter: function () {},
map: function () {},
[[Prototype]]: <Object.prototype>
}
var fruits = ['Apple', 'Banana', 'Potato'];
fruits.slice(1);
// ['Banana', 'Potato']
function kawabanga () {
console.log('Kawabanga!')
}
Object.getPrototypeOf(kawabanga);
// Function.prototype;
Object.getPrototypeOf(kawabanga);
// Function.prototype;
Function.prototype = {
call: function () {},
apply: function () {},
bind: function () {},
[[Prototype]]: <Object.prototype>
}
function kawabanga () {
console.log('Kawabanga!')
}
kawabanga.call(null);
// Kawabanga!
var student = {
name: 'Daria',
sleep: function () {}
}
console.log(student.name);
// Daira
student.name = 'Anna';
console.log(student.name);
// Anna
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
console.log(student.type); // human
student.type = 'pirat';
console.log(student.type); // pirat
console.log(person.type); // ???
student.type = 'pirat';
console.log(person.type); // ???
console.log(person.type); // 'human'
var student = {
name: 'Daria',
type: 'pirat',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
Такой эффект называется
затенением свойств
writable – помечает поле как изменяемое (true, по умолчанию)
setter/getter - переопределение установки/чтения поля
enumerable – помечает поле как перечисляемое (true, по умолчанию)
writable – помечает поле как изменяемое (true, по умолчанию)
setter/getter - переопределение установки/чтения поля
enumerable – помечает поле как перечисляемое (true, по умолчанию)
var student = { name: 'Daria' }
Object.defineProperty(student, 'gender', {
writable: false,
value: 'female',
});
console.log(student.gender); // female
student.gender = 'robot';
console.log(student.gender); // ???
// female
'use strict;'
var student = { name: 'Daria' }
Object.defineProperty(student, 'gender', {
writable: false,
value: 'female'
});
student.gender = 'robot';
TypeError: Cannot assign to read only property 'gender' of object
var student = {
name: 'Daria',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
'use strict;'
Object.defineProperty(person, 'planet', {
writable: false, value: 'Earth'
});
console.log(student.planet); // Earth
student.planet = 'Mars';
TypeError: Cannot assign to read only property 'planet' of object
writable – помечает поле как изменяемое (true, по умолчанию)
setter/getter - переопределение установки/чтения поля
enumerable – помечает поле как перечисляемое (true, по умолчанию)
var student = {
name: 'Daria'
[[Prototype]]: <person>
}
Object.defineProperty(student, 'age', {
set: function(age) { this._age = parseInt(age); },
get: function() { return this._age; }
});
student.age = '20 лет';
console.log(student.age); // 20;
var student = {
[[Prototype]]: <person>
}
var person = {
age: null,
type: 'human'
}
student.age = 20;
var student = {
age: 20,
[[Prototype]]: <person>
}
var person = {
age: null,
type: 'human'
}
Затенение свойства
var student = {
[[Prototype]]: <person>
}
var person = {
type: 'human'
}
Object.defineProperty(person, 'age', {
set: function(age) { this._age = parseInt(age); },
get: function() { return this._age; }
});
student.age = '20 лет';
console.log(student.age); // 20;
student.hasOwnProperty(age); // false;
writable – помечает поле как изменяемое (true, по умолчанию)
setter/getter - переопределение установки/чтения поля
enumerable – помечает поле как перечисляемое (true, по умолчанию)
var student = { name: 'Daria', age: 20 }
for (var key in student) console.log(key);
// name, age
var student = { name: 'Daria' }
Object.defineProperty(student, 'age', {
enumerable: false,
value: '20'
});
for (var key in student) console.log(key);
// name
Object.keys(student);
// name
var student = {
name: 'Daria'
[[Prototype]]: <person>
}
var person = {
type: 'human'
}
Object.defineProperty(person, 'age', {
enumerable: false
});
for (var key in student) console.log(key);
// name, type
Хрюндель
create-after-deadline - решение прислано после первого дедлайна
closed-after-deadline - задача принята уже после второго дедлайна
accepted - задача принята на 1 балл
half-points - задача принята на 1/2 балла
duplicate - решение списано
Всего будет 10 задач
8 баллов – зачёт автоматом
5 баллов – минус задача/теория на зачёте
3 балла – допуск к зачёту
Deadline
17 ноября
02:59:59.999