__proto__ VS. JavaScript中的原型

时间:2012-03-31 21:13:14

标签: javascript prototype javascript-objects prototypal-inheritance

  

此图再次显示每个对象都有一个原型。构造函数   函数Foo也有自己的__proto__,它是Function.prototype,   而且它又通过其__proto__属性再次引用   Object.prototype。因此,重复,Foo.prototype只是一个明确的   Foo的属性,指的是b和c对象的原型。

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

__proto__prototype属性之间有什么区别?

enter image description here

该图来自here

31 个答案:

答案 0 :(得分:678)

__proto__是查找链中用于解析方法等的实际对象。prototype是使用{创建对象时用于构建__proto__的对象{1}}:

new

答案 1 :(得分:308)

prototype是Function对象的属性。它是由该函数构造的对象的原型。

__proto__是对象的内部属性,指向其原型。目前的标准提供了等效的Object.getPrototypeOf(O)方法,但事实上的标准__proto__更快。

您可以通过将函数的instanceof与对象的prototype链进行比较来找到__proto__关系,并且可以通过更改prototype来打破这些关系。

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var myPoint = new Point();

// the following are all true
myPoint.__proto__ == Point.prototype
myPoint.__proto__.__proto__ == Object.prototype
myPoint instanceof Point;
myPoint instanceof Object;

这里Point是一个构造函数,它在程序上构建一个对象(数据结构)。 myPoint是由Point()构建的对象,因此当时Point.prototype会保存到myPoint.__proto__

答案 2 :(得分:107)

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

例如:

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

一旦声明了上面的函数,就会在内部创建Person.prototype属性。 可以将许多属性添加到Person.prototype中,这些属性由使用新Person()创建的Person实例共享。

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

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

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

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

创建2个Person实例,这2个对象可以将Person.prototype的age属性称为person1.age,person2.age。

在上图中,您可以看到Foo是一个Function对象,因此它有一个__proto__指向Function.prototype的链接,而该链接又是Object的一个实例,并且有一个__proto__链接Object.prototype中。 proto链接在此结束,Object.prototype中的__proto__指向null。

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

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

以下instanceof运算符的代码可以更好地理解:

object instanceof当一个对象是一个Class的实例时,类运算符返回true,更具体地说,如果在该对象的proto链中找到Class.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.call(object,Class)如果object是Class的实例,则返回true。

答案 3 :(得分:60)

想到它的好方法是......

prototype函数使用

constructor()。它应该被称为"prototypeToInstall",因为它就是它。

__proto__是对象的“已安装的原型”(从constructor()函数创建/安装在对象上)

答案 4 :(得分:42)

Prototype VS. __proto__ VS. [[Prototype]]

创建函数时,会自动创建一个名为 prototype 的属性对象(您自己没有创建它)并且正在附加到函数对象(constructor)。
注意:这个新的原型对象也指向或具有本机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;
}

如果您要使用Foo关键字从new创建新对象,则基本上创建一个具有内部或私有链接我们之前讨论过的函数原型Foo

var b = new Foo();

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

<小时/> 与该函数对象的私有链接称为双括号原型或仅[[Prototype]]。许多浏览器都为我们提供了一个名为__proto__公开链接!

更具体地说,__proto__实际上是属于本机JavaScript对象的getter function。它返回this绑定所在的内部 - 私有原型链接(返回[[Prototype]]的{​​{1}}):

b

值得注意的是,从b.__proto__ === Foo.prototype // true 开始,您还可以使用getPrototypeOf方法获取内部私有链接:

ECMAScript5

<小时/> 注意:此答案并不打算涵盖创建新对象或新构造函数的整个过程,而是为了更好地理解Object.getPrototypeOf(b) === b.__proto__ // true __proto__和{{1它是如何工作的。

答案 5 :(得分:42)

解释让我们创建一个函数

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

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

  1. constructor
  2. __proto__
  3. 所以当我们做的时候

    a.prototype它返回

         constructor: a  // function definition
        __proto__: Object
    

    现在您可以看到constructor只是函数a本身 并且__proto__指向JavaScript的根级Object

    让我们看看当a函数与new关键字一起使用时会发生什么。

    var b = new a ('JavaScript');
    

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

    1. 它创建一个新对象,一个空对象// {}
    2. 它会在__proto__上创建b并指向a.prototype所以b.__proto__ === a.prototype
    3. 它使用新创建的对象(在步骤#1中创建)作为其上下文(this)执行a.prototype.constructor(函数a的定义),因此传递了name属性因为'JavaScript'(添加到this)被添加到新创建的对象中。
    4. 返回新创建的对象(在步骤#1中创建),因此var b被分配给新创建的对象。
    5. 现在,如果我们添加a.prototype.car = "BMW"并执行此操作 b.car,输出“宝马”。

      这是因为当JavaScript执行此代码时,它在car上搜索了b属性,但未找到使用的b.__proto__ JavaScript(指向'a.prototype) '在步骤#2中)并找到car属性,所以返回“宝马”。

答案 6 :(得分:27)

除了上面的答案之外,还要清楚一点:

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

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

实例 __ proto __ 原型

答案 7 :(得分:8)

在JavaScript中,函数可以用作构造函数。这意味着我们可以使用new关键字从中创建对象。每个构造函数都带有一个与它们链接在一起的内置对象。这个内置对象称为原型。的 Instances of a constructor function use __proto__ to access the prototype property of its constructor function.

prototype diagram

  1. 首先我们创建了一个构造函数:function Foo(){}。要清楚,Foo只是另一个功能。但我们可以使用new关键字从中创建一个对象。这就是我们称之为构造函数

  2. 的原因
  3. 每个函数都有一个唯一的属性,称为prototype属性。因此,构造函数Foo有一个原型属性,指向其原型,Foo.prototype(见图)。

  4. 构造函数本身就是一个函数,它是一个名为[[Function]]构造函数的系统构造函数的实例。所以我们可以说function Foo是由[[Function]]构造函数构造的。因此,我们__proto__的{​​{1}}将指向其构造函数的原型,即Foo function

  5. Function.prototype本身只不过是一个从另一个名为Function.prototype的系统构造函数构造的对象。因此,[[Object]][[Object]]的构造函数。因此,我们可以说Function.prototypeFunction.prototype的一个实例。因此[[Object]] __proto__指向Function.prototype

  6. Object.prototype是站在原型链中的最后一个人。我的意思是它还没有建成。它已经存在于系统中。因此Object.prototype指向__proto__

  7. 现在我们来到null的实例。当我们使用Foo创建实例时,它会创建一个新对象,该对象是new Foo()的实例。这意味着Foo是这些实例的构造函数。这里我们创建了两个实例(x和y)。因此,Foo x和y指向__proto__

答案 8 :(得分:7)

我正好从You Don't Know JS: this & Object Prototypes学习原型,这是一本很好的书,可以理解下面的设计并澄清如此多的误解(这就是为什么我试图避免使用继承和事物比如instanceof)。

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

什么是原型?

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

如何获取对象的原型?

通过__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

什么是prototype

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

当我们创建一个函数a时,prototype会自动创建为a上的特殊属性,并将函数代码保存为constructor 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();

因此,AraryFunctionObject都是功能。我应该承认这会刷新我对JS的印象。我知道函数是JS中的一等公民,但它似乎是建立在函数之上的。

__proto__prototype之间有什么区别?

__proto__引用适用于每个对象,以引用其[[Prototype]]属性。

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

通过这两个,我们可以在精神上绘制原型链。如下图所示:

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

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

答案 9 :(得分:6)

理解它的另一个好方法:

var foo = {}

/* 
foo.constructor is Object, so foo.constructor.prototype is actually 
Object.prototype; Object.prototype in return is what foo.__proto__ links to. 
*/
console.log(foo.constructor.prototype === foo.__proto__);
// this proves what the above comment proclaims: Both statements evaluate to true.
console.log(foo.__proto__ === Object.prototype);
console.log(foo.constructor.prototype === Object.prototype);

仅支持IE11 __proto__之后。在该版本之前,例如IE9,您可以使用constructor获取__proto__

答案 10 :(得分:5)

原型

prototype是Function的一个属性。它是使用带有new关键字的(构造函数)函数创建对象的蓝图。

__原__

__proto__用于查找链中以解析方法,属性。创建对象时(使用带有new关键字的构造函数),__proto__设置为(构造函数)Function.prototype

function Robot(name) {
    this.name = name;
}
var robot = new Robot();

// the following are true   
robot.__proto__ == Robot.prototype
robot.__proto__.__proto__ == Object.prototype

这是解释混淆的我(想象)解释:

想象一下,有一个与功能相关的想象类(蓝图/ coockie切割器)。该虚构类用于实例化对象。 prototype是扩展机制(C#中的扩展方法,或Swift扩展),用于向该虚构类添加内容。

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

以上可以想象为:

// imaginary class
class Robot extends Object{

    static prototype = Robot.class  
    // Robot.prototype is the way to add things to Robot class
    // since Robot extends Object, therefore Robot.prototype.__proto__ == Object.prototype

    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

} 

所以,

var robot = new Robot();

robot.__proto__ == Robot.prototype
robot.prototype == undefined
robot.__proto__.__proto__ == Object.prototype

现在将方法添加到Robot的prototype

Robot.prototype.move(x, y) = function(x, y){ Robot.position.x = x; Robot.position.y = y};
// Robot.prototype.move(x, y) ===(imagining)===> Robot.class.move(x, y)

以上可以想象为Robot类的扩展:

// Swift way of extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}

反过来,

// imaginary class
class Robot{

    static prototype = Robot.class // Robot.prototype way to extend Robot class
    var __proto__;

    var name = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

    // added by prototype (as like C# extension method)
    function move(x, y){ 
        Robot.position.x = x; Robot.position.y = y
    };
}

答案 11 :(得分:4)

简单地说:

> var a = 1
undefined
> a.__proto__
[Number: 0]
> Number.prototype
[Number: 0]
> Number.prototype === a.__proto__
true

这允许您将属性附加到X.prototype AFTER类型的对象已被实例化,并且它们仍然可以通过__proto__引用访问这些新属性,Javascript引擎用它来走原型链。 / p>

答案 12 :(得分:3)

我认为您需要了解 __proto__[[prototype]]prototype 之间的区别。

接受的答案是有帮助的,但它可能(不完美地)暗示 __proto__仅与在构造函数上使用 new 创建的对象相关的东西,这不是真的。

更准确地说:__proto__ 存在于每个对象上

  • 但是 __proto__ 到底是什么?

    • 嗯,它是一个引用另一个对象的对象,该对象也是所有对象的一个​​属性,称为 [[prototype]]
    • 值得一提的是,[[prototype]] 是 JavaScript 在内部处理的,开发人员无法访问
  • 为什么我们需要属性 [[prototype]](所有对象的)的引用对象?

    • 因为 JavaScript 不允许直接获取/设置 [[prototype]],所以它允许它通过一个中间层 __proto__。因此,您可以将 __proto__ 视为 [[prototype]] 属性的 getter/setter。
  • 那么 prototype 是什么?

    • 它是特定于函数的东西(最初在Function中定义,即Function.prototype,然后由原型继承 strong> 创建函数,然后这些函数再次将其提供给它们的子代,形成一个原型继承链)。

    • 当父函数使用 prototype 运行时,JavaScript 使用父函数的 [[prototype]] 来设置其子函数的 new(记住我们说过 all 对象有 [[prototype]]?好吧,函数也是对象,所以它们也有 [[prototype]])。所以当一个函数(子)的 [[prototype]] 被设置为另一个函数(父)的 prototype 时,你最终会得到这个:

      let child = new Parent();
      child.__proto__ === Parent.prototype // --> true.
      

      (记住 child.[[prototype]] 是不可访问的,所以我们使用 __proto__ 检查了它。)


注意 1: 每当属性不在子级中时,它的 __proto__ 将被“隐式”搜索。因此,例如,如果 child.myprop 返回一个值,您不能说“myprop”是子项的属性,还是其父项原型之一的属性。这也意味着您永远不需要自己做类似的事情:child.__proto__.__proto__.myprop,只需 child.myprop 会自动为您做。

注意 2: 即使父级的原型中有项目,子级自己的 prototype 最初也将是一个空对象。如果您想进一步扩展继承链(将 child[ren] 添加到 child),您可以向其中添加项目或手动从中删除项目。或者它可以被隐式操作,例如,使用 class syntax。)

注意 3: __proto__ 有点outdated,现代 JavaScript 建议使用 Object.setPrototypeOfObject.getPrototypeOf 代替.)

答案 13 :(得分:3)

摘要:

对象的__proto__属性是映射到该对象的构造函数的prototype的属性。换句话说:

instance.__proto__ === constructor.prototype // true

这用于形成对象的prototype链。 prototype链是对象属性的查找机制。如果访问了对象的属性,JavaScript将首先查看对象本身。如果在该位置找不到该属性,它将一直攀升至protochain,直到找到(或找不到)

示例:

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

Person.prototype.age = 25;

const willem = new Person('Willem');

console.log(willem.__proto__ === Person.prototype); // the __proto__ property on the instance refers to the prototype of the constructor

console.log(willem.age); // 25 doesn't find it at willem object but is present at prototype
console.log(willem.__proto__.age); // now we are directly accessing the prototype of the Person function 

我们的第一个日志结果为true,这是因为如上所述,构造函数创建的实例的__proto__属性引用了构造函数的prototype属性。请记住,在JavaScript中,函数也是对象。对象可以具有属性,任何函数的默认属性都是一个名为prototype的属性。

然后,当将此函数用作构造函数时,从该函数实例化的对象将收到一个名为__proto__的属性。这个__proto__属性是指构造函数的prototype属性(默认情况下每个函数都具有)。

这为什么有用?

JavaScript在Objects上查找属性时具有一种机制,称为“原型继承” ,这基本上是它的作用:

  • 首先,检查属性是否位于Object本身上。如果是这样,则返回此属性。
  • 如果属性不在对象本身上,它将“爬升原型链”。它基本上查看由__proto__属性引用的对象。在那里,它检查属性在__proto__所引用的对象上是否可用。
  • 如果该属性不在__proto__对象上,它将沿着__proto__链向上攀升,一直到Object对象。
  • 如果找不到对象及其prototype链上任何位置的属性,它将返回undefined

例如:

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

let mySelf = new Person('Willem');

console.log(mySelf.__proto__ === Person.prototype);

console.log(mySelf.__proto__.__proto__ === Object.prototype);

答案 14 :(得分:3)

我知道,我迟到但让我试着简化它。

让我们说有一个功能

    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);
  1. 现在我们有两个对象,对象a和对象b。两者都是创造的 使用构造函数Foo。请记住构造函数在这里只是一个词。
  2. 对象a和b都有一个消息属性的副本。
  3. 这两个对象a和b链接到构造函数Foo的原型对象。
  4. 在对象a和b上,我们可以在所有浏览器中使用 proto 属性访问Foo原型,在IE中我们可以使用Object.getPrototypeOf(a)或Object.getPrototypeOf(b)
  5. 现在,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.prototype中添加了Greet()方法,但它可以在a和b或使用Foo构造的任何其他对象中访问。

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

    我希望,现在原型和 proto 有点简化了。

答案 15 :(得分:3)

Prototype或Object.prototype 是对象文字的属性。它表示 Object 原型对象,您可以覆盖该对象以在原型链中进一步添加更多属性或方法。

__ proto __ 是一个访问器属性(get和set函数),它公开了访问它的对象的内部原型。

参考文献:

  1. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype
  2. http://www.w3schools.com/js/js_object_prototypes.asp

  3. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto

答案 16 :(得分:2)

解释

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

prototype - 包含以下内容的对象:
 =&GT;功能(3)    特别是ConstructorFunction.prototype(5),每个人都可以访问    object(4)通过这个构造函数(1)创建或创建  =&GT;构造函数本身(1)
 =&GT;此特定对象的__proto__(原型对象)

__proto__ (dandor proto?) - 通过特定构造函数(1)创建的任何对象(2)与该构造函数的原型对象属性(5)的链接BETWEEN这允许每个创建的对象(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;

答案 17 :(得分:2)

 JavaScript prototype vs __prototype__

'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属性进行设置, 然后构造函数将被新对象调用, 在该过程中,“ this”将在构造函数范围内引用新对象,最后返回新对象。

构造函数的原型是__proto__属性,构造函数的prototype属性是new运算符的作用。

构造函数必须是一个函数,但即使具有prototype属性,函数也不一定是构造函数。

原型链实际上是对象的__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运算符来创建对象, 因此这些函数中的任何一个都可以成为构造函数。

答案 18 :(得分:1)

您创建的每个函数都有一个名为__proto__的属性,它作为一个空对象开始。在使用此函数作为构造函数,即使用&#39; new&#39;之前,此属性是没用的。关键词。

这经常与对象的prototype属性混淆。有些人可能会感到困惑,除了对象的prototype属性可能会使它们成为对象的原型。但事实并非如此。 __proto__用于获取从函数构造函数创建的对象的function Person(name){ this.name = name }; var eve = new Person("Eve"); console.log(eve.__proto__ == Person.prototype) // true // this is exactly what prototype does, made Person.prototype equal to eve.__proto__

在上面的例子中:

&#13;
&#13;
{{1}}
&#13;
&#13;
&#13;

我希望这是有道理的。

答案 19 :(得分:1)

[[原型]]:

[[Prototype]]是JS中对象的内部隐藏属性,它是对另一个对象的引用。创建时的每个对象都会收到[[Prototype]]的非空值。请记住,当我们引用myObject.a之类的对象的属性时,将调用[[Get]]操作。如果对象本身具有属性,则将使用该属性。

let myObject= {
    a: 2
};

console.log(myObject.a);            // 2

但是,如果对象本身直接不具有请求的属性,则[[Get]]操作将继续跟随对象的[[Prototype]]链接。该过程将继续进行,直到找到匹配的属性名称或[[Prototype]]链结束(在内置Object.prototype中)为止。如果找不到匹配的属性,则将返回undefined。 Object.create(specifiedObject)创建一个具有[[Prototype]]链接到指定对象的对象。

let anotherObject= {
    a: 2
};

// create an object linked to anotherObject
let myObject= Object.create(anotherObject);
console.log(myObject.a);                // 2

for..in循环和in运算符都使用[[Prototype]]链查找过程。因此,如果我们使用for..in循环来迭代对象的属性,则通过该对象的[[Prototype]]链可以达到的所有可枚举的属性也将与该对象本身的可枚举的属性一起枚举。并且当使用in运算符测试对象上是否存在属性时,in运算符将通过对象的[[Prototype]]链接检查所有属性,而不管它们的可枚举性。

// for..in loop uses [[Prototype]] chain lookup process
let anotherObject= {
    a: 2
};

let myObject= Object.create(anotherObject);

for(let k in myObject) {
    console.log("found: " + k);            // found: a
}

// in operator uses [[Prototype]] chain lookup process
console.log("a" in myObject);              // true

.prototype:

.prototype是JS中函数的属性,它是指具有构造函数属性的对象,该对象存储函数对象的所有属性(和方法)。

let foo= function(){}

console.log(foo.prototype);        
// returns {constructor: f} object which now contains all the default properties

foo.id= "Walter White";

foo.job= "teacher";

console.log(foo.prototype);       
// returns {constructor: f} object which now contains all the default properties and 2 more properties that we added to the fn object
/*
{constructor: f}
    constructor: f()
        id: "Walter White"
        job: "teacher"
        arguments: null
        caller: null
        length: 0
        name: "foo"
        prototype: {constructor: f}
        __proto__: f()
        [[FunctionLocation]]: VM789:1
        [[Scopes]]: Scopes[2]
    __proto__: Object

*/

但是JS中的普通对象没有.prototype属性。我们知道Object.prototype是JS中所有对象的根对象。所以很明显Object是一个函数,即typeof Object ===“ function”。这意味着我们还可以通过Object函数创建对象,例如让myObj = new Object()。同样,Array,Function也是函数,因此我们可以使用Array.prototype,Function.prototype来存储数组和函数的所有常规属性。因此,我们可以说JS是基于函数构建的。

{}.prototype;                            // SyntaxError: Unexpected token '.'

(function(){}).prototype;                // {constructor: f}

如果我们从一个函数创建对象,也要使用new运算符,然后那些新创建的对象的内部隐藏的[[Prototype]]属性将指向原始函数的.prototype属性所引用的对象。在下面的代码中,我们创建了一个对象,它来自fn,Letter和两个属性,一个添加到fn对象,另一个添加到fn的原型对象。现在,如果我们尝试访问新创建的对象的两个属性,那么我们将只能访问添加到函数原型对象的属性。这是因为该函数的原型对象现在位于新创建的对象a的[[Prototype]]链上。

let Letter= function(){}

let a= new Letter();

Letter.from= "Albuquerque";

Letter.prototype.to= "New Hampshire";

console.log(a.from);                // undefined

console.log(a.to);                  // New Hampshire

.__proto__:

.__proto__是JS中对象的属性,它引用[[Prototype]]链中的另一个对象。我们知道[[Prototype]]是JS中对象的内部隐藏属性,它引用[[Prototype]]链中的另一个对象。我们可以通过两种方法获取或设置内部[[Prototype]]属性所引用的对象

  1. Object.getPrototypeOf(obj) / Object.setPrototypeOf(obj)

  2. obj.__proto__

我们可以使用.__proto__.__proto__. .遍历[[Prototype]]链。与.constructor,.toString()、. isPrototypeOf()一起,我们的dunder原型属性(__proto__)实际上存在于内置Object.prototype根对象上,但可在任何特定对象上使用。我们的.__proto__实际上是一个吸气剂/设置剂。 {。{1}}在Object.prototype中的实现如下:

.__proto__

要检索Object.defineProperty(Object.prototype, "__proto__", { get: function() { return Object.getPrototypeOf(this); }, set: function(o) { Object.setPrototypeOf(this, o); return o; } }); 的值就像调用,obj.__proto__实际上返回Object.prototype对象上存在的吸气剂fn obj.__proto__()的调用。尽管Object.getPrototypeOf(obj)是可设置的属性,但是由于性能问题,我们不应更改现有对象的[[Prototype]]。

如果我们从函数创建对象,则使用new运算符,然后这些新创建的对象的内部隐藏的[[Prototype]]属性将指向原始函数的.prototype属性所引用的对象。使用.__proto__属性,我们可以访问该对象的内部隐藏[[Prototype]]属性引用的其他对象。但是.__proto__与[[Prototype]]不同,而是它的获取者/设定者。考虑下面的代码:

__proto__

enter image description here

答案 20 :(得分:1)

这是一个非常重要的问题,与任何想了解原型继承的人有关。据我了解,默认情况下,使用函数中的new创建对象时会分配原型,因为Function具有定义的原型对象:

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

当我们创建一个没有新对象(即从函数显式)的普通对象时,它没有原型,但是有一个空的 proto ,可以为其分配原型。

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

我们可以使用Object.create显式链接对象。

// 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`

答案 21 :(得分:1)

我为自己制作了一个小图,代表以下代码片段:

var Cat = function() {}
var tom = new Cat()

Understanding __proto__ and prototype

我有一个经典的OO背景,因此以这种方式表示层次结构很有帮助。为了帮助您阅读此图,请将图像中的矩形视为JavaScript对象。是的,功能也是对象。 ;)

JavaScript中的对象具有属性,__proto__只是其中之一。

此属性背后的想法是指向(继承)层次结构中的祖先对象。

JavaScript中的根对象是Object.prototype,所有其他对象都是该对象的后代。根对象的__proto__属性是null,它代表继承链的末端。

您会注意到prototype是函数的属性。 Cat是一个函数,但是FunctionObject是(本机)函数。 tom不是函数,因此不具有此属性。

此属性背后的想法是指向将在构造中使用的对象,即,当您在该函数上调用new运算符时。

  

请注意,原型对象(黄色矩形)还有另一个称为   constructor指向各自的功能对象。对于   简洁的原因未对此进行描述。

实际上,当我们使用tom创建new Cat()对象时,创建的对象会将__proto__属性设置为构造函数的prototype对象。

最后,让我们玩一下此图。以下陈述是正确的:

  • tom.__proto__属性指向与Cat.prototype相同的对象。

  • Cat.__proto__指向Function.prototype对象,就像Function.__proto__Object.__proto__一样。

  • Cat.prototype.__proto__tom.__proto__.__proto__指向同一个对象,即Object.prototype

干杯!

答案 22 :(得分:1)

说明性示例:

function Dog(){}
Dog.prototype.bark = "woof"

let myPuppie = new Dog()

现在,myPupppie具有指向Dog.prototype的__proto__属性。

> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}

但是myPuppie没有原型属性。

> myPuppie.prototype
>> undefined

因此,mypuppie的__proto__是对用于实例化此对象的构造函数的.prototype属性的引用(并且当前myPuppie对象具有与“代理”的关系)这个__proto__对象),而myPuppie的.prototype属性完全不存在(因为我们没有设置它)。

MPJ的很好解释: proto vs prototype - Object Creation in JavaScript

答案 23 :(得分:1)

__proto__是构造prototype的基础和构造函数,例如:function human(){}具有prototype,该__proto__在新实例中通过OutDir共享。构造函数。更详细的阅读here

答案 24 :(得分:1)

我会尝试四年级的解释:

事情很简单。 prototype是应该如何构建某个东西的示例。所以:

  • 我是function,我构建的新对象类似于我的prototype

  • 我是object我是以我的__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

答案 25 :(得分:0)

(function(){ 
      let a = function(){console.log(this.b)};
      a.prototype.b = 1;
      a.__proto__.b = 2;
      let q = new a();
      console.log(a.b);
      console.log(q.b) 
    })()

尝试此代码以了解

答案 26 :(得分:0)

正如this正确陈述的那样

  

__proto__是在查找链中用于   解析方法等。prototype是用于构建的对象   __proto__用新的对象创建时:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;

我们还可以注意到,使用函数构造函数创建的对象的__proto__属性指向该相应构造函数的 prototype 属性所指向的内存位置。

如果我们更改构造函数的 prototype 的存储位置,则派生对象的__proto__仍将继续指向原始地址空间。因此,要使公用属性在继承链中可用,请始终将属性附加到构造函数 prototype 中,而不是重新初始化它(这会更改其内存地址)。

考虑以下示例:

function Human(){
    this.speed = 25;
}

var himansh = new Human();

Human.prototype.showSpeed = function(){
    return this.speed;
}

himansh.__proto__ === Human.prototype;  //true
himansh.showSpeed();    //25

//now re-initialzing the Human.prototype aka changing its memory location
Human.prototype = {lhs: 2, rhs:3}

//himansh.__proto__ will still continue to point towards the same original memory location. 

himansh.__proto__ === Human.prototype;  //false
himansh.showSpeed();    //25

答案 27 :(得分:0)

只有一个对象用于原型链接。该对象显然具有名称和值:firebase是其名称,而__proto__是其值。就是这样。

为使其更容易理解,请查看这篇文章顶部的图表(Dmitgram by dmitry soshnikov),您将找不到prototype指向__proto__以外的其他地方,因为它的价值。

要点是:prototype是引用原型对象的名称,而__proto__是实际的原型对象。

这就像在说:

prototype

var x = {name: 'john'}; 是对象名称(指针),而x是实际对象(数据值)。

注意:这只是在很大程度上简化了它们之间的关联的提示。

答案 28 :(得分:0)

如何将__proto__用于静态方法?

function Foo(name){
  this.name = name
  Foo.__proto__.collection.push(this)
  Foo.__proto__.count++

}

Foo.__proto__.count=0
Foo.__proto__.collection=[]

var bar = new Foo('bar')
var baz = new Foo('baz')

Foo.count;//2
Foo.collection // [{...}, {...}]
bar.count // undefined

答案 29 :(得分:-1)

我的理解是:__ proto__和原型都是为原型链技术服务的。不同之处在于使用下划线命名的函数(如__proto__)并不是开发人员明确调用的目标。换句话说,它们只是用于继承等机制,它们是后端的。但是没有下划线命名的函数是为明确调用而设计的,它们是前端&#39;。

答案 30 :(得分:-3)

!!!这是世界上最好的解释!!!!!

var q = {}
var prototype = {prop: 11}

q.prop // undefined
q.__proto__ = prototype
q.prop // 11

在函数构造函数中,当我们编写q.__proto__ = prototype时,javascript引擎会自动调用此new Class,并进入__proto__道具集Class.prototype

function Class(){}
Class.prototype = {prop: 999} // set prototype as we need, before call new

var q = new Class() // q.__proto__ = Class.prototype
q.prop // 999

享受%)