JavaScript:从 Function.prototype 继承的对象

shm*_*uli 4 javascript inheritance

我正在测试 James Shore 的Object Playground,我看到所有方法都继承自 Function.prototype,包括全局 Object.prototype 上的方法。这是如何运作的?是不是有点圆?我的意思是...不是 Object.prototype 固有的 Function.prototype “本身”吗?那么 Object 是如何从 Function.prototype 中继承任何东西的呢?函数不只是对象的子类型吗?无论如何,对象本身不应该包含这些行为吗?为什么需要继承?

在此处输入图片说明

ist*_*tos 5

TL; 博士

Object.prototype位于原型链的最后,它不继承任何东西。该对象的构造是一个继承自Function.prototype的,因为它只是一个功能; 它是一个Function实例。


长版

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

  1. “原型”一词的两种用法。
  2. 如何在 JavaScript 中创建类。
  3. 该如何功能对象的构造有关。

注意:解释 JavaScript 的真正工作原理可能很困难,有时会令人困惑。我希望你能从中得到一些东西。


“原型”一词的两种用法

“原型”这个词在 JavaScript 中可能有点令人困惑。那是因为根据上下文至少有两种使用这个词的方法:

1) “另一个对象的原型对象”

另一个对象的原型对象也被称为“内部原型”,表示为[[Prototype]],或__proto__;它们都是同一个意思。举个例子,让我们这个数组:nums = [9, 8, 7];。我们说那nums是一个数组……但为什么呢?

  1. 我们说它是一个数组,因为它是构造函数的一个实例Array构造函数只是函数,除非我们将它们与new关键字一起使用)。
  2. 我们也说它是一个数组,因为它的原型对象(又名“内部原型”)是包含在Array.prototype属性内部的对象。

2) “构造函数的原型属性

与继续nums阵列例如,Array构造函数有一个命名的属性prototype,我们可以像这样访问:Array.prototype。这个属性是 Array 实例的“内部原型”,并提供了我们用来调用数组的所有方法——例如forEachpushpopjoin等等。

因此,同样,我的 functionfoo()或任何其他函数的内部原型是包含在Function.prototype属性中的对象;换句话说,Function.prototype是任何函数的“内部原型”对象。另外,我们可以说Function构造函数有一个prototype属性,它最终是所有函数的“内部原型”。

我的意思是我们用两种不同的方式谈论一件事(原型)。在第一种方式中,我们说:对象的“原型/内部原型”,在第二种方式中,我们说:“构造函数的原型”属性。


JavaScript 类是如何创建的

在 JavaScript 中,构造函数就像其他编程语言中的。嗯,不完全是。实际上,为了类似于类,JavaScript 使用了构造函数和另一个称为原型的对象的组合。实际上每个 JavaScript 函数都会自动获得一个原型属性,因为函数可以用作构造函数或简单地用作函数。当一个函数不用作构造函数时,它的原型属性不会用于任何事情,它只是作为无用的属性悬挂在那里。

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

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

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

同样,JavaScript 中的所有构造函数都有一个prototype属性,该属性包括构造函数实例将继承的方法。

例子:

// 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
Run Code Online (Sandbox Code Playgroud)


函数和对象构造函数的关系

Object构造函数。

对象的构造是一样的人物构造以上,但它产生的对象实例,而不是人的情况。

Function构造函数。

功能的构造是一样的对象上面的构造,不同之处在于它产生功能的情况下,换句话说,它产生功能。

JavaScript 中的所有构造函数,如Person, Object, Array, Function, String, Boolean, 等等,都只是函数。由于它们的功能,这意味着他们与创造new Function的语言内部,所有功能的方法,如call()apply()来自哪里Function.prototype的。换句话说,Function.prototype是所有函数的“原型/内部原型”对象,包括构造函数和函数Function本身。

结论:

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

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

对于代码结论,请看一下对象和函数构造函数是如何在 JavaScript 内部创建的:

// Object constructor
// ==============================================
function Object() { /* ... */ }
// Object.keys()
// Object.observe()
// ...


// `Object.__proto__` (internal [[Prototype]])
// -----------------------------------------------
// Since `Object` is a function, it inherits all of Function's 
// instance methods (the ones inside of Function.prototype). 
// 
// In other words the `Object` constructor can use methods 
// like `apply()`, `call()`, `bind()`, and more.
// 
// So we can say that the Object's prototype is the 
// `Function.prototype` object.
Object.__proto__ = Function.prototype;


// `Object.prototype` (instance methods)
// -----------------------------------------------
// The Object's `prototype` property is totally different from  
// the `__proto__` property. This `prototype` property includes 
// methods that all JavaScript objects inherit. So an object
// literal like `var obj = {}` or an array like `var arr = []` 
// or even a function like `alert` can use these methods.
Object.prototype = {
  constructor: Object,
  hasOwnProperty: function() {},
  isPrototypeOf: function() {},
  //...
};



// Function constructor
// ==============================================
function Function() { /* ... */ }
// Function.call()
// Function.apply()
// ...


// [[Prototype]]  +  instance methods
// -----------------------------------------------
// Since `Function` is a function itself and at the same time 
// the constructor for other JavaScript functions, its internal
// [[Prototype]] and the `prototype` property point to the same 
// exact object.
Function.__proto__ = Function.prototype = {
  apply: function() {},
  call: function() {},
  bind: function() {},

  //...

  // Just an object literal, so it inherits the 
  // Object's instance methods.
  __proto__: Object.prototype
};
Run Code Online (Sandbox Code Playgroud)

更多资源