13

在 JavaScript 中,对象是所有实体的根还是函数是根?

例如在下面的源objects-functions-and-prototypes-in.html中,首先作者说“Javascript 中的每个实体都是一个对象”,然后它说“任何新对象只能作为函数的实例创建(即使你执行 'var a = new Object;',Object 也是一个函数)”。据我所知,作者基本上是自相矛盾的。

我在 JavaScript 的许多其他资源中看到了同样混乱的评论。在 Java 中这很容易,您知道任何类层次结构中的第一个实体是 Object 类,但在 JavaScript 中,我看到的只是混乱。

那么,有人可以澄清一下对象是先还是函数?什么是根。

4

3 回答 3

10

我相信该行的结尾是Object.prototype,这是一个对象。这就是让我这么想的原因:

Function.prototype;                    // the empty function object
Function.prototype.__proto__;          // the default Object prototype
Object.prototype;                      // the default Object prototype
Object.prototype.__proto__;            // null

ECMAScript 5.1 规范是这样声明的:

  1. 15.3.4 函数原型对象的属性中

    Function原型对象的[[Prototype]]内部属性的值是标准的内置Object原型对象

  2. 并在15.2.4 对象原型对象的属性

    Object原型对象的[[Prototype]]内部属性的值为null

于 2013-01-04T17:51:28.610 回答
9

这是MDN 文档必须Object.prototype说的:

所有对象都从 Object.prototype 继承方法和属性,尽管它们可能被覆盖(除了具有空原型的对象,即 Object.create(null))。

换句话说,Object.prototype几乎所有对象的根。两者ObjectFunction都是 的子级Function.prototype,而后者本身就是 的子级Object.prototype

当我忽略构造函数并专注于原型链时,我发现 Javascript 中的继承更容易理解。对我来说,这样做会使问题和答案都变得更简单;像这样的问题:

  • 什么是对象的原型链?
  • 给定两个对象 x 和 y,x 在 y 的原型链中吗?(或者:y 是否从 x 继承?)

您可以使用这个小片段(此处的有用文档)轻松地自己研究原型链:

function getPrototypes(obj) {
    var protos = [],
        parent = obj;
    while ( true ) {
        parent = Object.getPrototypeOf(parent);
        if ( parent === null ) {
            break;
        }
        protos.push(parent);
    }
    return protos;
}

根据这个函数,原语没有原型:

> getPrototypes(3)
TypeError: Object.getPrototypeOf called on non-object

所以让我们把图元排除在外。对于对象,层次结构看起来像这样(其中子级缩进到其父级的右侧)。据我所知,真正的多重继承在 Javascript 中是不可能的,所以每个对象都有一个父对象,除了Object.prototype没有父对象:

  • Object.create(null)
  • 对象.原型
    • arguments
    • Object.create(Object.prototype)
    • {}
      • Object.create({}) --假设{}是上一行的对象,而不是单独的新对象
    • JSON
    • 数学
    • Array.prototype
      • []
      • new Array()
    • 函数原型
      • 大批
      • 目的
      • 功能
      • 数字
      • 布尔值
      • 细绳
      • 正则表达式
      • function MyFunction() {}
      • Object.keys
      • Object.prototype.toString
      • Object.prototype.toString.call
      • getPrototypes
    • MyFunction.prototype
      • new MyFunction()
    • String.prototype
      • new String('abc')
        • Object.create(new String('abc'))
    • Number.prototype
      • new Number(41)
    • Boolean.prototype
      • new Boolean()
      • new Object(false)
    • 正则表达式原型
      • /a/

这非常令人困惑!请注意,在大多数情况下,X.prototype它不是X!的原型。如果我们有一些更好的术语,情况可能会有所改善;但是......我们不 :( 如您所见,构造函数如Number和 与Boolean它们生成的对象处于单独的子层次结构中。此外,Object它本身继承自Function.prototype继承自Object.prototype.

如果您尝试这些示例,您还会发现使用该constructor属性是检查对象原型的一种糟糕方法,原因有几个。鉴于var str1 = new String('abc'); var str2 = Object.create(str1);,这就是为什么:

  1. 一个对象可以是多个构造函数的一个实例:str1 instanceof String并且str1 instanceof Object都为真。这没有反映在constructor属性中:str1.contructor === String

  2. 有时,我们在对象的原型链中找不到每个对象的构造函数: Object.getPrototypeOf(str2).constructor === String. 这是因为该constructor属性继承自String.prototype:bothstr1.hasOwnProperty('constructor')str2.hasOwnProperty('constructor')为假,而Object.getPrototypeOf(str1).hasOwnProperty('constructor')为真。幸运的是,您可以使用该Object.prototype.isPrototypeOf方法来代替: str1.isPrototypeOf(str2)是真的。

于 2014-03-08T17:23:45.207 回答
3

你误会了。

Javascript 中的一切(包括所有函数)都是一个对象。

但是,每个对象都是函数的一个实例。(由对象的constructor属性指定)

于 2013-01-04T17:40:17.967 回答