2015-10-04 6 views
19

Я копаю в цепочку прототипов Javascript.
Для того, чтобы документировать свои выводы, я нарисовал следующую схему:Function.prototype - это функция

enter image description here

Хотя большинство понятий ясно, я остался только с двумя связанными с этим вопросами. Вместо того, разделив их, я предположил, что централизация их в этом вопросе может быть лучше:

  1. Есть ли причина Function.prototype быть функции типа, а не объект?
    typeof Function.prototype; //"function"
  2. Есть Function.prototype «уникальная функция» в JS, так как у него нет собственного прототипа, как и другие функции? (Это есть «имя» обычно принято ссылаться на него?)
+0

обратите внимание, что 'функция Person() {} TypeOf Person.prototype // "объект"' – Saar

+1

Функции также являются объектами –

+2

Object.getPrototypeOf (Function.prototype) === Object.prototype –

ответ

18

Причина заключается в том, что the ES5 spec говорит так:

Объект прототип функции сам объект Function (его [[Class ]] - это «Функция»), которая при вызове принимает любые аргументы, а возвращает неопределенные.

Примечание это распространено в ES5, чтобы сделать прототип некоторого класса членом этого класса:

  • Object.prototype является объектом Object.
  • Function.prototype - объект функции, который возвращает undefined при вызове.
  • Array.prototype - пустой объект Array.
  • String.prototype - объект String, значение которого является пустой строкой.
  • Boolean.prototype - булев объект, значение которого false.
  • Number.prototype - Объект Number, значение которого равно +0.
  • Date.prototype - объект Date, чей [[PrimitiveValue]] - NaN.
  • RegExp.prototype - объект RegExp, свойства которого соответствуют new RegExp().
  • Error.prototype является объектом ошибки.

Я думаю, что это стандартизировано как таковое, потому что прототип класса обладает внутренними свойствами этого класса, как экземпляры этого класса. И если он looks like a duck, он должен вести себя как утка. Поэтому нужно также призывать методы прототипа к самому прототипу, а не к экземпляру.

Однако ES6 это не понравилось. Так что изменилось поведение для тех, кто:

  • Boolean.prototype обычный объект не [[BooleanData]] внутренний слот.
  • Error.prototype - обычный объект без внутреннего слота [[ErrorData]].
  • Number.prototype - обычный объект без внутреннего слота [[NumberData]].
  • Date.prototype - обычный объект без внутреннего слота [[DateValue]].
  • String.prototype - обычный объект без внутреннего слота [[StringData]].
  • RegExp.prototype - обычный объект без [[RegExpMatcher]], ни один из других внутренних слотов объектов экземпляра RegExp.

А также для новых "классов" (ES6 не объекты не имеют [[Class]]):

  • Symbol.prototype обычный объект не [[SymbolData]] внутренний слот.
  • TypedArray.prototype - обычный объект без [[ViewedArrayBuffer]] или любой другой из внутренних слотов, которые являются специфическими для TypedArray объектов экземпляра.
  • Map.prototype - обычный объект без внутреннего слота [[MapData]].
  • Set.prototype - обычный объект без внутреннего слота [[SetData]].
  • WeakMap.prototype - обычный объект без внутреннего слота [[WeakMapData]].
  • WeakSet.prototype - обычный объект без внутреннего слота [[WeakSetData]].
  • ArrayBuffer.prototype - обычный объект без внутренних слотов [[ArrayBufferData]] и [[ArrayBufferByteLength]].
  • DataView.prototype - обычный объект без внутренних [[DataView]], [[ViewedArrayBuffer]], [[ByteLength]] и [[ByteOffset]] внутренних слотов.
  • GeneratorFunction.prototype - обычный объект без [[ECMAScriptCode]] или любой другой из внутренних слотов, перечисленных в Table 27 или Table 56.
  • Promise.prototype - обычный объект, не имеющий [[PromiseState]] или любой другой внутренний слот экземпляров Promise.

Однако старое поведение остается для тех, кто:

  • Function.prototype сам встроенный объект функции.
  • Array.prototype является экзотическим объектом Array и имеет внутренние методы, указанные для таких объектов.

Итак, теперь причина обратная совместимость:

Функциональный прототип объекта задается как функция объекта обеспечения совместимости с ECMAScript кодом, который был создан до спецификации ECMAScript 2015.

Примечание: это не делает Function.prototype специальную функцию. Только конструкторы имеют prototype property:

Функциональных случаи, которые могут быть использованы в качестве конструктора имеют prototype свойства.

Существуют многочисленные примеры функций не-конструктора помимо Function.prototype, такие как

  • методы в Math объекта:

    typeof Math.pow; // "function 
    'prototype' in Math.pow; // false 
    
  • Некоторые принимающие объекты:

    typeof document.createElement('object'); // "function 
    'prototype' in document.createElement('object'); // false 
    
  • В ES6, стрелка функции:

    typeof (x => x * x); // "function 
    'prototype' in (x => x * x); // false 
    
+2

Мать javascript. И когда я подумал, что это больше не может меня удивить – slezica

2

В замены предыдущего ответа, который я не мог стоять на. Благодаря Ориолу. Головка царапин - моя.

В отношении первого вопроса объект Function это не особенно отличается просто потому, что Function.prototype является функцией. Другие встроенные конструкторы используют прототипы объектов своего типа. То, что привлекает внимание к случаю функции, заключается в том, что оператор typeof рассматривает объекты функции в отличие от других объектов, возвращая «функцию» вместо «объекта».

Глобальные Конструкторы листинг себя конструкторами своих объектов-прототипов:

var BuiltIn = Function; // for example 
BuiltIn.prototype.constructor == BuiltIn // true 

является более или менее документальный. Объекты прототипа встроенных конструкторов обычно имеют методы, которые взаимодействуют с движком javascript и не создаются с помощью вызова javascript к их указанному конструктору, как он отображается во время выполнения: Function.prototype instanceof Function является ложным с аналогичными результатами для других встроенных конструкторов, таких как Array, RegExp и т. д.

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

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

5

В ответ на вопросы:

1)Function.prototype является тип функции, потому что, в соответствии с ECMAScript 2015:

Объект Прототип функции является внутренней задачей% FunctionPrototype%. Объект-прототип функции сам по себе является встроенным функциональным объектом.

Объект-прототип функции задан как функциональный объект для обеспечения совместимости с кодом ECMAScript, который был создан до спецификации ECMAScript 2015.

Таким образом, объект-прототип функции определяется только как объект функции, чтобы обеспечить совместимость со старыми стандартами ECMAScript. Функция фактически ничего не делает:

При вызове он принимает любые аргументы и возвращает неопределенные.

http://www.ecma-international.org/ecma-262/6.0/#sec-properties-of-the-function-prototype-object

2) Что касается свойства прототипа:

Функциональный объект-прототип не имеет свойства прототипа.

Same Source

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

Я создал JSFiddle с различными тестами в случае это помогает кто-нибудь:

http://jsfiddle.net/Ld0b39xz/

// We'll use 'Object.getPrototypeOf' to access [[prototype]] 

// As you know, [[prototype]] of Object.prototype returns 'null'. 
console.log(Object.getPrototypeOf(Object.prototype)); 
// null 

//////////////////////////////////////////////////////// 

// Let's take a closer look at Function.prototype 
console.log(Function.prototype); 
// Output: 
// function(){} 

// This is what the specs say should happen: 
// "The Function prototype object is itself a built-in function object." 

///////////////////////////////////////////////////// 

// Let's see if this function has a 'prototype' property. 
// All functions normally have a prototype property that initially 
// references an empty object...except this one. 
var fn = Function.prototype; 
console.log(fn.prototype); 
// Output: 
// undefined 

// This is expected, according to the specs: 
// "The Function prototype object does not have a prototype property." 

// It does have some properties such as 'name' and 'length', 
// but not 'prototype'. 

//////////////////////////////////////////////////////// 

// Let's see what [[prototype]] of Function.prototype returns. 
console.log(Object.getPrototypeOf(Function.prototype)); 
// Output: 
// Object{} 

// Again this is expected: 
// "The value of the [[Prototype]] internal slot of the 
// Function prototype object is the intrinsic object %ObjectPrototype%" 

///////////////////////////////////////////////////////// 

// Now lets see what the [[Prototype]] of this object is: 
console.log(Object.getPrototypeOf(Object.getPrototypeOf(Function.prototype))); 
// Output: 
// null 

// We've come full circle since all the statement above is 
// doing is looking for the prototoype of the native Object, 
// which we already know is 'null' from our first test.