Object.getPrototypeOf()vs .prototype

luk*_*aus 19 javascript

我正在学习一些JS,我希望有人可以用简单的术语向我解释Object.getPrototypeOf()vs 之间的区别.prototype

function ParentClass() {}

function ChildClass() {}

ChildClass.prototype = new ParentClass();

var mychild = new ChildClass();
var myparent = new ParentClass();


# .getPrototypeOf
Object.getPrototypeOf(ChildClass.prototype)   // ParentClass {}
Object.getPrototypeOf(mychild)                // ParentClass {}
Object.getPrototypeOf(ParentClass.prototype)  // {}
Object.getPrototypeOf(myparent)               // ParentClass {}

# .prototype
ParentClass.prototype                         // ParentClass {}
myparent.prototype                            // undefined
ChildClass.prototype                          // ParentClass {}
mychild.prototype                             // undefined
Run Code Online (Sandbox Code Playgroud)

所以看起来你只能在构造函数上调用.prototype?

还有其他差异吗?

luk*_*aus 36

TL; DR

function MyConstructor() {}

var obj = new MyConstructor()

Object.getPrototypeOf(obj) === obj.prototype // false
Object.getPrototypeOf(obj) === MyConstructor.prototype // true

MyConstructor.prototype // MyConstructor {}
obj.prototype // undefined

MyConstructor.prototype.constructor === MyConstructor  // true
Object.getPrototypeOf(MyConstructor) === Function.prototype // true
Run Code Online (Sandbox Code Playgroud)

关于javascript中原型的令人困惑的部分是有两种不同的东西听起来非常相似.

创建新对象时,如果用于创建新对象的函数或对象具有.prototype方法,则引用的对象.prototype将成为新对象的原型newObj.__proto__.

听起来很复杂......让我们进一步分解.

A. .prototype属性

示例 - 使用函数作为构造函数

new函数上使用关键字时(即使用函数作为构造函数),函数的.prototype将成为新函数obj.__proto__.

让我们首先创建一个函数并检查这个.prototype属性

function MyConstructor(){
}

console.log(MyConstructor.prototype)  // {}
Run Code Online (Sandbox Code Playgroud)

等等...... MyConstructor.prototype // {}- 做了神奇的事情吗?这个空物体{}来自哪里?

这里有2件事:

  1. 每当您声明一个函数时,Javascript都会自动创建一个.prototype对象 - 自动生成.

  2. 该对象不为空.它实际上有一个属性,指向创建对象的函数(对象的'构造函数').让我们来看看:

console.log(MyConstructor.prototype.constructor); // [Function: MyConstructor]

MyConstructor.prototype.constructor === MyConstructor // true

因此,对于函数,会自动创建.prototype属性及其关联对象.

仍然困惑?让我们在那里添加一些方法,以便更容易看到发生了什么......

function MyConstructor(){
}

MyConstructor.prototype.func2 = function(){
};

console.log(MyConstructor);  // [Function: MyConstructor]
console.log(MyConstructor.prototype);  // MyConstructor { func2: [Function] }
MyConstructor.func2();  // TypeError: MyConstructor.func2 is not a function
Run Code Online (Sandbox Code Playgroud)

显然,我们可以从上面的代码中看到MyConstructor和MyConstructor.prototype是2个独立的实体.

B.对象的原型

对象的原型(不是.prototype - 参见上面的A.)是javascript用于查找和解析对象中尚未存在的方法的内容(稍后将详细介绍).

从上面继续,当我们从具有.prototype属性的函数或对象创建对象时,新创建的对象将使它object.__proto__引用此.prototype对象.

可以通过访问对象的原型

Object.getPrototypeOf(obj)

或者弃用了

obj.__proto__

示例 - 使用函数作为构造函数

让我们使用函数MyConstructor作为构造函数创建一个新对象.

function MyConstructor(){
}

var obj = new MyConstructor()

console.log(Object.getPrototypeOf(obj));  // {}
Run Code Online (Sandbox Code Playgroud)

以下是三个相关的事情:

  • MyConstructor(一个函数)
  • obj(从MyConstructor创建的对象)
  • obj.__proto__ - > MyConstructor.prototype

所以obj.__proto__MyConstructor.prototype.这是证明:

MyConstructor.prototype === Object.getPrototypeOf(obj)  // true
Run Code Online (Sandbox Code Playgroud)

让我们为MyConstructor添加一个方法

function MyConstructor(){
  this.func1 = function(){
    console.log("this is func1");
  };
}

var obj = new MyConstructor();

obj.func1();  // this is func1
Run Code Online (Sandbox Code Playgroud)

从上面你可以看到你可以调用在构造函数中声明的方法.事实上,如果我们看一下,由于javascript创建对象的方式,我们声明的方法func1实际上是obj的一部分.

console.log(obj); // MyConstructor { func1: [Function] }
Run Code Online (Sandbox Code Playgroud)

我们还可以通过将方法添加到原型中来添加obj可以使用的方法.例如

MyConstructor.prototype.func2 = function(){
  console.log("this is func2");
};

obj.func2(); // this is func2
Run Code Online (Sandbox Code Playgroud)

MyConstructor和MyConstructor.prototype方法将可用于使用此设置使用MyConstructor创建的所有对象.


有用的参考资料

面向对象JavaScript的权威指南

理解JavaScript:继承和原型链

JavaScript原型的简明英语指南

  • 这些链接本身就值得点赞(更不用说其余的优秀答案了)。很有用。 (4认同)

Bur*_*ito 6

@lukeaus 的回答非常好。对我来说,最重要的几点是:

  • 函数的 .prototype 属性与函数的原型不同。
  • .prototype 属性指定从函数构造对象的原型。
function MyConstructor() {} // automatically creates MyConstructor.prototype
// You can add methods to MyConstructor.prototype for objects to "inherit"
MyConstructor.prototype.foo = function() { console.log("do foo") }
// Or even reassign .prototype
// MyConstructor.prototype = { foo: function() { console.log("more foo?") } }
var obj = new MyConstructor()
Object.getPrototypeOf(obj) === MyConstructor.prototype // true
obj.foo()
Run Code Online (Sandbox Code Playgroud)

所以obj的原型就是MyConstructor.prototype。MyConstructor 的原型是什么?好吧,每个函数都“继承”自 Function,所以Object.getPrototypeOf(MyConstructor) === Function.prototype

作为旁注,如果你将 .prototype 分配给一些愚蠢的东西,事情就会变得很奇怪:

function MyConstructor() {}
MyConstructor.prototype = "foo" // make objects inherit from... a string?
var obj = new MyConstructor()
Object.getPrototypeOf(obj) === MyConstructor.prototype // false! 
Run Code Online (Sandbox Code Playgroud)


Joe*_*oel 6

它们肯定是不同的,但它们非常相似,因为它们都只是检索原型。您可以使用Object.getPrototypeOf().prototype来获得完全相同的结果:

\n
function Plant(type, size) {\n  this.type = type,\n  this.size = size\n};\n\nlet plant1 = new Plant("grass", "small")\n\nconsole.log(Plant.prototype === Object.getPrototypeOf(plant1)) // returns true\n
Run Code Online (Sandbox Code Playgroud)\n

区别在于,.prototype将获取指定构造函数实例的原型,而Object.getPrototypeOf()将获取括号 \xe2\x80\x94 内指定的对象的原型,无论该对象是构造函数还是(据我所知)任何其他目的。

\n

换句话说,当您这样做时MyConstructor.prototype,您不会获得 的原型,而是获得 的实例MyConstructor的原型。MyConstructor如果你想要 的原型MyConstructor,你可以这样做

\n
Object.getPrototypeOf(MyConstructor) // preferred, or \nMyConstructor.__proto__ // bad because MDN says so\n
Run Code Online (Sandbox Code Playgroud)\n

免责声明:总体而言,我对 JS 和编程还是或多或少的新手。这个解释只是我自己尝试理解这个主题的结果。

\n