Вы понимаете, верно. Объекты, созданные с нотацией obj = { ... }
, наследуются от Object.prototype
, и изменение их прототипа с помощью __proto__
или его современного эквивалента Object.setPrototypeOf
является особенно медленным во всех реализациях JavaScript. Но есть и другой способ установить прототип объекта при создании.
Функция Object.create(proto)
позволяет вам создать объект, который наследуется от proto
, поэтому вам не нужно использовать запутанный Foobar.prototype
синтаксис и магический оператор new
.
let Foobar = {
id: 0,
sayHi: function() {
console.log('Hi');
}
};
let obj = Object.create(Foobar);
obj.id = 1;
obj.sayHi(); // Hi
Если бы у вас было дюжина свойств для установки на obj
, необходимость присваивать каждое свойство вручную после создания объекта было бы немного неубедительным, но вы для этого можно использовать изящную функцию Object.assign
:
let Elephant = {
name: 'an elephant',
ears: 'boring',
sayHi: function() {
console.log(`Hi, I am ${this.name} and my ears are ${this.ears}.`);
}
};
let dumbo = Object.assign(Object.create(Elephant), {
name: 'Dumbo',
ears: 'AWESOME'
});
dumbo.sayHi(); // Hi, I am Dumbo and my ears are AWESOME.
Если вы хотите создать группу объектов и дать им все те же 3 метода, вы можете заменить это:
let t = { name: "Tom", eat, sleep, repeat };
let g = { name: "Garfield", eat, sleep, repeat };
с этим:
let protoCat = { eat, sleep, repeat };
let t = Object.assign(Object.create(protoCat), { name: "Tom" });
let g = Object.assign(Object.create(protoCat), { name: "Garfield });
Однако было бы более практично иметь вместо этого некоторую функцию конструктора. Использование Object.assign
для одного свойства немного излишне, поэтому я упросту следующий пример:
function cat(name) {
const c = Object.create(protoCat);
c.name = name;
return c;
}
let t = cat("Tom");
let t = cat("Garfield");
Обратите внимание, что вы не вызываете cat
с new
, так как cat создает свой собственный объект. Если вы попытаетесь вызвать cat
с оператором new
, это приведет к созданию объекта, который наследуется от пустого cat.prototype
, но этот объект в конечном итоге будет отброшен, поскольку cat
имеет возвращаемое значение.
ОБНОВЛЕНИЕ: Хотя мой ответ дает довольно полное объяснение того, как работает prototype
, я чувствую, что не смог указать, что вам вообще не нужно его использовать. Вы могли бы очень хорошо просто назначать методы каждый раз.
function cat(name) {
return { name, eat, sleep, repeat };
}
Конечно, все ваши кошки теперь имеют ссылку на все свои методы, которые могут занимать чуть-чуть дополнительной памяти, но при этом сложно писать для поддержки кода. сэкономить несколько байтов - это не то, что я бы назвал оптимизацией.
JavaScript любит обрабатывать объекты как данные, подобно lisp, и если вы просто притворяетесь, что у них есть классы, вы можете в конечном итоге вы хотите, чтобы вы использовали другой язык.