Гоголев Сергей
var student = {
name: 'Billy',
type: 'human',
getName: function() {},
sleep: function() {}
};
var lecturer = {
name: 'Sergey',
type: 'human',
getName: function() {}
talk: function() {}
};
Проблема: дублирование кода
var student = {
name: 'Billy',
sleep: function () {}
};
var lecturer = {
name: 'Sergey',
talk: function () {}
};
var person = {
type: 'human',
getName: function () {}
};
var student = {
name: 'Billy',
sleep: function () {}
};
var person = {
type: 'human',
getName: function () {}
};
student.getName();
// Billy
var student = {
name: 'Billy',
sleep: function () {}
[[Prototype]]: <ссылка на объект>
};
var student = {
name: 'Billy',
sleep: function () {},
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
student.__proto__ = person;
Object.setPrototypeOf(student, person);
var student = Object.create(person);
student.name = 'Billy';
student.sleep = function () {};
student.getName();
var student = {
name: 'Billy',
[[Prototype]]: <person>
};
var person = {
getName: function () { console.info(this.name); },
[[Prototype]]: <Object.prototype>
};
Object.prototype = {
toString: function () {},
[[Prototype]]: null
};
Object.prototype = {
toString: function () {},
hasOwnProperty: function () {},
[[Prototype]]: null
};
Array.prototype = {
forEach: function () {},
[[Prototype]]: <Object.prototype>
};
Function.prototype = {
call: function () {},
[[Prototype]]: <Object.prototype>
};
var student = {
name: 'Billy',
sleep: function () {},
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
Object.getPrototypeOf(student) === person;
// true
var student = {
name: 'Billy',
sleep: function () {},
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
student.type = 'robot';
var student = {
type: 'robot',
name: 'Billy',
sleep: function () {},
[[Prototype]]: <person>
};
var person = {
type: 'human',
getName: function () {}
};
var student = {
name: 'Billy',
sleep: function () {}
};
var person = {
type: 'human',
getName: function () {}
};
Object.setPrototypeOf(student, person);
var billy = {
name: 'Billy',
sleep: function () {}
};
var willy = {
name: 'Willy',
sleep: function () {}
};
Проблема: дублирование кода
при создании объекта
Решение: использовать
конструктор объектов
function createStudent(name) {
return {
name: name,
sleep: function () {
console.info('zzzZZ ...');
}
};
}
var billy = createStudent('Billy');
var willy = createStudent('Willy');
Проблема: каждый раз создаём метод sleep()
Решение: вынести этот метод в прототип
var studentProto = {
sleep: function () {
console.info('zzzZZ ...');
}
};
function createStudent(name) {
var student = {
name: name
};
Object.setPrototypeOf(student, studentProto);
return student;
}
var billy = createStudent('Billy');
var willy = createStudent('Willy');
billy.sleep();
// zzzZZ ...
willy.sleep();
// zzzZZ ...
Любая функция, вызванная оператором new
var billy = new createStudent('Billy');
function createStudent(name) {
this.name = name;
}
function createStudent(name) {
// var this = {};
this.name = name;
// return this;
}
this указывает на создаваемый объект
function createStudent(name) {
this.name = name;
}
var billy = new createStudent('Billy');
Чуть больше семантики
function student(name) {
this.name = name;
}
var billy = new student('Billy');
Чтобы отличить функцию-конструктор от обычной, их именуют с заглавной буквы.
function Student(name) {
this.name = name;
}
var billy = new Student('Billy');
function Student(name) {
this.name = name;
}
var billy = Student('Billy');
Поле появится в глобальном объекте!
window.name === 'Billy'; // true
use strict;
TypeError: Cannot set property 'name' of undefined
function Student(name) {
this.name = name;
return {
name: 'Muahahahahaha!'
};
}
var billy = new Student('Billy');
console.info(billy.name);
// Muahahahahaha
function Student(name) {
this.name = name;
return null; // Evil mode on!
}
var billy = new Student('Billy');
console.info(billy.name);
// Billy
function Student(name) {
this.name = name;
}
var studentProto = {
sleep: function () {}
}
function createStudent(name) {
var student = { name: name };
Object.setPrototypeOf(student, studentProto);
return student;
}
function Student(name) {
this.name = name;
}
Student.prototype = {
sleep: function () {}
};
function Student(name) {
// var this = {};
this.name = name;
// Object.setPrototypeOf(this, Student.prototype);
// return this;
}
function Student(name) {
this.name = name;
}
Student.prototype = {
sleep: function () {}
};
var billy = new Student('Billy');
var billy = {
name: 'Billy',
[[Prototype]]: <Student.prototype>
};
Прямо как Object.prototype!
billy
⇣
Student.prototype
⇣
Object.prototype
⇣
null
1. Есть у каждой функции
function kawabanga(name) {
console.info('kawabanga!');
}
2. Хранит объект
– неперечисляемое
– хранит ссылку на саму функцию
function Student(name) {
this.name = name;
}
Student.prototype.constructor === Student; // true
var billy = new Student('Billy');
console.info(billy.constructor.name); // ?
// Student
function Student(name) {
this.name = name;
}
Student.prototype = {
sleep: function () {}
};
Проблема: уничтожаем поле .constructor
Решение: не перезаписывать .prototype
function Student(name) {
this.name = name;
}
Student.prototype.sleep = function () {
console.info('zzzZZ ...');
}
var billy = new Student('Billy');
billy.sleep(); // zzzZZ ...
billy.constructor === Student; // true
var billy = {
name: 'Billy',
sleep: function () {}
};
var willy = {
name: 'Willy',
sleep: function () {}
};
Object.setPrototypeOf(billy, person);
Object.setPrototypeOf(willy, person);
var personProto = {
type: 'human',
getName: function () {
console.info(this.name);
}
};
function Person() {
this.type = 'human';
}
Person.prototype.getName = function () {
console.info(this.name);
}
function Student(name) {
this.name = name;
}
Student.prototype = Person.prototype;
Student.prototype.sleep = function () {};
var billy = new Student('Billy');
billy.getName();
// Billy
function Student(name) {
this.name = name;
}
Student.prototype = Person.prototype;
Student.prototype.sleep = function () {};
function Lecturer(name) {
this.name = name;
}
Lecturer.prototype = Person.prototype;
var sergey = new Lecturer('Sergey');
sergey.sleep(); // zzzZZ ...
billy
⇣
Student.prototype === Person.prototype
⇣
Object.prototype
⇣
null
billy
⇣
Student.prototype
⇣
Person.prototype
⇣
Object.prototype
⇣
null
function Student(name) {
this.name = name;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.sleep = function () {};
function Lecturer(name) {
this.name = name;
}
Lecturer.prototype = Object.create(Person.prototype);
var sergey = new Lecturer('Sergey');
sergey.sleep();
TypeError: sergey.sleep is not a function
billy
⇣
Student.prototype
⇣
Person.prototype
⇣
Object.prototype
⇣
null
sergey
⇣
Lecturer.prototype
⇣
Person.prototype
⇣
Object.prototype
⇣
null
Создаёт пустой объект, прототипом которого становится объект, переданный первым аргументом
var fruitProto = {
isUsefull: true
}
var apple = Object.create(fruitProto);
apple.isUsefull; // true
var apple = Object.create(fruitProto);
Object.create = function(prototype) {
// Простейший конструктор пустых объектов
function emptyFunction() {};
emptyFunction.prototype = prototype;
return new emptyFunction();
};
Student.prototype = Object.create(Person.prototype);
Object.create = function(prototype) {
function emptyFunction() {};
emptyFunction.prototype = prototype;
return new emptyFunction();
};
Student.prototype = {
[[Prototype]]: <Person.prototype>
}
var foreverAlone = Object.create(null);
foreverAlone.hasOwnProperty; // undefined
foreverAlone
⇣
null
function Student(name) {
this.name = name;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.sleep = function () {};
Student.prototype
⇣
Person.prototype
function Student(name) {
this.name = name;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.sleep = function () {};
Student.prototype.constructor = Student;
function Person() {
this.type = 'human';
}
Person.prototype.getName = function () {
console.info(this.name);
};
function Student(name) {
this.name = name;
}
Student.prototype = Object.create(Person.prototype);
Student.prototype.sleep = function () {};
Student.prototype.constructor = Student;
var billy = new Student('Billy');
billy
⇣
Student.prototype
⇣
Person.prototype
⇣
Object.prototype
⇣
null
Поле .name
Метод .sleep
Метод .getName
Общие методы
billy instanceof Student;
// true
billy instanceof Person;
// true
billy instanceof Object;
// true
Object.create(null) instanceof Object
// false
billy instanceof Person;
billy.__proto__ === Person.prototype;
// false -> Может, там null?
billy.__proto__ === null;
// false -> Идём дальше по цепочке
billy.__proto__.__proto__ === Person.prototype;
// true -> Возвращаем true
Object.create(null) instanceof Object;
Object.create(null).__proto__ === Object.prototype;
// false -> Может, там null?
Object.create(null).__proto__ === null;
// true -> Так и есть, возращаем false!
Student.prototype.isPrototypeOf(billy);
// true
Person.prototype.isPrototypeOf(billy);
// true
Object.prototype.isPrototypeOf(billy);
// true
function Student(name) {
this.name = name;
}
function Lecturer(name) {
this.name = name;
}
Проблема: дублирование кода
Решение: вынести общий код в Person
function Student(name) {
this.name = name;
}
function Person() {
this.type = 'human';
}
function Student(name) {}
function Person(name) {
this.type = 'human';
this.name = name;
}
function Person(name) {
this.type = 'human';
this.name = name;
}
function Student(name) {}
function Student(name) {
Person.call(this, name);
}
var billy = new Student('Billy');
console.info(billy.name); // undefined
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
Student.prototype.getName = function () {
return 'Student ' + this.getName();
};
var billy = new Student('Billy');
billy.getName();
RangeError: Maximum call stack size exceeded
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
Student.prototype.getStudentName = function () {
return 'Student ' + this.getName();
};
var billy = new Student('Billy');
billy.getStudentName();
function Person(name) {
this.type = 'human';
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
Student.prototype.getName = function () {
return 'Student ' +
Person.prototype.getName.call(this);
};
new , prototype , Object.create
Можно проще!
var personProto = {
getName: function () {
return this.name;
}
};
var studentProto = Object.create(personProto);
studentProto
⇣
personProto
studentProto.sleep = function () {};
var billy = Object.create(studentProto);
billy
⇣
studentProto
⇣
personProto
billy.name = 'Billy';
var personProto = {};
personProto.getName = function () { return this.name; }
var studentProto = Object.create(personProto);
studentProto.sleep = function () {};
var billy = Object.create(studentProto);
billy.name = 'Billy';
var personProto = {};
personProto.getName = function () { return this.name; }
var studentProto = Object.create(personProto);
studentProto.sleep = function () {};
studentProto.create = function (name) {
return Object.create(this, {
name: { value: name }
});
}
var billy = studentProto.create('Billy');
var apple = Object.create(fruit, {
shape: { value: 'round', writable: false },
color: { value: 'Green' },
amount: { writable: true }
});
apple.amount = 'half';
new или Object.create?
function Student(name) {
this.name = name;
}
Student.prototype.getName = function () {
return this.name;
};
class Student {
constructor(name) {
this.name = name;
}
getName() {
return this.name;
}
}
class Student {
// ...
}
var billy = new Student('Billy');
billy.getName(); // Billy
Student.prototype.isPrototypeOf(billy); // true
typeof Student.prototype.getName; // function
typeof Student; // function
class или Object.create?
Common Misconceptions About Inheritance in JavaScript, Eric Elliott
Что почитать?
Objects and Inheritance, Dr. Axel Rauschmayer
Прототипы, Илья Кантор