【问题标题】:Function.prototype is a functionFunction.prototype 是一个函数
【发布时间】:2016-01-30 09:37:03
【问题描述】:

我正在深入研究 Javascript 原型链。
为了记录我的发现,我绘制了以下方案:

虽然大部分概念都很清楚,但我只剩下两个相关的问题。我猜与其将它们分开,不如将它们集中在这个问题上可能会更好:

  1. Function.prototype 是函数类型而不是对象类型是否有原因?
    typeof Function.prototype; //"function"
  2. Function.prototype 是 JS 中的“唯一函数”吗,因为它不像其他函数那样拥有自己的原型属性? (是否有一个普遍接受的“名称”来指代它?)

【问题讨论】:

标签: javascript prototype


【解决方案1】:

原因是the ES5 spec是这么说的:

Function 原型对象本身就是一个 Function 对象(它的 [[Class]] 是 "Function"),当被调用时,它接受任何参数和 返回未定义。

请注意,在 ES5 中,使某个类的原型成为该类的成员是很常见的:

我认为它是标准化的,因为一个类的原型具有该类的内在属性,作为该类的实例。如果它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 27Table 56 中列出的任何其他内部槽。
  • Promise.prototype 是一个普通对象,没有 [[PromiseState]] 也没有任何其他 Promise 实例的内部槽。

但是,旧行为仍然存在:

所以现在的原因是向后兼容:

函数原型对象被指定为函数对象 确保与之前创建的 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
    

【讨论】:

  • javascript之母。当我认为它不再让我感到惊讶时
【解决方案2】:

回答您的问题:

1) Function.prototype 是一种函数,因为根据 ECMAScript 2015:

函数原型对象是内部对象 %FunctionPrototype%。 Function 原型对象本身就是一个内置的函数对象。

函数原型对象被指定为函数对象,以确保与在 ECMAScript 2015 规范之前创建的 ECMAScript 代码兼容。

所以 Function 原型对象只定义为 Function 对象,以确保与旧的 ECMAScript 标准兼容。该函数实际上并没有做任何事情:

当被调用时,它接受任何参数并返回 undefined。

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

2)关于原型属性:

函数原型对象没有原型属性。

Same Source

这是独一无二的,因为所有函数通常都具有prototype 属性,但是由于函数原型对象仅被指定为函数对象以保持兼容性,因此它的行为不同于常规函数。

我创建了一个带有各种测试的 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.

【讨论】:

    【解决方案3】:

    代替我无法忍受的先前答案。感谢 Oriol。挠头是我的。

    关于第一个问题,Function 对象并没有特别的不同,因为Function.prototype 是一个函数。其他内置构造函数使用它们自己类型的原型对象。值得注意的是 Function 案例是 typeof 运算符通过返回“function”而不是“object”来区别对待其他对象。

    全局构造函数将自己列为其原型对象的构造函数:

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

    或多或少是纪录片。内置构造函数的原型对象通常具有与 javascript 引擎交互的方法,并且不是使用对其列出的构造函数的 javascript 调用创建的,因为它在运行时出现:Function.prototype instanceof Function 为 false,其他内置构造函数(例如 Array)的结果类似, RegExp 等经过测试。

    然而,全局Function 对象是独一无二的,因为它将自己列为自己的构造函数(Function.constructor == Function 为真),并且它是自身的一个实例(Function instanceof Function 也是如此)。后一个结果表明Function.prototypeFunction 的原型链中。 Function.prototype 本身的原型是在 Object.prototype 上。

    另一个认为Function.prototype 不是通常意义上的 Function 对象的原因(除了在文档中这样说之外)是它不能作为构造函数调用,并且如果尝试这样做会引发错误。由于函数的原型属性在作为构造函数调用时使用,所以Function.prototype 不具有此属性是有意义的。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-06
      • 1970-01-01
      • 1970-01-01
      • 2018-10-01
      相关资源
      最近更新 更多