Гоголев Сергей
var student = {
name: 'Billy',
type: 'human',
getName: function () {
console.info(this.name);
},
sleep: function () {
console.info('zzZZZ...');
}
};
student.getName();
// Billy
var lecturer = {
name: 'Sergey',
type: 'human',
getName: function () {
console.info(this.name);
}
talk: function () {}
};
var student = {
name: 'Billy',
type: 'human',
getName: function() {},
sleep: function() {}
};
var lecturer = {
name: 'Sergey',
type: 'human',
getName: function() {}
talk: function() {}
};
Проблема: дублирование кода
Решение: выделить общие части
var person = {
type: 'human',
getName: function () {}
};
var student = {
name: 'Billy',
sleep: function () {}
};
var lecturer = {
name: 'Sergey',
talk: function () {}
};
var person = {
type: 'human',
getName: function () {}
};
Задача: научить student пользоваться общим кодом, который вынесли в person
person.getName.call(student);
// Billy
student.getName();
// Billy
Можем ли мы связать объекты student и personтак, чтобы это было возможным?
var student = {
name: 'Billy',
sleep: function () {},
[[Prototype]]: <ссылка на объект>
};
student['[[Prototype]]'] = person; // Так не работает
student.__proto__ = person;
var student = {
name: 'Billy',
sleep: function () {},
[[Prototype]]: <ссылка на person>
};
var student = {
name: 'Billy',
sleep: function () {},
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
Объект, на который указывает ссылка в [[Prototype]], называется прототипом
«person послужил прототипом для student»
var student = {
name: 'Billy',
sleep: function () {},
[[Prototype]]: <person>
};
console.info(student.name); // Поле есть в объекте
// Billy
console.info(student.type); // Поля нет в объекте
// ???
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
Если поля у объекта нет, то интерпретатор будет искать его в прототипе
console.info(student.type);
// human
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {
console.info(this.name);
}
};
student.getName(); // Метод, которого нет у объекта
// Billy
this при этом будет ссылаться на student
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var lecturer = {
name: 'Sergey',
[[Prototype]]: <person>
};
var person = {
getName: function () {}
};
student.getName();
// Billy
lecturer.getName();
// Sergey
Интепретатор будет идти по цепочке прототипов
в поиске поля или метода, пока не встретит null
в поле [[Prototype]]
var student = {
name: 'Billy',
sleep: function () {},
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {},
[[Prototype]]: null //?
};
var person = {
type: 'human',
getName: function () {},
[[Prototype]]: <Object.prototype>
}
«Глобальный прототип для всех объектов»
Cодержит общие методы для всех объектов
Object.prototype = {
toString: function () {}
};
student.toString();
// [object Object]
console.info('Hello, ' + student);
// Hello, [object Object]
// :(
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var person = {
type: 'human',
[[Prototype]]: <Object.prototype>
};
Object.prototype = {
toString: function () {},
[[Prototype]]: null
};
var lecturer = { name: 'Sergey'}
var student = { name: 'Billy' }
lecturer.__proto__ = student;
student.__proto__ = lecturer;
console.info(lecturer.abrakadabra);
Uncaught TypeError: Cyclic __proto__ value
Ещё на строчке «student.__proto__ = lecturer»
var student = Object.create(person)
var student = {
name: 'Billy',
sleep: function () {}
};
var person = {
type: 'human',
getName: function () {}
};
Object.setPrototypeOf(student, person);
student.getName();
// Billy
student.__proto__ = 42; // Неявно проигнорируется
Object.setPrototypeOf(student, 42);
TypeError: Object prototype may only be an Object or null
var student = {
name: 'Billy',
[[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>
}
Cодержит общие методы для всех массивов
function kawabanga () {
console.info('Kawabanga!')
}
Object.getPrototypeOf(kawabanga);
// Function.prototype;
Function.prototype = {
call: function () {},
apply: function () {},
bind: function () {},
[[Prototype]]: <Object.prototype>
}
var student = {
name: 'Billy',
sleep: function () {}
};
student.name = 'Willy';
console.info(student.name);
// Willy
var student = {
name: 'Billy',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
console.info(student.type); // human
student.type = 'robot';
console.info(student.type); // robot
console.info(person.type); // ???
console.info(person.type); // 'human'
var student = {
name: 'Billy',
type: 'robot',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
Такой эффект называется
затенением свойств
Object.prototype = {
toString: function () {}
};
student.toString();
// [object Object]
console.info('Hello, ' + student);
// Hello, [object Object]
// :(
var student = {
name: 'Billy'
toString: function () {
return this.name;
}
};
student.toString();
// Billy
console.info('Hello, ' + student);
// Hello, Billy
// :)
writable – помечает поле как изменяемое
set/get – переопределяет установку/чтение
enumerable – помечает как перечисляемое
var student = { name: 'Billy' };
Object.defineProperty(student, 'gender', {
writable: false,
value: 'male',
});
console.info(student.gender); // male
student.gender = 'robot';
console.info(student.gender); // male
Неявное поведение!
'use strict';
var student = { name: 'Billy' };
Object.defineProperty(student, 'gender', {
writable: false,
value: 'male'
});
student.gender = 'robot';
TypeError: Cannot assign to read only property 'gender' of object
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
Object.defineProperty(person, 'planet', {
writable: false,
value: 'Earth'
});
console.info(student.planet); // Earth
student.planet = 'Mars';
TypeError: Cannot assign to read only property 'planet' of object
writable – помечает поле как изменяемое
set/get – переопределяет установку/чтение
enumerable – помечает как перечисляемое
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
Object.defineProperty(student, 'age', {
set: function(age) { this._age = parseInt(age); },
get: function() { return this._age; }
});
student.age = '20 лет';
console.info(student.age); // 20;
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.info(student.age); // 20;
student.hasOwnProperty(age); // false;
Затенение не работает
writable – помечает поле как изменяемое
set/get – переопределяет установку/чтение
enumerable – помечает как перечисляемое
var student = { name: 'Billy', age: 20 }
for (var key in student) console.info(key);
// name, age
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
for (var key in student) console.info(key);
// 'name', 'type', 'getName'
*Оператор in проверяет наличие свойства не только у объекта,
но и в цепочке прототипов
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
for (var key in student)
if (student.hasOwnProperty(key))
console.info(key);
// 'name'
var student = {
name: 'Billy',
[[Prototype]]: <person>
}
var person = {
type: 'human',
getName: function () {}
}
var keys = Object.keys(student); // Получаем массив ключей
console.info(keys);
// ['name']
var student = { name: 'Billy' };
Object.defineProperty(student, 'age', {
enumerable: false,
value: '20'
});
for (var key in student) console.info(key);
// 'name'
Object.keys(student);
// ['name']
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var person = {
type: 'human'
};
Object.defineProperty(person, 'age', {
enumerable: false
});
for (var key in student) console.info(key);
// 'name', 'type'
Object.prototype = {
toString: function () {},
[[Prototype]]: null
};
var person = {
type: 'human',
[[Prototype]]: <Object.prototype>
};
for (var key in person) console.info(key);
// 'type'
Методы глобальных прототипов не перечисляемы по умолчанию