【问题标题】:why is functionName() == functionName.prototype.constructor()为什么 functionName() == functionName.prototype.constructor()
【发布时间】:2015-05-05 18:10:51
【问题描述】:

我注意到我是否有以下情况:

var functionName = function(){console.log("this is a function!")}

调用functionName 等效于functionName.prototype.constructor,因为它们都包含上面的函数定义。

我想我只想解释一下函数是如何在 JavaScript 中用作对象的,以及它与原型继承的关系。这是一个广泛的问题,所以主要是为了明确它,我想知道为什么何时函数的定义被隐式设置为其构造函数。我想这与支持 new functionName() 对象构造范式有关。

【问题讨论】:

标签: javascript function prototypal-inheritance


【解决方案1】:

为什么以及何时将函数的定义隐式设置为其构造函数

这不是正在发生的事情。您误解了函数 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 步中描述了此行为:

  1. 创建一个新的原生 ECMAScript 对象,并让 F 成为该对象。
  2. 按照 8.12 中的描述设置 F 的所有内部方法,除了 [[Get]] 之外。
  3. F 的 [[Class]] 内部属性设置为“Function”。
  4. F 的 [[Prototype]] 内部属性设置为 15.3.3.1 中指定的标准内置函数原型对象。

...

  1. proto 成为创建新对象的结果,该对象将由表达式 new Object() 构造,其中 Object 是具有该名称的标准内置构造函数。
  2. 使用参数“constructor”调用proto的[[DefineOwnProperty]]内部方法,属性描述符{[[Value]]:F,... } ...
  3. 使用参数“prototype”调用 F 的 [[DefineOwnProperty]] 内部方法,属性描述符 {[[Value]]: proto, ...} ...

【讨论】:

    【解决方案2】:

    JavaScript 只有一种结构——它们是对象。每个对象都通过其原型链接到另一个对象。当您调用函数属性时,JavaScript 将查找对象的原型、父对象的原型等,直到找到您要查找的属性。原型搜索的最后一行类似于如果你调用 toString(),它会搜索这个,除非你覆盖了 toString() 属性,否则它会在 Object.prototype 中找到 toString()。

    当您声明一个函数时,解释器会创建一个新的函数对象并填充原型属性。注意:原型的默认值是一个带有属性构造函数的对象。

    function functionName() {}
    var newFunction = new functionName();
    newFunction.hasOwnProperty('constructor') //false
    newFunction.prototype.hasOwnProperty('constructor') //true as you noted above
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-12-07
      • 2019-10-08
      • 2013-06-05
      • 1970-01-01
      • 2014-11-16
      相关资源
      最近更新 更多