我正在深入研究Javascript原型链 为了记录我的发现,我得出了以下方案:
虽然大多数概念都很清楚,但我只剩下两个相关的问题。我猜测将这些问题集中在这个问题上可能会更好,而不是将它们分开:
Function.prototype
是否有类型函数的原因,而不是对象?typeof Function.prototype; //"function"
Function.prototype
是一个'唯一函数',因为它没有像其他函数那样拥有自己的原型属性吗? (是否有一个普遍接受的“名称”来指代它?)答案 0 :(得分:22)
原因是the ES5 spec这样说:
Function原型对象本身就是一个Function对象(它的 [[Class]]是" Function"),当被调用时,接受任何参数和 返回undefined。
注意在ES5中常见的做法是使某个类的原型成为该类的成员:
Object.prototype
是一个Object对象。Function.prototype
是一个Function对象,在调用时返回undefined
。Array.prototype
是一个空的Array对象。String.prototype
是一个String对象,其值为空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外来对象,并具有为这些对象指定的内部方法。所以现在的原因是向后兼容性:
将Function原型对象指定为函数对象 确保与之前创建的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
答案 1 :(得分:6)
回答你的问题:
1) Function.prototype
是一种功能,因为根据ECMAScript 2015:
Function原型对象是内部对象%FunctionPrototype%。 Function原型对象本身就是一个内置的函数对象。
将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)关于原型属性:
Function原型对象没有原型属性。
这是唯一的,因为所有函数通常都具有prototype
属性,但是由于Function原型对象仅被指定为Function对象以保持兼容性,因此它的行为与常规函数的行为不同。
我已经创建了一个带有各种测试的JSFiddle,以防它对任何人有所帮助:
// 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.
答案 2 :(得分:3)
取代之前的答案,我无法忍受。感谢Oriol。头部刮伤是我的。
关于第一个问题,Function对象并没有特别不同,因为Function.prototype
是一个函数。其他内置构造函数使用自己类型的原型对象。引起对函数情况的注意的是typeof
运算符通过返回" function"将函数对象与其他对象区别对待。而不是"对象"。
全局构造函数将自己列为原型对象的构造函数:
var BuiltIn = Function; // for example
BuiltIn.prototype.constructor == BuiltIn // true
或多或少是纪录片。内置构造函数的原型对象通常具有与javascript引擎交互的方法,并且不是在运行时使用对其列出的构造函数的javascript调用创建的:Function.prototype instanceof Function
为false,其他内置构造函数的结果类似as Array,RegExp等测试。
全局Function
对象是唯一的,因为它将自己列为自己的构造函数(Function.constructor == Function
为真),并且它是自身的实例(Function instanceof Function
也是如此)。后一个结果表明Function.prototype
位于Function
的原型链中。 Function.prototype
本身就是Object.prototype
上的原型。
认为Function.prototype
不是通常意义上的Function对象的另一个原因(除了在文档中这样说)是它不能被调用为构造函数并且如果尝试执行则抛出错误所以。由于在将函数作为构造函数调用时使用函数的prototype属性,因此Function.prototype
不具有此属性是有意义的。