JS

inheritance

Agenda

  • Inheritance
  • Polymorphism

Inheritance

Является способом повторного использования кода существующих объектов или для определения подтипа существующего объекта или того и другого, в зависимости от поддержки языка программирования.

Prototype

Это obj от которого наследуют свойства другие obj. 

По умолчанию у каждого obj есть свой прототип.

Prototype

Прототип работает как резервное хранилище свойств. Если свойства нет у объекта - оно ищется в его прототипе. Получается наследование.

Prototype chain

var obj = {
  name: 'Arni'
};

Наследование реализуется через скрытую ссылку __proto__

получили прототип нашего obj

конечная точка -> прототип прототипа null

Prototype

  • Ссылка на прототип создается оператором new во время создания объекта.
  • Ее значением становится свойство prototype функции-конструктора. Значение prototype указывает, от кого будут наследовать новые объекты
  • Прототип работает как резервное хранилище свойств. Если свойства нет у объекта - оно ищется в его прототипе. Получается наследование.

 

Prototype

  • Использовать ссылку __proto__ нельзя, вместо нее нужно использовать свойство prototype.
  • Свойство prototype нужно для того что бы указать откуда брать прототип.

Function Constructor

// Function constructor
var Person = function() {
    this.name = 'Arni';
};

var person = new Person();

console.log(person.name);

Inheritance

var Person = function() {
    this.name = 'Arni';
};

var person = new Person();

console.log(person.name);

var personInfo = {
    name: 'Vik',
    getName: function() {
        return this.name;
    }
};

Person.prototype = personInfo;

var person2 = new Person();

console.log('person2', person2);

prototype

var Person = function() {
    this.name = 'Arni';
};

var person = new Person();

console.log(person.name);

var personInfo = {
    name: 'Vik',
    getName: function() {
        return this.name;
    }
};

Person.prototype = personInfo;

var person2 = new Person();

console.log('person2', person2);

В person нового obj не будет так как добавляем в прототип после оператора new. Новый обьект будет в прототипе person2.

Inheritance

var NewPerson = function() {
    this.name = 'Arni';
};

var PersonInfo2 = function() {
    this.name = 'Team';
    this.getName = function() {
        return this.name;
    }
};

NewPerson.prototype = new PersonInfo2();

var newPerson = new NewPerson();

console.log('newPerson', newPerson);
console.log('newPerson.getName()', 
newPerson.getName());

Inheritance

var animal = {
    canRun: true
};

// создадим Волка
var Wolf = function() {
    this.name = 'wolf';
};

// создадим еще одного Волка
var GreyWolf = function() {
    this.color = 'grey';
};

var BlackWolf = function() {
    this.color = 'black';
};

// наследуем от animal
Wolf.prototype = animal;

var wolf = new Wolf();

GreyWolf.prototype = wolf;
BlackWolf.prototype = wolf;

var wolfyGrey = new GreyWolf();
var blackGrey = new BlackWolf ();
console.log(wolf);
console.log(wolfyGrey);
console.log(blackGrey);

Detect property source

hasOwnProperty

wolfyGrey.hasOwnProperty('color'); // true
wolfyGrey.hasOwnProperty('name'); // false

Prototype methods and properties are captured by for..in loop, so if you don't need them - use hasOwnProperty.

for (var key in wolfyGrey) {
    console.log(key + ' = ' + wolfyGrey[key]); // we see all properties
}

for (var key in wolfyGrey) {
    if (wolfyGrey.hasOwnProperty(key)) {
        console.log(key + ' = ' + wolfyGrey[key]); // show only own props
    }
}

Detect property source

instanceof

// проверка свойств от которого obj были созданы
console.log(wolfyGrey instanceof GreyWolf);  // true
console.log(wolfyGrey instanceof Person);    // false

Constructor

Constructor ссылается на ту функцию от которой obj был создан

var TestFunct = function() {
    this.testProp = 'test prop';
};

console.log(TestFunct.prototype);
console.log(TestFunct.prototype.constructor === TestFunct);

Не рекомендуется использовать данное свойство

Constructor

var TestFunct = function() {
    this.testProp = 'test prop';
};

var testObj = {
    constructor: 'new constructor'
};

TestFunct.prototype = testObj;

console.log(TestFunct.prototype);
console.log(TestFunct.prototype.constructor === TestFunct); 
// false

Пример того почему лучше не использовать свойство constructor

Inheritance

Object.create()

// for new IE

var wolf2 = {
    canRun: true
};

var dog = Object.create(wolf2);

console.log('dog canRun: ', dog.canRun);
function inherit(proto) {
    // создаем временный конструктор, который возвращает пустой obj,
    // в качесте прототипа устанавливаем тот прототип который передали

    function F() {} // для того что бы вернуть пустой обьект, когда вызовем через new

    F.prototype = proto;

    return new F();
}

var dog2 = inherit(wolf2);

console.log('dog2 canRun: ', dog2.canRun);

Polyfill

Defining an object template

// Function constructor
function Person(firstName, lastName, age, gender, interests) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
    this.gender = gender;
    this.interests = interests;
};

// adding methods
Person.prototype.bio = function() {
    return this.firstName + ' ' + this.lastName + 'is ' + this.age + ' years old. They like ' + this.interests;
}

Person.prototype.greeting = function() {
    return 'Hi I am ' + this.firstName + ' ' + this.lastName;
}

Creating actual objects

// creat person
var person = new Person('Arni', 'Sv', 31, 
                        'male', 'actor')
var person2 = new Person('David', 'Sv', 30, 
                        'male', 'sport')

// проверим принадлежность к классу Person
console.log(person instanceof Person)  
// => true

// call methods
console.log(person.bio());
console.log(person2.bio());

Specialist classes

В этом случае нам не нужны общие люди - мы хотим учителей и студентов, которые являются более конкретными типами людей. В ООП мы можем создавать новые классы на основе других классов - эти новые дочерние классы могут быть сделаны для наследования функций данных и кода их родительского класса, поэтому вы можете повторно использовать функциональные возможности, общие для всех типов объектов, а не дублировать их. Если функциональность отличается между классами, вы можете определить специализированные функции непосредственно для определенного obj по мере необходимости

Polymorphism

Возможность объектов с одинаковой спецификацией иметь различную реализацию.

 

Язык программирования поддерживает полиморфизм, если классы с одинаковой спецификацией могут иметь различную реализацию — например, реализация класса может быть изменена в процессе наследования.

 

Кратко смысл полиморфизма можно выразить фразой: «Один интерфейс, множество реализаций».

Specialist classes

Specialist classes

function Teacher(firstName, lastName, age, gender, interests, subject) {
    Person.call(this, firstName, lastName, age, gender, interests); 
    // отнаследовать
    
    // в данном подходе есть нюанс
    // Наследник не имеет доступа к приватным свойствам родителя. 
    // (денлаем их через this._variable)

    this.subject = subject;
}

// Если в Person через prototype были добавлены методы то их не отнаследует так как 
// через call прототип не наследуется
Teacher.prototype = Object.create(Person.prototype);
Teacher.prototype.constructor = Teacher;

Teacher.prototype.greeting = function() {
  return 'Hello my name is ' + this.firstName + ' ' + this.lastName + 
        'and I teach ' + this.subject;
};

var teacher = new Teacher('Arni', 'Sv', 30, 'male', 'actor', 'programmer');

console.log(teacher);

Teacher

Specialist classes

function Student(firstName, lastName, age, gender, interests) {
    Person.apply(this, arguments); // отнаследовать
    // или Person.apply(this, [firstName, lastName, age, gender, interests]);
}

Student.prototype = Object.create(Person.prototype);
Student.prototype.constructor = Student;

Student.prototype.greeting = function() {
    return 'Yo! I\'m ' + this.firstName + ' ' + this.lastName;
};

var student = new Student('Arni', 'Sv', 20, 'male', 'programming');

console.log(student);

Student

Specialist classes

Specialist classes

class Person {
    constructor(firstName, lastName, age, gender, interests) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
        this.interests = interests;
    }
    
    greeting() {
    	console.log('Hello');
    }
};

class Student extends Person {
    greeting() {
    	console.log(`Hello, I am ${this.firstName}`);
    }
}

let student = new Student('Vic', 'D', 23, 'm', 'sport')

super

class Person {
    constructor(firstName, lastName, age, gender, interests) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
        this.gender = gender;
        this.interests = interests;
    }
    
    greeting() {
    	console.log('Hello');
    }
};

class Student extends Person {
    constructor(firstName, lastName, age, gender, interests, className) {
    	super(firstName, lastName, age, gender, interests);
        
    	this.className = className;
    }
    
    greeting() {
    	console.log(`Hello, I am ${this.firstName}`);
    }
}

let student = new Student('Vic', 'D', 23, 'm', 'sport', '5')

Links

Examples

Inheritance in JS

By Oleg Rovenskyi

Inheritance in JS

  • 772