JavaScript:继承自Function.prototype的对象

时间:2015-04-23 03:22:34

标签: javascript inheritance

我正在测试James Shore的Object Playground,我发现所有方法都继承自Function.prototype,包括全局Object.prototype上的方法。这是如何运作的?那不是圆形吗?我的意思是......没有Function.prototype"本身" Object.prototype固有的?那么Object如何固有来自Function.prototype的东西呢? Isn只是一个函数的子类型吗?不管对象本身是否包含这些行为?为什么需要继承?

enter image description here

2 个答案:

答案 0 :(得分:2)

TL; DR

Object.prototype 是原型链中的最后一个,它不会从任何东西继承。 Object 构造函数是继承自 Function.prototype 的构造函数,因为它只是一个函数;它是功能实例。

长版

由于您的问题很普遍,我会尝试描述一些主题,希望您能回答自己的问题。以下是我试图涵盖的主题:

  1. 使用单词" prototype"。
  2. 的两种方法
  3. 如何在JavaScript中创建类。
  4. 功能& 对象构造函数相关。
  5. 注意:解释JavaScript如何运作可能会很困难,有时会让人感到困惑。我希望你能从中得到一些东西。


    使用单词" prototype"

    的两种方法

    "原型"在JavaScript中可能有点混乱。这是因为根据具体情况,至少有两种方法可以使用这个词:

    1) "另一个对象的原型对象"

    另一个对象的原型对象也被称为"内部原型" ,表示为 [[Prototype]] 或{{ 1}};他们都意味着同样的事情。举个例子,我们来看看这个数组:__proto__。我们说nums = [9, 8, 7];是一个数组......但为什么呢?

    1. 我们说它是一个数组,因为它是nums构造函数的一个实例(构造函数只是函数,除了我们使用 new 关键字< / em>的)。
    2. 我们还说它是一个数组,因为它的原型对象(又名&#34;内部原型&#34; )是包含在其中的对象Array财产。
    3. 2) &#34;构造函数的原型属性&#34;

      继续Array.prototype数组示例,Array构造函数有一个名为nums的属性,我们可以像这样访问它:prototype。这个属性是&#34;内部原型&#34;数组实例,并提供我们用于调用数组的所有方法 - 例如Array.prototypeforEachpushpop等。

      因此,沿着相同的路线,我的函数join的内部原型或任何其他函数是foo()属性中包含的对象;换句话说,Function.prototype是任何函数&#34;内部原型&#34;宾语。另外,我们可以说 Function 构造函数有一个 prototype 属性,它最终是&#34;内部原型&#34;所有功能。

      我所处的地方是我们以两种不同的方式谈论一件事(原型)。在第一种方式中我们说:&#34;原型/内部原型&#34;一个对象,在第二种方式中我们说:&#34;构造函数的原型&#34;属性。


      如何在JavaScript中创建类

      在JavaScript中构造函数与其他编程语言中的类似。嗯,不太好。实际上,为了类似于类,JavaScript使用构造函数和另一个名为 prototype 的对象的组合。实际上,每个JavaScript函数都会自动获取 prototype 属性,因为函数可以用作构造函数或简单地用作函数。当一个函数不被用作构造函数时,它的 prototype 属性不会被用于任何东西,并且它只是作为一个无用的属性悬挂在那里。

      在经典语言中,该类包含实例变量实例方法,但在JavaScript中,构造函数包含实例变量及其原型对象包含实例方法。

      实例变量对于构造函数的特定实例(它们包含特定于实例的数据)是唯一的,并且实例方法由所有实例共享。换句话说,所有实例都可以执行实例方法,但不能访问彼此的变量。

      因此,JavaScript中的所有对象都是各自构造函数的实例。例如,Function.prototype之类的数组是[1,2,3]构造函数的实例。 function Array() {}之类的对象是{key: 'value'}构造函数的实例。 function Object() {}等JavaScript函数是alert()构造函数的实例......依此类推。

      同样,JavaScript中的所有构造函数都有function Function() {}属性,此属性包含构造函数实例将继承的方法。

      示例:

      prototype


      功能&amp;对象构造函数关联

      // Person constructor to create people instances function Person(name, age) { // Every instance has its own "instance variables", a.k.a. properties. this.name = name; this.age = age; } // The "instance methods" Person.prototype = { greet: function() { return 'Hello ' + this.name; }, //... }; // Joe is an instance of the `Person` constructor, and Joe's "prototype" // is the `Person.prototype` object. We call Joe's "prototype" the // "internal prototype". var joe = new Person('Joe Doe', 44); joe.name; //=> Joe Doe joe.greet(); //=> Hello Joe Doe 构造函数。

      Object 构造函数就像上面的 Person 构造函数,除了它创建对象实例而不是人物实例。

      Object构造函数。

      功能构造函数就像 Person &amp;上面的 Object 构造函数,除了它创建Function实例,换句话说它创建函数。

      FunctionPersonObjectArrayFunctionString等JavaScript中的所有构造函数都只是功能。由于它们是函数,因此意味着它们是在语言内部使用Boolean创建的,并且new Functioncall()等所有函数方法都来自 Function.prototype 。换句话说, Function.prototype 是&#34;原型/内部原型&#34;所有函数的对象,包括构造函数和函数apply()本身。

      <强>结论:

      不要将构造函数的Function属性(包括未来实例将使用的方法)与构造函数本身的内部原型混淆。

      但是,请记住构造函数的prototype属性是构造函数实例的内部[[Prototype]]。例如,prototypeFunction.prototype构造函数的内部[[Prototype]],这是有道理的,因为Object构造函数只是另一个函数(Object实例)

      对于代码结论,请看一下Object&amp;函数构造函数在JavaScript内部创建:

      Function

      更多资源

答案 1 :(得分:1)

什么是原型?

JavaScript是一种基于原型的语言。这意味着技术上没有“类”。只有原型,描述对象。每个对象都有一个原型。原型本身实际上是一个对象。 (令人困惑吧?如果你不能把它包裹起来,请不要过于考虑它。它会在某个时候点击。只要知道原型是你可以修改的对象。

在继续之前,我想指出我的代码示例不符合正确或最佳做法。我编写的代码示例纯粹是为了演示或解释一个概念。

让我们看看一些代码:

Object.toString();                 // "[object Object]"
Object.prototype.toString();       // "[object Object]"
Object.hasOwnProperty('toString'); // true
typeof Object;                     // "function"
typeof Object.prototype            // "object"

var obj = new Object();
obj.toString();                    // "[object Object]"
obj.hasOwnProperty('toString');    // false

obj.toString = function() {
    return 'My Object';
};

obj.toString();                    // "My Object"
obj.hasOwnProperty('toString')     // true
obj.__proto__.toString();          // "[object Object]"
typeof obj;                        // "object"
typeof obj.__proto__;              // "object"

您可能还注意到typeof Object返回"function"。这是因为Object实际上是一个构造函数方法,用于实例化新对象。我的实例对象实际上是typeof obj === "object"

原型链

正如您在上面的代码中看到的那样,Object包含一个名为toString的方法。但Object的实例却没有。 obj没有自己的toString方法。但您仍然可以在toString上致电obj。 JavaScript通过遵循原型链来完成继承

我可以覆盖obj.toString以使obj拥有自己的toString方法,但obj.__proto__属性仍然拥有其toString方法prototype }。

如果有问题的对象不包含自己的属性toString,那么该属性将查看其原型。如果它自己的原型不包含属性toString,则查找将继续原型链直到找到属性。如果原型是null,则表示属性为undefined

JavaScript中的所有内容都是对象?

是的,在最核心,最终在原型链中,每个对象都是一个JavaScript对象。包括Functions

var func = function() {};
func.__proto__                       //function Empty() {}
func.__proto__.__proto__             // Object {}
func.__proto__.isPrototypeOf(Object) // true

因此函数是JavaScript中的对象。这就是为什么你可以将属性附加到函数。

还有一些澄清......

  

所有方法都继承自Function.prototype

不,所有方法都不会从Function继承。方法 Function

  

那么Object.prototype如何固有来自Function.prototype的东西?

Object不会从Function继承任何内容。对象可以使用功能,例如toString方法。

Object有点演示复合设计模式。 (除了可以向引用自身的对象添加属性和/或创建循环引用之外)

来自[http://en.wikipedia.org/wiki/Composite_pattern]

  

在软件工程中,复合模式是一种分区设计模式。复合模式描述了一组对象的处理方式与对象的单个实例相同。复合的意图是将对象“组合”成树结构以表示部分整体层次结构。

因为Object包含多个属性,这些属性也都是Object

那么它是否循环?不,不是真的。但它肯定是递归的。

您可以在此处详细了解JavaScript原型:http://blog.pluralsight.com/understanding-javascript-prototypes

请注意,ES6在JavaScript中引入了实际的类。这与我上面解释的一切不同。 ES6 class是我还没有玩过的东西。