这张图再次表明,每个对象都有一个原型。构造函数 function Foo也有自己的__proto__,也就是function .prototype, 而它又通过__proto__属性再次引用 Object.prototype。因此,重复,Foo。原型只是一个显式 Foo的属性,引用b和c对象的原型。

var b = new Foo(20);
var c = new Foo(30);

__proto__和prototype之间有什么区别?

这一数据来自dmitrysoshnikov.com网站。

注:上述2010年的文章现在有第二版(2017年)。


当前回答

'use strict'
function A() {}
var a = new A();
class B extends A {}
var b = new B();
console.log('====='); // =====
console.log(B.__proto__ === A); // true
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(b.__proto__ === B.prototype); // true
console.log(a.__proto__ === A.prototype); // true
console.log(A.__proto__ === Function.__proto__); // true
console.log(Object.__proto__ === Function.__proto__); // true
console.log(Object.prototype === Function.__proto__.__proto__); // true
console.log(Object.prototype.__proto__ === null); // true

在JavaScript中,每个对象(函数也是对象!)都有__proto__属性,该属性是对其原型的引用。

当我们使用new操作符和构造函数一起创建一个新对象时, 新对象的__proto__属性将被设置为构造函数的prototype属性, 然后构造函数将由new对象调用, 在这个过程中,“this”将是构造函数作用域中对新对象的引用,最终返回新对象。

构造函数的prototype是__proto__属性,构造函数的prototype属性是work with new操作符。

构造函数必须是函数,但函数并不总是构造函数,即使它具有prototype属性。

Prototype chain实际上是对象的__proto__属性,用于引用其原型, 以及原型的__proto__属性来引用原型的原型,等等, 直到引用Object的原型的__proto__属性,该属性引用为null。

例如:

console.log(a.constructor === A); // true
// "a" don't have constructor,
// so it reference to A.prototype by its ``__proto__`` property,
// and found constructor is reference to A

[[Prototype]]和__proto__属性实际上是一样的。

我们可以使用Object的getPrototypeOf方法来获取某个对象的原型。

console.log(Object.getPrototypeOf(a) === a.__proto__); // true

我们编写的任何函数都可以用new操作符创建一个对象, 这些函数中的任何一个都可以是构造函数。

其他回答

对于任何想要了解原型继承的人来说,这都是一个非常重要的问题。根据我的理解,默认情况下,当从函数中使用new创建对象时,prototype会被赋值,因为function定义了prototype对象:

function protofoo(){
}
var protofoo1 = new protofoo();
console.log(protofoo.prototype.toString()); //[object Object]

当我们创建一个普通的对象,没有new,即显式地从一个函数,它没有原型,但它有一个空的原型,可以分配一个原型。

var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

我们可以使用Object。创建以显式链接对象。

// we can create `bar` and link it to `foo`
var bar = Object.create( foo );
bar.fooprops= "We checking prototypes";
console.log(bar.__proto__); // "foo"
console.log(bar.fooprops); // "We checking prototypes"
console.log(bar.check); // 10 is delegated to `foo`

为了解释,让我们创建一个函数

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

当JavaScript执行这段代码时,它将prototype属性添加到。prototype属性是一个具有两个属性的对象:

构造函数 __proto__

所以当我们这样做的时候

a.原型它返回

     constructor: a  // function definition
    __proto__: Object

现在你可以看到构造函数就是函数a本身 而__proto__指向JavaScript的根对象。

让我们看看当我们使用带有new关键字的函数时会发生什么。

var b = new a ('JavaScript');

当JavaScript执行这段代码时,它会做4件事:

它创建了一个新对象,一个空对象// {} 它在b上创建__proto__,并使其指向a.prototype,因此b.__proto__ === a.prototype 它使用新创建的对象(在步骤#1中创建)作为上下文(this)执行a.p otype.constructor(这是函数a的定义),因此作为'JavaScript'传递的name属性(它被添加到this)被添加到新创建的对象。 它返回新创建的对象(在步骤#1中创建),因此var b被分配给新创建的对象。

现在如果我们添加a.prototype。car = "BMW"然后 b.car,输出“BMW”出现。

这是因为当JavaScript执行这段代码时,它在b上搜索car属性,它没有发现,然后JavaScript使用b.__proto__(在步骤#2中指向“a.prototype”)并找到car属性,因此返回“BMW”。

除了以上这些精彩的答案外,我还想说得更清楚一点:

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

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

实例有__proto__,类有prototype。

我知道,我迟到了,但让我试着简化一下。

假设有一个函数

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);

Foo函数将有一个原型对象链接。所以,无论何时我们在JavaScript中创建一个函数,它总是有一个原型对象链接到它。

现在让我们继续使用函数Foo创建两个对象。

    var a = new Foo("a");
    var b = new Foo("b");
    console.log(a.message);
    console.log(b.message);

现在我们有两个对象,对象a和对象b。它们都被创建了 使用构造函数Foo。记住,构造函数在这里只是一个词。 对象a和b都有message属性的副本。 这两个对象a和b链接到构造函数Foo的原型对象。 在对象a和b上,我们可以在所有浏览器中使用__proto__属性访问Foo prototype,在IE中我们可以使用Object.getPrototypeOf(a)或Object.getPrototypeOf(b)

现在,Foo。Prototype, a.__proto__和b.__proto__都表示同一个对象。

    b.__proto__ === Object.getPrototypeOf(a);
    a.__proto__ ===  Foo.prototype;
    a.constructor.prototype  === a.__proto__;

所有这些都将返回true。

如我们所知,在JavaScript中属性可以动态添加。我们可以向对象添加属性

    Foo.prototype.Greet = function(){

         console.log(this.message);
    }
    a.Greet();//a
    b.Greet();//b
    a.constructor.prototype.Greet();//undefined 

如你所见,我们在Foo中添加了Greet()方法。但它可以在a和b或任何其他使用Foo构造的对象中访问。

在执行a.Greet()时,JavaScript将首先在对象a的属性列表中搜索Greet。如果没有找到,它将在a. Since a.__proto__和Foo的__proto__链中上升。prototype是同一个对象,JavaScript会找到Greet()方法并执行它。

我希望,现在prototype和__proto__被简化了一点。

一种很好的思考方式是……

Prototype用于构造函数。它真的应该被称为“prototypeToInstall”,因为它就是这样的。

__proto__是对象上的“已安装原型”(由上述构造函数()函数创建/安装在对象上)