Подтвердить что ты не робот

Почему в JavaScript как "Object instanceof Function", так и "Function instanceof Object" возвращаются true?

Почему в JavaScript делают как Object instanceof Function, так и Function instanceof Object return true?

Я попробовал его в Safari WebInspector.

4b9b3361

Ответ 1

Мне потребовалось время, чтобы разобраться, но это действительно стоит потраченного времени. Сначала давайте посмотрим, как работает instanceof.

Цитата из MDN,

Оператор instanceof проверяет, имеет ли объект в своей цепочке прототипов свойство prototype конструктора.

[instanceof]

Теперь давайте посмотрим, как instanceof определяется спецификацией ECMA 5.1,

Произведение RelationalExpression: RelationalExpression instanceof ShiftExpression оценивается следующим образом:

  • Пусть lref будет результатом оценки RelationalExpression.
  • Пусть lval be GetValue(lref).
  • Пусть rref будет результатом оценки ShiftExpression.
  • Пусть rval be GetValue(rref).
  • Если Type(rval) не является объектом, бросьте исключение TypeError.
  • Если rval не имеет внутреннего метода [[HasInstance]], бросьте исключение TypeError.
  • Возвращает результат вызова внутреннего метода [[HasInstance]] rval с аргументом lval.

Сначала вычисляются выражения слева и справа (GetValue), а результат правой стороны должен быть объектом с внутренним методом [[HasInstance]]. Не все объекты имеют внутренний метод [[HasInstance]], но функции. Например, следующее будет терпеть неудачу

console.log(Object instanceof {});
# TypeError: Expecting a function in instanceof check, but got #<Object>

[[HasInstance]]

Теперь давайте посмотрим, как [[HasInstance]] был определен в спецификации ECMA 5.1,

Предположим, что F является объектом Function.

Когда вызывается внутренний метод [[HasInstance]] F со значением V, выполняются следующие шаги:

  • Если V не является объектом, верните false.
  • Пусть O является результатом вызова внутреннего метода [[Get]] F с именем свойства "prototype".
  • Если Type(O) не является объектом, бросьте исключение TypeError.
  • Повторите
    • Пусть V будет значением внутреннего свойства [[Prototype]] V.
    • Если V - null, верните false.
    • Если O и V относятся к одному и тому же объекту, верните true.

Это так просто. Возьмите свойство prototype F и сравните его с внутренним свойством [[Prototype]] O до тех пор, пока он не станет null или prototype of F не будет таким же, как O.

[[Prototype]] внутреннее свойство

Сначала давайте посмотрим, что является внутренним свойством [[Prototype]],

Все объекты имеют внутреннее свойство [[Prototype]]. Значение этого свойства либо null, либо объект и используется для реализации наследования. Может ли собственный объект иметь объект-хост, поскольку его [[Prototype]] зависит от реализации. Каждая цепочка [[Prototype]] должна иметь конечную длину (то есть, начиная с любого объекта, рекурсивный доступ к внутреннему свойству [[Prototype]] должен в конечном итоге привести к значению null).

Примечание. Мы можем получить это внутреннее свойство с помощью функции Object.getPrototypeOf.

prototype свойство

[[HasInstance]] также говорит о другом свойстве prototype, которое относится к объектам Function.

Значение свойства prototype используется для инициализации внутреннего свойства [[Prototype]] для вновь созданного объекта до того, как объект Function вызывается как конструктор для этого вновь созданного объекта.

Это означает, что когда объект функции используется как конструктор, будет создан новый объект, и новый объект будет иметь свой внутренний [[Prototype]], инициализированный этим свойством prototype. Например,

function Test() {}
Test.prototype.print = console.log;
console.log(Object.getPrototypeOf(new Test()) === Test.prototype);
# true

Актуальная проблема

Теперь вернемся к актуальному вопросу. Возьмем первый случай

console.log(Object instanceof Function);
# true

Сначала он выберет Function.prototype, и он попытается найти, находится ли этот объект в иерархии прототипов Object. Посмотрим, как получится

console.log(Function.prototype);
# [Function: Empty]
console.log(Object.getPrototypeOf(Object));
# [Function: Empty]
console.log(Object.getPrototypeOf(Object) === Function.prototype);
# true

Так как Function.prototype соответствует внутреннему свойству Object [[Prototype]], он возвращает true.

Теперь давайте возьмем второй случай

console.log(Function instanceof Object);
# true
console.log(Object.prototype);
# {}
console.log(Object.getPrototypeOf(Function));
# [Function: Empty]
console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}
Object.getPrototypeOf(Object.getPrototypeOf(Function)) === Object.prototype
# true

Здесь мы сначала получаем Object.prototype, который равен {}. Теперь он пытается найти, существует ли тот же объект {} в цепочке прототипов Function. Непосредственный родительский элемент Function является и пустой функцией.

console.log(Object.getPrototypeOf(Function));
# [Function: Empty]

Это не то же самое, что Object.prototype

console.log(Object.getPrototypeOf(Function) === Object.prototype);
# false

Но алгоритм [[HasInstance]] не останавливается на достигнутом. Он повторяет и поднимает еще один уровень

console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function)));
# {}

И это то же самое, что и Object.prototype. Вот почему это возвращает true.

Ответ 2

Из MDN:

Оператор instanceof проверяет, имеет ли объект в своей прототипной цепочке свойство прототипа конструктора.

По существу, он проверяет, есть ли Object (а не экземпляр Object, но сам конструктор) имеет экземпляр Function.constructor где-то вверх по цепочке прототипов.

И действительно:

> Function.__proto__.__proto__ === Object.prototype
true
> Object.__proto__ === Function.prototype
true

Это объясняет, почему Object instanceof Function, а также наоборот.

Ответ 3

ВСЕ объекты имеют внутреннее свойство, называемое [[Prototype]]. Значение этого свойства равно либо null, либо объекту и используется для реализации наследования. Если вы попытаетесь найти ключ на объекте и его не найти, JavaScript будет искать его в цепочке прототипов.

Конструктор Function создает новые объекты Function (экземпляры конструктора Function). Свойство prototype специфично для объектов Function. Конструктор Function сам является объектом Function (экземпляр конструктора Function).

Когда объект Function используется как конструктор, будет создан новый объект, и новый объект будет иметь свой [[Прототип]], инициализированный с помощью свойства prototype конструктора.

function Dog () {}
var myCrazyDog = new Dog();
myCrazyDog.__proto__ === Dog.prototype // true

Спецификация языка состоит в том, что все объекты являются экземплярами конструктора Object, а все функции являются экземплярами конструктора Function.

Object instanceof Функция истинна, потому что Object является функцией и, следовательно, является экземпляром Function (Object является объектом Function - экземпляром конструктора Function). Объект наследуется от Function.prototype.

console.log(Object instanceof Function)                         // true
console.log(Object.__proto__ === Function.prototype)            // true

Объект instanceof Object имеет значение true, потому что Object наследует функцию Function.prototype. Поскольку Function.prototype является объектом, он наследует Object.prototype. Экземпляр функции объекта true, потому что функция наследует функцию Function.prototype. Поскольку Function.prototype является объектом, он наследует Object.prototype. Цепочка прототипа выглядит так:

Object ---> Function.prototype ---> Object.prototype ---> null
Function ---> Function.prototype ---> Object.prototype ---> null

console.log(Object instanceof Object)                               // true
console.log(Object.__proto__ === Function.prototype)                // true
console.log(Object.__proto__.__proto__ === Object.prototype)        // true
console.log(Function instanceof Object)                             // true
console.log(Function.__proto__ === Function.prototype)              // true
console.log(Function.__proto__.__proto__ === Object.prototype)      // true

Функция instanceof Function истинна. Функция - это сам экземпляр (естественно, поскольку его функция и, следовательно, экземпляр функции). Цепочка прототипа выглядит так:

Function ---> Function.prototype ---> Object.prototype ---> null

console.log(Function instanceof Function)                           // true
console.log(Function.__proto__ === Function.prototype)              // true
console.log(Function.__proto__.__proto__ === Object.prototype)      // true

Поэтому имейте в виду, что конструкторы Function() и Object() являются функциями. Поскольку они являются функциями, они являются экземплярами конструктора Function() и наследуются от Function.prototype. Поскольку Function.prototype является объектом, Function.prototype является экземпляром Object, таким образом, наследуется от Object.prototype.

console.log(Object instance of Function)                    // true
console.log(Function instance of Function)                  // true
console.log(Function.prototype instanceof Object);          // true

Ответ 4

Источником путаницы в вашем вопросе является внутренняя двойственная природа функций * в JavaScript (ECMAScript).

Функции в js являются одновременно регулярными функциями и объектами. Подумайте о них как алгоритмическом Dr. Джекил и мистер Хайд. Они выглядят как объекты снаружи, но внутри они просто ваши старые добрые js-функции со всеми их причудами, или, может быть, наоборот.

JavaScript действительно сложный бизнес:)

Итак, вернемся к вашему вопросу, заимствуя синтаксис, появляющийся на MDN:

object instanceof constructor

Применяя его к первому выражению в вашем коде:

Object instanceof Function

Здесь у вас есть Object, функция-конструктор, которая используется как инициализатор объекта, но поскольку функции приводят к двойному проживанию в js, у него есть привязанные к объекту реквизиты и методы, связанные с ним, что также эффективно отражается на объекте.

Итак, первое условие в инструкции выполнено. Мы продолжаем исследовать другое условие или операнд.

Function, как вы могли заметить, также является конструктором функций, но его другая сторона объекта сейчас не интересует нас во время выполнения этого конкретного оператора.

Итак, синтаксические условия встречаются как "объект" и "конструктор". Теперь мы можем приступить к расследованию их наследственного отношения и если есть связь между ними.

Так как Object является самой рабочей функцией, имеет смысл предположить, что у нее есть внутренняя прототипная поддержка, указывающая на ссылку на объект Function.prototype, поскольку в функциях js ALL наследуется их реквизита и методов через это же место Function.prototype.

true определенно является ТОЛЬКО ожидаемым результатом этого сравнения, выполняемого оператором instanceof.

В другом случае:

Function instanceof Object

Так как мы уже установили, что функции из js также имеют объектную сторону. Имеет смысл, что они получили свои фантастические игрушки, специфичные для объекта, из Object.prototype, и поэтому они представляют собой экземпляры конструктора Object.

Надеюсь, я не добавил к путанице с моими объяснениями и аллегориями.:)

*: Не только функции, которые приводят к двойной жизни в js. Почти все типы данных в js имеют темную сторону объекта, которая облегчает выполнение операций и манипуляций без каких-либо проблем.

Ответ 5

Самое плохое свойство на самом деле состоит в том, что функция является экземпляром самого себя. Function instanceof Function возвращает true.

Это хорошо объяснено в Kannan Удивительно элегантная модель типа Javascript, http://web.archive.org/web/20140205182624/http://vijayan.ca/blog/2012/02/21/javascript-type-model

Цитата в конце объяснения:

Да, это означает, что функция является экземпляром самого себя (естественно, поскольку его функция и, следовательно, экземпляр функции). Это то, с чем мы все время занимались, сознательно или нет, уже давно - все функции-конструкторы являются регулярными функциями и, следовательно, экземплярами Function, а сама функция - это просто функция-конструктор для построения других функций, поэтому она тоже является экземпляром функции.

введите описание изображения здесь