Вчера у меня было собеседование, и была задача написать класс JavaScript, который может быть создан с несколькими новыми и созданными объектами, которые должны быть экземпляром всех его родителей. Я пытался сделать это с помощью Function.bind (), но это не сработало.
function JSObject() {
return JSObject.bind(null);
}
var obj1 = new JSObject();
var obj2 = new obj1();
var obj3 = new obj2();
console.info(obj2 instanceof obj1); // prints false, expected true
console.info(obj3 instanceof obj2); // prints false, expected true
console.info(obj3 instanceof obj1); // prints false, expected true
console.info(obj1 instanceof obj2); // prints false, expected false
console.info(obj1 instanceof obj3); // prints false, expected false
let objects = [JSObject, new JSObject()];
for (let i = 0; i < 10; i++) {
objects.push(new objects[objects.length - 1]());
}
for (let obj of objects) {
const objProt = Object.getPrototypeOf(obj);
const objProtProt = Object.getPrototypeOf(obj.prototype);
const funcProt = Object.getPrototypeOf(Function);
const funcProtProt = Object.getPrototypeOf(Function.prototype);
console.info(objProt === funcProt); // expected true
console.info(objProtProt === funcProtProt); // expected true
}
Кроме того, я не могу напрямую изменить прототип, тесты проверяют, что прототип объекта должен быть функцией.
вернуть это или ничего в конструкторе, чтобы получить наследование. Вы также должны вернуть объект, но это вторично по отношению к вашему возврату, отличному от этого ...
@dandavis, если вы вернете this
, как бы вы использовали его в качестве конструктора при попытке вызвать new obj1();
?
@MarkMeyer: поскольку формально из конструкторов могут поступать только объекты, вы не можете вернуть конструктор из конструктора, вам придется использовать фабричный шаблон.
@dandavis Верно, поэтому возврат this
не решит проблему OP.
да, я просто привожу некоторую предысторию, так как неясно, что OP должен здесь делать; он говорит, что console.info(obj2 instanceof obj1);
должен быть ложным и истинным, что невозможно ...
Да, похоже, опечатка. Второй, вероятно, должен быть obj2 instanceof obj3
@dandavis исправлено
Что вы имеете в виду под "можно создать с несколькими новыми"? Также неясно, что должно означать «экземпляр всех его родителей» в этом контексте. Вы должны были создать простую иерархию классов?
@Bergi первый означает: var obj = new new new new new JSObject (); Я думаю, мне нужно создавать новые объекты таким образом, чтобы они унаследовали от предыдущего объекта или корня.
@GrigoryZaripov Да, похоже (см. Мой ответ). Но это также означает, что каждый созданный объект является функцией («конструктором»), противоречит ли это требованию «Я не могу изменить прототип напрямую, тесты проверяют, что прототип объекта должен быть функцией»?
@Bergi да, это так. console.info выводит ожидаемые значения, но прототип изменен.
@gzaripov Не могли бы вы добавить этот чек к вопросу? Но я сомневаюсь, что возможно иметь obj2
, который можно использовать как с new
(для которого требуется функция), так и может быть экземпляром obj1
(для которого требуется наследование от obj1.prototype
) без изменения прототипа функции.
@Bergi добавил проверку.
На самом деле это не «класс», поскольку вы не можете отличить конструктор от экземпляра. Каждая функция «конструктор» просто создает новые объекты, которые сами являются «подклассами».
function inherit(parent) {
function object() {
return Object.setPrototypeOf(inherit(object), object.prototype);
}
object.prototype = Object.create(parent.prototype);
return object;
}
var JSObject = inherit(Function);
Или используя ES6:
function inherit(parent) {
return class object extends parent {
constructor() {
return Object.setPrototypeOf(inherit(object), new.target.prototype);
}
}
}
const JsObject = inherit(Function);
Они даже достигают obj instanceof Function
и obj.prototype instanceof Function
(и, конечно же, instanceof Object
). Ваши дополнительные требования к Object.getPrototypeOf(obj) == Function.prototype
и Object.getPrototypeOf(obj.prototype) == Object.prototype
не достижимы. (Предполагается, что мы не используем прокси с отслеживанием состояния, которые обманывают ваши тесты).
Не уверен, какая именно цель здесь. Ваш конструктор всегда просто возвращает новую функцию, которая сама по себе не является конструктором (это промежуточная функция, которую возвращает
bind
, а неJSObject
), хотя при вызове он возвращает новый экземпляр, поэтому он никогда не будет экземпляром чего-либо.