Object.getPrototypeOf()vs .prototype

时间:2016-08-03 10:10:28

标签: javascript

我正在学习一些JS,我希望有人可以用简单的术语向我解释Object.getPrototypeOf().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

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

还有其他差异吗?

6 个答案:

答案 0 :(得分:26)

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

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

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

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

甲。 .prototype属性

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

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

让我们先创建一个函数并签出这个.prototype属性

function MyConstructor(){
}

console.log(MyConstructor.prototype)  // {}

等等...... MyConstructor.prototype // {} - 做了什么神奇的事情?这个空对象{}来自哪里?

这里有两件事:

  1. 只要您声明一个函数,Javascript就会自动创建一个.prototype对象 - 自动生成。

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

  3. 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
    

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

    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));  // {}
    

    以下是三个相关的事情:

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

    所以obj.__proto__MyConstructor.prototype。以下是证据:

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

    让我们为MyConstructor添加一个方法

    function MyConstructor(){
      this.func1 = function(){
        console.log("this is func1");
      };
    }
    
    var obj = new MyConstructor();
    
    obj.func1();  // this is func1
    

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

    console.log(obj); // MyConstructor { func1: [Function] }
    

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

    MyConstructor.prototype.func2 = function(){
      console.log("this is func2");
    };
    
    obj.func2(); // this is func2
    
    使用此设置,使用MyConstructor创建的所有对象都可以使用MyConstructor和MyConstructor.prototype方法。


    有用的参考资料

    Definitive Guide to Object-Oriented JavaScript

    Understanding JavaScript: Inheritance and the prototype chain

    A Plain English Guide to JavaScript Prototypes

答案 1 :(得分:1)

function Foo() {
    // ...
}

var a = new Foo();

Object.getPrototypeOf( a ) === Foo.prototype; // true

通过调用a创建new Foo()时,发生的一件事就是a获得了[[Prototype]]对象的内部Foo.prototype链接指着。

如果您真的想深入学习JavaScript,我建议您阅读"You don't know JavaScript"系列丛书。

答案 2 :(得分:0)

Object.getPrototypeOf().prototype

  • Prototype:javascript中的每个对象都有一个原型。这仅仅是它“继承”属性和方法的另一个对象。这个概念称为原型继承,并且是javascript中唯一的继承形式。诸如JavaScript中的class关键字之类的构造仅仅是建立在该原型继承系统之上的语法糖。

    每个函数都有一个prototype对象属性。然后将此功能与new关键字一起用作构造函数时,新创建的对象将从该prototype对象继承。

  • Object.getPrototypeOf():是返回此原型对象引用的函数。我们传入一个对象作为参数,它将返回原型对象的引用。

示例:

function Dog (name) {
  this.name = name;
}

// We can put properties on the prototype of the Dog constructor
Dog.prototype.bark = function () { console.log('woof'); };

let dog = new Dog('fluffie');
// Our newly created dog now has access to this bark method via the prototype chain
dog.bark();

// With the Object.getPrototypeOf method the Dog prototype object is returned
console.log(Object.getPrototypeOf(dog));

这有什么用?

原型继承使用原型链是一个非常强大的概念。它基本上可以通过以下方式工作:

  1. 当您尝试访问属性时,它将首先在对象本身上查找该属性。
  2. 如果在对象本身上未找到该属性,它将在对象的prototype中查找。
  3. 如果在prototype上找不到该属性,它将爬上原型链,并查看对象prototype对象的prototype。这将重复直到原型链中没有更高的链(即没有更高的对象可以继承)。

这具有以下优点:

  1. 我们可以使用非常方便的函数,这些函数位于本地JS对象上。例如,在Object.prototypeArray.prototype上有许多函数为我们提供了很多功能。例如,我们可以通过原型继承在任何数组上使用Array.prototype的功能。
  2. 我们可以定义自己的原型并从这些原型扩展。从我们自己定义的原型扩展,使我们能够在创建对象时立即提供对象功能。

答案 3 :(得分:0)

一种 prototype 是一种机制,JavaScript对象通过该机制彼此继承功能。 [1]

Object.getPrototypeOf-这将返回给定对象的原型。 [2]

以下代码定义了一个构造函数,该函数可以通过将关键字new放在调用之前来构建对象:

function Cat(name) {
    this.name = name;
}

Cat.prototype.meow = function (sound) {
    console.log(`Meow ${sound}`);
};

let cat = new Cat("Garfield");

构造函数会自动获得名为prototype属性,默认情况下,该属性保存一个从Object.prototype派生的普通的空对象。可以覆盖此属性,也可以像前面的代码一样添加属性。

  

理解原型方法之间的区别至关重要   与构造函数(通过其原型属性)相关联,并且与   对象具有原型(可通过Object.getPrototypeOf 找到)。

构造函数的实际原型为Function.prototype,因为构造函数 是功能。它的prototype属性保存用于实例的原型 通过它创建的。

希望在这一点上,下面的代码将使之前所说的清楚:

// This is a Cat object
> cat
Cat {name: "Garfield"}

> cat.prototype // notice that this object does not have the prototype property
undefined

// this is the constructor function
> Cat
ƒ Cat(name) {
    this.name = name;
}

// this is the prototype property of a constructor
> Cat.prototype
{meow: ƒ, constructor: ƒ}
meow: ƒ (sound)
constructor: ƒ Cat(name)
__proto__: Object

// this is true as previously stated
> Object.getPrototypeOf(Cat) == Function.prototype 
true

// this is true since the property prototype of a constructor is the
// prototype that objects created from it will have
> Object.getPrototypeOf(cat) == Cat.prototype
true

// Finally the prototype of the prototype property of a constructor
// is the same as Object.prototype
> Object.getPrototypeOf(Cat.prototype) == Object.prototype
true

其他信息

ES6中引入的

JS类主要是对JavaScript现有的基于原型的继承的语法糖。 类语法不会向JavaScript引入新的面向对象的继承模型。

因此,Cat的先前定义等同于以下内容:

class Cat {
    constructor(name) {
        this.name = name;
    }

    meow(sound) {
        console.log(`Meow ${this.sound}`);
    }
}

答案 4 :(得分:0)

@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()

因此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! 

答案 5 :(得分:-1)

只有一个区别,方法Object.getPrototypeOf获取对象的构造函数,然后返回其原型,而prototype属性不执行任何操作(返回自身)。 (好吧,prototype可以是任何东西,但如果它的对象是一个类,那么prototype肯定应该是一个对象。)。