У меня есть следующий код JavaScript
function Parent() {
}
function Child() {
}
Child.prototype = Object.create(Parent.prototype);
Обратите внимание на отсутствие утверждения
Child.prototype.constructor = Child;
Я понимаю, что, поскольку свойство constructor
не было установлено, проверки instanceof
должны завершиться неудачно для новых экземпляров класса Child
.
var child = new Child();
child instanceof Child; //Should give false
Я проверил, что конструктор неправильно установлен
Но когда я запустил child instanceof Child
, он дал мне истинную
Но это должно быть false
, поскольку свойство конструктора не установлено на прототипе Child
как Child
.
Окружающая среда
Google Chrome Version 48.0.2564.109 (64-bit)
Ubuntu 14.04 LTS
Мое понимание состоит в том, что поскольку свойство конструктора не было установлено, проверка экземпляра должна завершиться неудачно для новых экземпляров класса Child.
Нет, это неверно. Фактически, до ES2015 (иначе ES6) свойство constructor
не использовалось ни для чего вообще в самом JavaScript. Он был определен как существующий на объектах по умолчанию, время выполнения назначает свойство prototype
для функций, но не используется.
instanceof
вообще не заботится о construtor
. Рассмотрим:
o instanceof Foo
instanceof
будет выглядеть, если объект Foo.prototype
указывает на то, что находится в цепочке прототипов o
. (Если "цепочка прототипов" не является знакомым термином, см. * В конце ответа, а затем возвращайтесь.) Если это так, он возвращает true
; если нет, он возвращает false
.
Например, здесь концептуальная реализация instanceof
, ручная размахивая некоторыми деталями:
function isAnInstance(obj, func) {
var p;
for (p = Object.getPrototypeOf(obj); p; p = Object.getPrototypeOf(p)) {
if (p === func.prototype) {
return true;
}
}
return false;
}
Хотя он был заменен спецификацией ES2015, я привяжусь к спецификации ES5, потому что он написан на более доступном языке, и этот аспект не изменился: instanceof
эффективно просто вызывает функцию [[HasInstance]]
внутренний метод, указанный здесь.
Мы можем видеть, что constructor
не участвует в вашем вопросе, а также из этой простой демонстрации:
var p = {};
var o = Object.create(p);
var Foo = function() {};
Foo.prototype = p;
snippet.log(o instanceof Foo); // true
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
Обратите внимание, что:
o
не был создан через Foo
Foo
даже не существовал, пока не был создан o
o
и его прототип вообще не имеет свойства constructor
... и все же instanceof
говорит: "Да, похоже, что это Foo".:-) Чисто, потому что объект Foo.prototype
указывает на то, что он также находится в цепочке прототипов o
.
* Цепочка прототипов
Вы четко знаете, что объекты в JavaScript имеют прототипы, из которых они наследуют свойства. Эти прототипы являются объектами, поэтому у них есть прототипы. Таким образом, вы получаете "цепочку" прототипов.
Рассмотрим двухуровневую (возможно, трехуровневую) иерархию наследования, здесь в ES5:
function Base() {
}
function Derived() {
Base.call(this);
}
Derived.prototype = Object.create(Base.prototype);
Derived.prototype.constructor = Derived;
... или в ES2015:
class Base {
}
class Derived extends Base {
}
Теперь мы используем его:
var d = new Derived();
(Где вы видите "объект d
" и тому подобное в нижеследующем, я, конечно, имею в виду "объект d
относится к" — но это действительно многословно.)
Теперь прототипом объекта d
является Derived.prototype
. Derived.prototype
прототип Base.prototype
. Base.prototype
прототип Object.prototype
. Object.prototype
не имеет прототипа (его внутренний слот [[Prototype]]
null
).
Эти объекты являются цепочкой прототипов, лежащей в основе d
, и они означают, что d
- это instanceof Object
, instanceof Base
и instanceof Derived
.