为什么以及何时将函数的定义隐式设置为其构造函数
这不是正在发生的事情。您误解了函数 prototype 属性的用途。
JavaScript 中的任何函数都可以是构造函数。 “构造函数”只是一个用new 调用的普通函数,例如new foo()。
当使用new 调用函数时,函数返回一个新创建的对象,其原型链以函数的prototype 属性开始。对象的__proto__ 属性(或[[Prototype]] 内部属性,用ECMAScript 术语)设置为构造函数的prototype 属性。
function Boat() { }
var titanic = new Boat();
console.log(titanic.__proto__ == Boat.prototype); // true
由于函数可以随时用作带有new 的构造函数,因此每个函数都必须具有prototype 属性,以便构造实例用作其原型链的开始。
实例的constructor 属性用于帮助该实例识别创建它的构造函数。为此,该实例具有从其原型链继承的constructor 属性,该属性设置为以构造函数的prototype 属性开头。每当创建函数对象时,都会为其提供prototype 属性,并且prototype 属性将constructor 属性设置为函数本身。
function Boat() { }
var titanic = new Boat();
// what constructor function made this instance? The Boat function did
console.log(titanic.constructor == Boat);
// does titanic have its own `constructor` property? no, it does not
console.log(titanic.hasOwnProperty("constructor") == false);
// the `constructor` property is inherited from the prototype chain
console.log(titanic.__proto__.constructor == Boat);
// titanic's prototype chain begins with `Boat.prototype`
console.log(titanic.__proto__ == Boat.prototype);
// these are the same
console.log(titanic.__proto__.constructor == Boat.prototype.constructor);
// these are also the same
console.log(titanic.constructor == Boat.prototype.constructor);
ES5 13.2, Creating Function Objects 的第 16 步到第 18 步中描述了此行为:
- 创建一个新的原生 ECMAScript 对象,并让 F 成为该对象。
- 按照 8.12 中的描述设置 F 的所有内部方法,除了 [[Get]] 之外。
- 将 F 的 [[Class]] 内部属性设置为“
Function”。
- 将 F 的 [[Prototype]] 内部属性设置为 15.3.3.1 中指定的标准内置函数原型对象。
...
- 让 proto 成为创建新对象的结果,该对象将由表达式
new Object() 构造,其中 Object 是具有该名称的标准内置构造函数。
- 使用参数“
constructor”调用proto的[[DefineOwnProperty]]内部方法,属性描述符{[[Value]]:F,... } ...
- 使用参数“
prototype”调用 F 的 [[DefineOwnProperty]] 内部方法,属性描述符 {[[Value]]: proto, ...} ...