这张图再次表明,每个对象都有一个原型。构造函数 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年)。


当前回答

我碰巧从You Don't Know JS: this & Object prototyping中学习原型,这是一本很好的书,可以理解设计的底层,澄清许多误解(这就是为什么我试图避免使用继承和instanceof之类的东西)。

但我和这里的人有同样的问题。有几个答案真的很有帮助,很有启发性。我也很乐意分享我的理解。


什么是原型?

JavaScript中的对象有一个内部属性,在规范中表示为[[Prototype]],它只是对另一个对象的引用。几乎所有对象在创建时都会被赋予这个属性的非空值。

如何获得一个对象的原型?

通过__proto__或Object.getPrototypeOf

var a = { name: "wendi" };
a.__proto__ === Object.prototype // true
Object.getPrototypeOf(a) === Object.prototype // true

function Foo() {};
var b = new Foo();
b.__proto__ === Foo.prototype
b.__proto__.__proto__ === Object.prototype

原型是什么?

原型是作为函数的特殊属性自动创建的对象,用于建立委托(继承)链,即原型链。

当我们创建一个函数a时,prototype会自动作为a上的一个特殊属性创建,并将上的函数代码保存为prototype上的构造函数。

function Foo() {};
Foo.prototype // Object {constructor: function}
Foo.prototype.constructor === Foo // true

我想把这个属性作为存储函数对象的属性(包括方法)的地方。这也是JS中的实用函数被定义为Array.prototype.forEach()、Function.prototype.bind()、Object.prototype.toString()的原因。

为什么要强调函数的性质?

{}.prototype // undefined;
(function(){}).prototype // Object {constructor: function}

// The example above shows object does not have the prototype property.
// But we have Object.prototype, which implies an interesting fact that
typeof Object === "function"
var obj = new Object();

Arary, Function, Objectare都是函数。我必须承认,这刷新了我对JS的印象。我知道函数是JS中的一等公民,但它似乎是建立在函数之上的。

__proto__和prototype有什么区别?

__proto__a引用作用于每个对象以引用其[[Prototype]]属性。

Prototype是作为函数的特殊属性自动创建的对象,用于存储函数对象的属性(包括方法)。

有了这两个,我们可以在脑海中绘制出原型链。如图所示:

function Foo() {}
var b = new Foo();

b.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true

其他回答

在声明函数时创建Prototype属性。

例如:

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

的人。Prototype属性在声明上述函数后在内部创建。 可以向Person添加许多属性。由使用new Person()创建的Person实例共享的原型。

// adds a new method age to the Person.prototype Object.
Person.prototype.age = function(){return date-dob}; 

值得注意的是,Person。prototype默认是Object字面量(可以根据需要更改)。

使用new Person()创建的每个实例都有一个指向Person.prototype的__proto__属性。这是用于遍历查找特定对象的属性的链。

var person1 = new Person(somedate);
var person2 = new Person(somedate);

创建2个Person实例,这2个对象可以调用Person的age方法。原型作为人物1。年龄,person2.age。

在你的问题的上图中,你可以看到Foo是一个函数对象,因此它有一个__proto__链接到函数。prototype是Object的一个实例,并且有一个指向Object.prototype的__proto__链接。原型链接在这里以对象中的__proto__结束。原型指向null。

任何对象都可以访问其原型链中的所有属性,通过__proto__链接,从而形成原型继承的基础。

__proto__不是访问原型链的标准方法,标准但类似的方法是使用Object.getPrototypeOf(obj)。

下面的instanceof操作符代码提供了更好的理解:

当一个对象是一个类的实例时,更具体地说,如果Class,则返回true。prototype是在该对象的原型链中找到的,那么该对象就是该类的实例。

function instanceOf(Func){
  var obj = this;
  while(obj !== null){
    if(Object.getPrototypeOf(obj) === Func.prototype)
      return true;
    obj = Object.getPrototypeOf(obj);
  }
  return false;
}      

上面的方法可以调用为:instanceOf。调用(object, Class),如果object是Class的实例则返回true。

Prototype VS. __proto__ VS. [[Prototype]]

在创建函数时,会自动创建一个名为prototype的属性对象(不是您自己创建的),并将其附加到函数对象(构造函数)。注意:这个新的原型对象也指向本机JavaScript对象,或者有一个内部私有链接。

例子:

function Foo () {
    this.name = 'John Doe';
}

// Foo has an object property called prototype.
// prototype was created automatically when we declared the function Foo.
Foo.hasOwnProperty('prototype'); // true

// Now, we can assign properties and methods to it:
Foo.prototype.myName = function () {
    return 'My name is ' + this.name;
}

如果你使用new关键字从Foo中创建一个新对象,你基本上是在创建一个新对象,它有一个内部或私有的链接到我们之前讨论过的函数Foo的原型:

var b = new Foo();

b.[[Prototype]] === Foo.prototype  // true

到该函数对象的私有链接称为双括号prototype或[[prototype]]。许多浏览器为我们提供了一个公共链接,称为__proto__!

更具体地说,__proto__实际上是一个属于原生JavaScript对象的getter函数。它返回this绑定的内部私有原型链接(返回b的[[prototype]]):

b.__proto__ === Foo.prototype // true

值得注意的是,ECMAScript5的启动,你也可以使用getPrototypeOf方法来获得内部的私有链接:

Object.getPrototypeOf(b) === b.__proto__ // true

注意:这个答案并不打算涵盖创建新对象或新构造函数的整个过程,而是帮助更好地理解__proto__、prototype和[[prototype]]以及它是如何工作的。

定义

(括号()内的数字是一个“链接”到下面写的代码)

原型-一个对象,包括: =>函数(3) prototype(5) 通过此构造函数(1)创建或将创建的对象(4) =>构造函数本身(1) =>此特定对象的__proto__ (prototype对象)

__proto__ (dandor prototype ?) -通过特定构造函数(1)创建的任何对象(2)和该构造函数的原型对象的属性(5)之间的链接,允许每个创建的对象(2)访问原型的函数和方法(4)(__proto__默认包含在JS中的每个对象中)

代码说明

1.

    function Person (name, age) {
        this.name = name;
        this.age = age;  

    } 

2.

    var John = new Person(‘John’, 37);
    // John is an object

3.

    Person.prototype.getOlder = function() {
        this.age++;
    }
    // getOlder is a key that has a value of the function

4.

    John.getOlder();

5.

    Person.prototype;

我试试四年级的解释:

事情很简单。原型是如何构建某样东西的例子。所以:

我是一个函数,我构建与原型相似的新对象 我是一个对象,我是用我的__proto__作为例子来构建的

证明:

function Foo() { }

var bar = new Foo()

// `bar` is constructed from how Foo knows to construct objects
bar.__proto__ === Foo.prototype // => true

// bar is an instance - it does not know how to create objects
bar.prototype // => undefined

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

假设有一个函数

    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__被简化了一点。