Добро пожаловать в часть 10 серии и первую часть вопросов по объектно-ориентированному JavaScript. Вы можете найти часть-9 здесь.
В этой части мы будем изучать объектно-ориентированный JavaScript по-старому, что немного сложнее из-за его синтаксиса. Последние классы ES6 — это не что иное, как синтетический сахар, который использует эти концепции только под капотом. Но это одна из важных тем на собеседованиях, где спрашивают о знаниях ООП.
Вопрос 60- Что такое функции-конструкторы в JavaScript?
Ответ-Функции-конструкторы — это специальные функции, используемые для создания его экземпляра. Это JavaScript-эквивалент классов в других языках программирования, таких как C++ и Java.
Давайте начнем с создания простой функции, использующей object для создания объектов сотрудников.
function createEmpObj(fName, lName, gender, desig) { var newObj = {}; newObj.firstName = fName; newObj.lastName = lName; newObj.gender = gender; newObj.designation = desig; return newObj; } var emp1 = createEmpObj("Parag", "Khandar", "M", "Project Manager");
Теперь рассмотрим строку var newObj = {}; и return newObj; Они будут одинаковыми в каждой функции, которую мы создадим. Итак, JS предоставил нам особый тип функции, известной как функция-конструктор, для их создания.
Мы рефакторим приведенное выше для использования функции-конструктора. Посмотрите на приведенный ниже код.
function CreateEmpObj(fName, lName, gender, desig) { //var this; this.firstName = fName; this.lastName = lName; this.gender = gender; this.designation = desig; //return this; } var emp2 = new CreateEmpObj("Shikha", "Biswas", "F", "Developer");
Мы добавляем ключевое слово new для создания объекта. В основном он заботится о создании и возврате newObj. Но дает этому новое имя this.
Обратите внимание, что нам не нужно помещать эти две строки в наш код и автоматически помещать их движком JS.
Вопрос 61. Как сделать переменные закрытыми в функциях конструктора в JavaScript?
Ответ. Давайте сначала рассмотрим приведенный ниже код для обычного Функция конструктора. Здесь мы можем получить прямой доступ к переменной «color» с помощью redCar.color. Теперь это может быть нежелательно во многих местах и в традиционных языках, что решается наличием «частных» переменных в классе, а затем наличием «геттеров» и «сеттеров» для доступа к ним.
let Car = function(color) { this.color = color; }; let redCar = new Car('red'); console.log(redCar.color); //red
Теперь мы реализуем то же самое в JavaScript, используя Closures. У нас есть две функции замыкания setColor и getColor, которые в основном являются «сеттерами» и «геттерами». Теперь переменная _color является закрытой и не может быть доступна вне функции с помощью blueCar._color, и мы можем получить к ней доступ только с помощью blueCar.getColor()
let PrivateCar = function(_color) { this.setColor = function(color) { _color = color; }; this.getColor = function() { return _color; } } let blueCar = new PrivateCar(); blueCar.setColor('blue'); console.log(blueCar._color); //undefined console.log(blueCar.getColor()); //blue
Вы можете найти JSFiddle для вышеуказанного здесь.
Вопрос 62- Что такое прототипы и как мы их используем в JavaScript?
Ответ-В JavaScript, как вы знаете, все является Объект. Поэтому всякий раз, когда мы создаем функцию, создается один объект. но на самом деле создается еще один объект, известный как объект-прототип.
Теперь для доступа к объекту Prototype у нас есть ссылка на объект функции, также известный как прототип.
Когда мы создаем экземпляр функции с новым ключевым словом, происходят интересные вещи. Он создает что-то известное как __proto__. Это создается движком JavaScript для каждого вызова функции с использованием нового ключевого слова.
Теперь давайте посмотрим, как создать функцию с использованием прототипа и какие преимущества это дает. В приведенном ниже коде есть две функции haveFun
и drinkCoffee
. Функция haveFun
— это обычная функция внутри функции конструктора. Функция drinkCoffee
создается снаружи и добавляется к объекту-прототипу с использованием его эталонного прототипа.
function Employee(name) { this.name = name; this.haveFun = function() { console.log('Play badminton'); }; } Employee.prototype.drinkCoffee = function() { console.log('coffee break') } let emp1 = new Employee('Nabendu'); let emp2 = new Employee('Shikha'); console.log(emp1.haveFun()); //Play badminton console.log(emp1.drinkCoffee()); //coffee break
Обе функции, кажется, делают одно и то же, тогда какая польза. Преимущество объявления функции с использованием прототипа заключается в том, что она создается один раз в объекте Prototype. Итак, теперь всякий раз, когда мы создаем новый экземпляр функции Constructor, функция больше не создается. Как на снимке экрана ниже, вы можете видеть, что emp1 и emp2 оба имеют name и haveFun. Но drinkCoffee находится внутри __proto__, который является ссылкой на объект Prototype.
Подробнее об объектах и прототипах читайте в моем посте здесь.
Вопрос 63- Объясните Object.create() в JavaScript?
Ответ-Каждый объект создается из глобального Object в JavaScript. Если мы посмотрим на это в консоли, у него много свойств, и создание было одним из них.
Метод Object.create() создает новый объект, используя существующий объект в качестве прототипа вновь созданного объекта.
Рассмотрим приведенный ниже пример, где мы можем создать новый объект из существующего объекта, а также добавить к нему новые свойства или изменить существующее свойство.
const person = { isCoder: false, printIntroduction: function () { console.log(`My name is ${this.name}. Am I coder? ${this.isCoder}`); } }; const me = Object.create(person); me.name = "Nabendu"; me.isCoder = true; me.printIntroduction(); // Output: "My name is Nabendu. Am I coder? true"
Теперь давайте посмотрим на практическое использование Object.create в Наследовании. В приведенном ниже примере у нас есть функция Employee, в прототипе которой есть две функции. Затем у нас есть еще одна функция SalesEmployee, и мы устанавливаем ее прототип на прототип сотрудника.
SalesEmployee.prototype = Object.create(Employee.prototype);
const Employee = function() { } Employee.prototype = { setName(_name) { this.name = _name }, getName() { return this.name; } } const SalesEmployee = function () { } SalesEmployee.prototype = Object.create(Employee.prototype); let emp1 = new SalesEmployee(); console.dir(emp1); console.log(emp1 instanceof SalesEmployee); //true console.log(emp1 instanceof Employee); //true console.log(emp1 instanceof Object); //true emp1.setName('Shikha'); console.log(emp1.getName()); //Shikha
Затем мы создаем экземпляр SalesEmployee как переменную emp1. Он имеет все функции функции Employee и также может ее использовать.
Вопрос 64- Объясните цепочку прототипов в JavaScript с помощью Object.create() ?
Ответ-Цепочка прототипов может быть объяснена с помощью приведенного ниже примера . Здесь у нас есть три функции Car, ToyCar и ToyTransformer. У каждого есть своя версия print().
Мы наследуем от Car к ToyCar, устанавливая прототип ToyCar в качестве прототипа Car, а затем наследуем от ToyCar к ToyTransformer, устанавливая прототип ToyTransformer в качестве прототипа ToyCar.
Затем у нас есть три экземпляра Car, ToyCar и ToyTransformer. При вызове print() мы получаем соответствующий журнал консоли.
// Car constructor const Car = function() {}; // Set Car's prototype Car.prototype = { print() { return 'This is a Car'; } }; // ToyCar constructor const ToyCar = function() {}; // Set ToyCar's prototype to be Car's prototype ToyCar.prototype = Object.create(Car.prototype); // Adding ToyCar's own print method ToyCar.prototype.print = function(){ return 'This is a ToyCar'; } //ToyTransformer constructor const ToyTransformer = function() {}; // Set ToyTransformer's prototype to be ToyCar's prototype ToyTransformer.prototype = Object.create(ToyCar.prototype); // Adding ToyCar's own print method ToyTransformer.prototype.print = function(){ return 'This is a ToyTransformer'; }; const toyota = new Car(); const legoCar = new ToyCar(); const bumbleBee = new ToyTransformer(); console.log(toyota.print()); //This is a Car console.log(legoCar.print()); //This is a ToyCar console.log(bumbleBee.print()); //This is a ToyTransformer
Теперь давайте удалим метод print() ToyTransformer, а затем, если мы вызовем print() для его экземпляра bumbleBee, мы получим результат от print() ToyCar.
// Car constructor const Car = function() {}; // Set Car's prototype Car.prototype = { print() { return 'This is a Car'; } }; // ToyCar constructor const ToyCar = function() {}; // Set ToyCar's prototype to be Car's prototype ToyCar.prototype = Object.create(Car.prototype); // Adding ToyCar's own print method ToyCar.prototype.print = function(){ return 'This is a ToyCar'; } const ToyTransformer = function() {}; // Set ToyCar's prototype to be Car's prototype ToyTransformer.prototype = Object.create(ToyCar.prototype); const bumbleBee = new ToyTransformer(); console.log(bumbleBee.print()); //This is a ToyCar
Если мы далее удалим метод print() ToyCar, а затем вызовем print() для его экземпляра bumbleBee, мы получим результат от print() Car.
// Car constructor const Car = function() {}; // Set Car's prototype Car.prototype = { print() { return 'This is a Car'; } }; // ToyCar constructor const ToyCar = function() {}; // Set ToyCar's prototype to be Car's prototype ToyCar.prototype = Object.create(Car.prototype); const ToyTransformer = function() {}; // Set ToyCar's prototype to be Car's prototype ToyTransformer.prototype = Object.create(ToyCar.prototype); const bumbleBee = new ToyTransformer(); console.log(bumbleBee.print()); //This is a Car
Итак, если вы вызываете метод для дочернего элемента, а этого метода там нет, он проверит свой родитель, а если нет, то проверит родителя родителя.
Вопрос 65- Объясните, как наследование работает в функциях-конструкторах ?
Ответ-Чтобы понять наследование с помощью функции-конструктора, мы рассмотрим пример содержащий функцию Mammal
parent и функцию Bat
child. Кроме того, сделайте прототип летучей мыши ссылкой на прототип млекопитающего, используя Object.create
. Bat’s Prototype будет иметь все методы Mammal’s Prototype.
let Mammal = function(legs) { this.legs = legs; }; Mammal.prototype = { walk() { return 'walking!'; }, sleep() { return 'sleeping'; } }; let Bat = function(legs, isVegetarian) { Mammal.call(this, legs); this.isVegetarian = isVegetarian; } Bat.prototype = Object.create(Mammal.prototype);
Теперь давайте посмотрим на «Bat» в консоли. Как видите, он содержит функцию сна и ходьбы «Млекопитающих» в своем __proto__.
Но у нас есть серьезная проблема, заключающаяся в том, что оператор «Bat.prototype = Object.create(Mammal.prototype);» стирает любую функцию прототипа летучей мыши, а также ее конструктор.
Мы не объявляли никаких функций Bat’s Prototype, но конструктор был стерт.
Итак, мы решаем это с помощью приведенного ниже кода. Он использует Bat.prototype.constructor = Bat; чтобы снова установить конструктор в «Bat».
Кроме того, мы объявляем функцию Bat’s Prototype после «Bat.prototype = Object.create(Mammal.prototype);».
... ... Bat.prototype = Object.create(Mammal.prototype); Bat.prototype.constructor = Bat; Bat.prototype.fly = function() { return 'Flying!'; } console.dir(Bat);
Давайте теперь завершим код и создадим два экземпляра «Bat» как fruitBat и bugBat. Оба могут получить доступ к функциям ходьбы, сна и полета.
let Mammal = function(legs) { this.legs = legs; }; Mammal.prototype = { walk() { return 'walking!'; }, sleep() { return 'sleeping'; } }; let Bat = function(legs, isVegetarian) { Mammal.call(this, legs); this.isVegetarian = isVegetarian; } Bat.prototype = Object.create(Mammal.prototype); Bat.prototype.constructor = Bat; Bat.prototype.fly = function() { return 'Flying!'; } let fruitBat = new Bat(4, true); let bugBat = new Bat(2, false); console.log(fruitBat.walk()); // walking! console.log(bugBat.sleep()); // sleeping console.log(bugBat.fly()); // Flying!
Вопрос 66- Объясните метод Object.setPrototypeOf()?
Ответ-Метод Object.setPrototypeOf()
был введен в ES6 для верхнего уровня «Объект ».
Этот метод берет метод одного объекта и делает его доступным для другого объекта.
Это также полезно при реализации наследования с использованием литералов объекта вместо функций-конструкторов (см. вопрос 65).
В приведенном ниже коде у нас есть два объекта — млекопитающее и летучая мышь. Затем, чтобы использовать метод млекопитающих в летучих мышах, мы использовали Object.setPrototypeOf(bat, млекопитающее); .
Кроме того, обратите внимание, что мы обновляем функцию walk() внутри "bat", а также вызываем функцию walk млекопитающего с помощью super.walk().
let mammal = { walk() { return 'walking!'; } }; let bat = { fly() { return 'Flying!'; }, walk() { return `${super.walk()} and eating`; } } Object.setPrototypeOf(bat, mammal); console.log(bat.fly()); //Flying! console.log(bat.walk()); //walking! and eating
На этом завершается часть 10 серии и первая часть вопросов по объектно-ориентированному JavaScript. Вы можете найти часть-11 здесь.