Прототипът съществува във всички обекти като вградено свойство. Това свойство помага за споделяне на функции между екземпляри на обекти...

Съдържание

Функционално инстанциране

Функционалното инстанциране означава създаване на обекти с функции. Тези функции се наричат ​​функции конструктор.

// 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.

Благодаря за четенето…

Вижте също