Это сводка различных шаблонов в JS Object Creation и выполнения различных действий с этими объектами.
Для каждого из представленных ниже шаблонов мы хотим выполнить следующие функции:
- Создание объекта или функции
- Расширение объекта или функции
- Создание подкласса со свойствами из нескольких объектов или функций
Заводской узор
Создание фабричной функции:
function Dog(name, age) { return { name, age, barks() { console.log(`${this.name} barks!`); } } } let menno = Dog(‘menno’, 12); console.log(menno.name); // menno console.log(menno.age); // 12 menno.barks(); // menno barks!
Расширение функции Dog:
function JackRussell(name, age) { return Object.assign(Dog(name, age), jumps() { console.log(`${this.name} jumps!`) }, }); } let bram = JackRusell(‘bram’, 10); console.log(bram.name); // bram console.log(bram.age); // 10 bram.barks(); // bram barks! bram.jumps(); // bram jumps!
Сочетание свойств Джека Рассела и золотистого ретривера:
function GoldenRetriever(name, age) { return Object.assign(Dog(name, age), { swims() { console.log(`${this.name} swims!`); } }) }
Теперь создаем смесь GoldenRussell со свойствами Retriever и Jackie:
function GoldenRussell(name, age) { return Object.assign(JackRussell(), GoldenRetriever(name, age)); } let bruno = GoldenRussell(‘bruno’, 1); console.log(bruno.name); // bruno console.log(bruno.age); // 1 bruno.barks(); // bruno barks! bruno.jumps(); // bruno jumps! bruno.swims(); // bruno jumps!
Шаблон конструктора
Создание функции-конструктора:
function Dog(name, age) { this.name = name; this.age = age; this.barks = function() { console.log(`${this.name} barks!`); } } let menno = new Dog(‘menno’, 11); let luna = Object.create(menno); menno.name; menno.age; menno.barks();
Альтернативно:
function Dog(name, age) { this.name = name; this.age = age; } Dog.prototype.barks = function() { console.log(`${this.name} barks!`) } function Husky() {} Husky.prototype = new Dog(name, age);
Смешивание шаблона конструктора с OOLO должно привести к тому же результату:
function Dog() {}; Dog.prototype.barks = function() { console.log(‘it barks!’); } let jackie = new Dog(); let menno = Object.create(jackie);
Проверка прототипного наследования:
Dog.isPrototypeOf(jackie); // false Dog.prototype.isPrototypeOf(jackie); // true Dog.prototype.isPrototypeOf(menno); // true jackie.isPrototypeOf(menno); // true // Checking for use of instanceof jackie instanceof Dog; // true menno instanceof Dog; // true menno instanceof jackie; // TypeError
Расширение функции Dog
:
jackie.jumps = function() { console.log(‘it jumps!’) } Dog.prototype.swims = function() { console.log(‘it swims!’) } Object.defineProperties(jackie, { eats: { value: function() { console.log(‘it eats!’); }, writable: true, }, }) jackie.__proto__.sleep = function() { console.log(‘it sleeps!’); } Object.getPrototypeOf(jackie).run = function() { console.log(‘it runs!’); } menno.jumps(); // it jumps! menno.swims(); // it swims! menno.eats(); // it eats! menno.sleep(); // it sleeps! menno.run(); // it runs!
Смешивание другими методами:
function Wolf() { this.hunts = function() { console.log(‘it hunts!’); } } let wolf = new Wolf(); function Husky() { return Object.assign(wolf, Dog.prototype); } let husky = new Husky(); husky;
Давайте воспользуемся наследованием, чтобы разделить методы между различными функциями конструктора.
function Dog(name, age) { this.name = name; this.age = age; this.barks = function() { console.log(‘it barks!’) } } function Husky(name, age) { Dog.call(this, name, age); this.hunts = function() { console.log(‘it hunts!’) } } let lars = new Husky(‘lars’, 8); lars.barks(); // it barks! lars.hunts(); // it hunts! Object.getPrototypeOf(lars) === Husky.prototype; // true Object.getPrototypeOf(lars) === Dog.prototype; // false lars instanceof Husky; // true lars instanceof Dog; // false
Обратите внимание, что после применения Dog.call()
в новой функции Husky
любые новые объекты Husky
теперь имеют доступ к уже существующим объектам в классе Dog
.
Но что, если мы добавим в Dog
еще один метод?
let menno = new Dog(‘menno’, 11); Dog.prototype.swims = function() { console.log(‘it swims!’); } menno.swims(); // it swims! lars.swims(); // TypeError
Исправление должно гарантировать, что Husky
наследуется от прототипа Dog
.
Husky.prototype = Object.create (Dog.prototype); Husky.prototype.constructor = Husky; let lars = new Husky(‘lars’, 8); lars.swims(); // it swims!
Таким образом, причина установки прототипной цепочки заключается в том, чтобы новый объект всегда мог наследовать от функции, а не просто получать доступ к методам, с помощью которых он был первоначально вызван (Dog.call()
).
Шаблон ES6 с использованием класса
class Dog { constructor(name, age) { this.name = name; this.age = age }; barks() { console.log(‘it barks!’); }; } let menno = new Dog(‘menno’, 11); menno.barks(); class Husky extends Dog { hunts() { console.log(‘it hunts!’); } } let lars = new Husky(‘lars’, 8); lars.hunts(); Husky.prototype.isPrototypeOf(lars); Dog.prototype.isPrototypeOf(lars);
Добавляя миксины из нескольких классов, Wolfcat
получает свойства как от Husky
, так и от Cat
.
class Cat { constructor(name, age) { this.name = name; this.age = age; }; purrs() { console.log(this.name + ‘ purrs!’); }; plays() { console.log(this.name + ‘ plays!’); }; }; class Wolfcat extends Husky { constructor(name, age) { super (name, age); } } for (let method of Object.getOwnPropertyNames(Cat.prototype).filter(item => typeof Cat.prototype[item] === ‘function’ && item !== ‘constructor’)) { Wolfcat.prototype[method] = Cat.prototype[method]; } let feline = new Wolfcat(‘feline’, 2); feline.barks(); // it barks! feline.hunts(); // it hunts! feline.purrs(); // it purrs! feline instanceof Husky; // true feline instanceof Wolfcat; // true feline instanceof Cat; // false Dog.prototype.isPrototypeOf(feline); // true Husky.prototype.isPrototypeOf(feline); // true Cat.prototype.isPrototypeOf(feline); // false Object.getPrototypeOf(feline) === Wolfcat.prototype; // true
Шаблон OLOO
let Dog = { init: function(name, age) { this.name = name; this.age = age; return this; }, barks() { console.log(‘it barks!’); } } let luna = Object.create(Dog).init(‘luna’, 8); let Jackie = Object.create(Dog, { jumps: { value: function() { console.log(‘it jumps!’); }, writable: false, enumerable: true, } }); let menno = Object.create(Jackie).init(‘menno’, 11); let Fish = { swims() { console.log(‘it swims!’); } } let Retriever = Object.assign(Object.create(Dog), Jackie, Fish); let lulu = Object.create(Retriever).init(‘lulu’, 7); lulu.swims(); // it swims lulu.jumps(); // it jumps lulu.barks(); // it barks