Прототипът съществува във всички обекти като вградено свойство. Това свойство помага за споделяне на функции между екземпляри на обекти...
Съдържание
- Функционална инстанция
-Функционална инстанция със споделени методи - Инстанция на прототип
- Какво ще кажете за статичните методи?
- Какво представлява ключовата дума ‘this’ и как става наследяването с прототипите? - Псевдокласическа инстанция — „новата“ ключова дума
- Прототипни вериги
- Как да напиша този пример с помощта на модерен Javascript (ES6)? - Пълният пример
Функционално инстанциране
Функционалното инстанциране означава създаване на обекти с функции. Тези функции се наричат функции конструктор.
// Constructor function function Todo(title, description, creationDate){ let todo = {}; todo.title = title; todo.description = description; todo.creationDate = creationDate; todo.archiveLocation = ""; todo.moveToArchive = function (archiveLocation) { console.log(`${this.title} moved to archive.`); this.archiveLocation = archiveLocation; } return todo; // Return created object. } const myTodo = Todo("myTodo-title", "myTodo-description", new Date());
Но горният пример съдържа проблем. Този проблем е прекомерно използване на паметта, защото създаваме нова функция moveToArchive всеки път, когато се създава обект, и не споделяме тази функция между екземплярите на обекта. Решението е…
Функционално създаване със споделени методи
const todoMethods = { moveToArchive(archiveLocation) { console.log(`${this.title} moved to archive.`); this.archiveLocation = archiveLocation; } }; function Todo(title, description, creationDate){ let todo = {}; todo.title = title; todo.description = description; todo.creationDate = creationDate; todo.archiveLocation = ""; // Share the function between instances. todo.moveToArchive = todoMethods.moveToArchive; return todo; } const myTodo = Todo("myTodo-title", "myTodo-description", new Date());
Сега споделяме функцията moveToArchive между екземпляри на обекти, но когато планираме да добавим функция към todoMethods, трябва също да променим функцията на конструктора Todo . С помощта на функцията Object.create можем да копираме имплицитно свойствата на todoMethods.
//... function Todo(title, description, creationDate){ let todo = Object.create(todoMethods); todo.title = title; todo.description = description; todo.creationDate = creationDate; todo.archiveLocation = ""; return todo; } // ...
Сега, когато добавим функция към todoMethodsне трябва да променяме функцията на конструктора Todo.
Прототипна инстанция
В Javascript всеки обект има вградено свойство прототип. Можем да използваме това свойство, вместо да управляваме todoMethods в друг обект.
Функции за масиви като concat, filter и find се наследяват с помощта на свойството prototype. (т.е. Array.prototype.concat, Array.prototype.filter)
function Todo(title, description, creationDate){ // Now we are inheriting functions from prototype let todo = Object.create(Todo.prototype); todo.title = title; todo.description = description; todo.creationDate = creationDate; todo.archiveLocation = ""; return todo; } // Put the function into prototype. Todo.prototype.moveToArchive = function(archiveLocation) { console.log(`${this.title} moved to archive.`); this.archiveLocation = archiveLocation; }; const myTodo = Todo("myTodo-title", "myTodo-description", new Date()); myTodo.moveToArchive();
Какво ще кажете за статичните методи?
Статичните методи се дефинират директно като свойство на обекта, тъй като не изискват екземпляра и не се отменят.
Todo.prototype.moveToArchive = function()... Todo.staticMethod = function()...
Можем да използваме функцията hasOwnProperty. Тази функция връща true, ако свойството съществува в самия обект (не в неговия прототип), в противен случай връща false.
//... const myTodo = Todo("myTodo-title", "myTodo-description", new Date()); console.log(myTodo.hasOwnProperty('description')); // true console.log(myTodo.hasOwnProperty('staticMethod')); // false console.log(myTodo.hasOwnProperty('moveToArchive')); // true -> // Because we are creating the todo with Object.create(Todo.prototype)
Какво представлява ключовата дума „това“ и как се случва наследяването с прототипите?
Когато извикваме свойство на обект, JS проверява дали обектът има собствено свойство (както по-горе). Ако обектът има съответното свойство, оценката завършва, в противен случай JS търси прототипа на обекта. (т.е. родителският обект)
Нека да разгледаме примера от MDN:
const parent = { value: 2, method() { return this.value + 1; }, }; // In this case `this` keyword refers to the 'parent' object. console.log(parent.method()); // 3 const child = { __proto__: parent, // We are setting the object's prototype. }; // In this case `this` keyword refers to the `child` object. // `child` object neither has property `method` and `value` // These are resolved using the child's prototype which is // the `parent` object. console.log(child.method()); // 3 // Now the `child` has own property `value` child.value = 10; // this.value = 10 console.log(child.method()); // 11 // Also we can override the `method` child.method = function () { return this.value + 10; } console.log(child.method()); // 20 console.log(child.__proto__.method()); // 3 // Because now the `this` keyword refers to `child.__proto__`, the // `parent` object. console.log(child.__proto__.method.apply(child)); // 11 // with the `apply` function we are setting // the `this` property to `child`. But the `method` is coming // from the `parent` object. console.log(child.method.apply(parent)); // 12 // the child.method is coming from the `child` which is overridden // at line 28, and we are setting the `this` property to // the `parent` object so the `value` property is equal to 2. // so the result is 12.
Псевдокласическа инстанция — „новата“ ключова дума
С ключовата дума new можем да пропуснем извикването на функцията Object.create, защото ключовата дума new прави това автоматично.
function Todo(title, description, dateCreated) { // Below statement automatically included // when we call new Todo(...) // const this = Object.create(Todo.prototype) this.name = name; this.energy = energy; // Below statement automatically included // when we call new Todo(...) // return this ; } const todo = new Todo("myTodo-title", "myTodo-description", new Date());
Прототипни вериги
Всеки обект има поле прототип, но помислете за това полето прототип само по себе си е обект, така че полето прототип също има прототип собственост. Това продължава като верига, докато един от прототипите стане равен на null. Стойността null прекратява веригата на прототипа.
const o = { a: 1, b: 2, __proto__: { b: 3, c: 4, }, }; // o = {a: 1, b: 2} // o.[[Prototype]] = {b:3, c:4} // o.[[Prototype]].[[Prototype]] = Object.prototype // o.[[Prototype]].[[Prototype]].[[Prototype]] = null | End of the chain console.log(Object.prototype.__proto__); // null
Пълният пример
function Animal(name){ this.name = name; } Animal.prototype.eat = function(){ console.log(`${this.name} is eating.`); } function Lion(name, age) { Animal.call(this, name); // We are calling the base constructor. this.age = age; } Lion.prototype.walk = function() { console.log(`${this.name} is walking`); } Lion.roar = function () { console.log("Static function is called."); } Object.setPrototypeOf(Lion.prototype, Animal.prototype); // Inheritance const animal = new Animal("An Animal"); animal.eat(); // An Animal is eating. const lion = new Lion("The Lion", 8); // The Lion is eating. lion.eat(); lion.walk(); // The Lion is walking // animal.walk(); Error animal.walk is not a function // lion.roar(); Error lion.roar is not a function Lion.roar(); // Static function is called.
Как да напиша този пример с помощта на модерен Javascript (ES6)?
class Animal { constructor(name){ this.name = name; } eat(){ console.log(`${this.name} is eating.`); } }; class Lion extends Animal { constructor(name, age){ super(name); this.age = age; } walk(){ console.log(`${this.name} is walking`); } static roar(){ console.log("Static function is called."); } }; const animal = new Animal("An Animal"); animal.eat(); // An Animal is eating. const lion = new Lion("The Lion", 8); // The Lion is eating. lion.eat(); lion.walk(); // The Lion is walking // animal.walk(); Error animal.walk is not a function // lion.roar(); Error lion.roar is not a function Lion.roar(); // Static function is called.
Благодаря за четенето…
Вижте също
- „Прототипи на обекти“
- Object.getPrototypeOf
- Object.setPrototypeOf
- Прототип на функция — прилагане
- Прототип на функция — повикване
- Прототипи и наследяване в Javascript
- „Разбиране на прототипите и наследяването в Javascript“