__proto__VS。JavaScript原型


783

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

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

__proto__和之间有什么区别prototype

在此处输入图片说明

该图取自dmitrysoshnikov.com



5
我认为自上而下或自下而上是一个优先事项。我实际上更喜欢这种方式,因此我可以追溯图表,直到找到问题的源头。
Mike Lippert 2014年

1
我喜欢JavaScript如何使用原型继承将y.constructor解析为y .__ proto __。constructor。我还喜欢将Object.prototype放置在原型继承链的顶部,并将Object.prototype .__ proto__设置为null。我还喜欢该图如何对程序员如何将对象视为1.实例,2。构造函数,3。原型的三列​​进行概念化可视化,这些构造函数通过new关键字实例化时与这些实例相关联。
约翰·桑德森

图使得直接的感觉你看像后youtube.com/watch?v=_JJgSbuj5VI,顺便说一句
mlvljr

现在,当我阅读完答案后,有义务真的推荐上面的视频,因为它确实对发生的事情有清晰的(并且不是WTFy)解释:)
mlvljr

Answers:


764

__proto__是在查找链中用于解析方法的实际对象,等等。 prototype是使用以下命令__proto__创建对象时用于构建的对象new

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

239
啊! 所以prototype在实例本身(或其他对象)上不可用,而仅在构造函数上可用。
rvighne 2014年

43
@rvighne:prototype仅适用于功能,因为它们都源于FunctionFunction以及Object但是在别的事实并非如此。但是,__proto__随处可见。
塔里克2014年

19
__proto__保存并用作原型的实际对象也是如此,而保存并用作原型的实际对象Myconstructure.prototype只是一个蓝图 __proto__。因此myobject.prototype,这将不是实际对象的属性,因为它只是构造函数用来概述myobject.__proto__外观的临时对象 。
Alex_Nabu

9
可以说__proto__一个对象的属性是一个指向该对象的构造函数的prototype属性的指针吗?即foo .__ proto__ === foo.constructor.prototype
Niko Bellic

10
@Alex_Nabu不完全是。newCar.__proto__ IS Car.prototype,不是的实例Car.prototype。虽然Car.protoype IS的一个实例objectCar.prototype是不是,让newCar任何属性或结构,它只是IS在未来objectnewCar的原型链。Car.prototype不是暂时的object。将object设置为,将其用作使用作为__proto__的任何new object的属性的值。如果您想将任何事物视为蓝图,请将其视为新车的蓝图。CarconstructorobjectCarobject
seangwright

335

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
同样,如果更改__proto__对象的属性,它也会更改在其上进行原型查找的对象。例如,您可以将方法的对象添加为函数,__proto__以具有某种可调用的实例对象。
2014年

myPoint .__ proto __。constructor.prototype == Point.prototype
Francisco

@kzh哈哈,给我带来有趣的结果console.log(obj1.call) // [Function: call] obj1.call()// TypeError:obj1.call不是函数。我做到了obj.__proto__ = Function.__proto__
Abhisekp '16

myFn.__proto__ = {foo: 'bar'}
kzh

我想我明白了。
ComicScrip

120

声明函数时创建原型属性。

例如:

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

Person.prototype声明上述函数后,将在内部创建属性。可以将许多属性添加到Person.prototype中,这些属性由使用new Person()创建的Person实例共享。

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

值得注意的Person.prototypeObject,默认情况下是文字(可以根据需要更改)。

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

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

创建的2个实例Person中,这些2个对象可以调用age的方法Person.prototypeperson1.ageperson2.age

在上面的问题图片中,您可以看到FooFunction Object,因此它具有的__proto__链接,而Function.prototype该链接又是的实例,Object并具有的__proto__链接Object.prototype。在原链接端这里__proto__Object.prototype指向null

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

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

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

当一个对象是一个Class的实例时,对象instanceofClass运算符返回true,更具体地说,如果Class.prototype在该对象的原型链中找到该对象,则该对象是该Class的实例。

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。


2
我想知道为什么prototype首先在内部创建对象?可以简单地将静态方法分配给函数对象本身。例如function f(a){this.a = a}; f.increment = function(){return ++this.a}?为什么不选择这种方法而不是将方法添加到prototype对象?如果f.__proto__ = gg是基类,这将起作用。
abhisekp '16

也许prototype选择对象是为了共享,因为只有互斥函数构造器属性可以存储在函数构造器对象中。
abhisekp '16

1
事实上,这将是一个烂摊子,因为instanceof会导致({}) instanceof Function === true如就没有办法,如果原型之间进行区分prototype财产被删除。
abhisekp '16

@abhisekp这是什么意思:“如果f .__ proto__ = g,其中g是基类,这将起作用。” 我不知道这是否有我不明白的含义,但是如果您以这种方式添加属性和方法,那么当您使用new关键字创建实例时,将不会复制属性和方法过度。
doubleOrt

66

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

prototypeconstructor()函数使用。它实际上应该称为"prototypeToInstall",因为它就是这样。

并且__proto__是对象上的“已安装原型”(已通过所述constructor()功能在对象上创建/安装)


2
我对此表示赞成,但也许是反对的原因是因为听起来“非原型构造函数使用原型”似乎不是,不是这种情况,但是除此之外,这不是我们现在的重点可以注意到,如果使用new调用,每个函数都可能是构造函数...
yoel halb 2015年

2
请将“ constructor()函数” 更改为“构造函数”,因为可能与“ __proto__.constructor()函数” 混淆。我认为这很重要,因为new使用关键字时实际上不会调用__proto __。constructor 。
亚历山大·贡奇

1
constructor()函数使用原型 ”的说法仅说明了一个重要事实的一部分,但以可能导致读者认为这是事实的方式进行了说明。原型是为Javascript中的每个函数声明内部创建的,无论将来如何调用该函数-是否带有new关键字;声明的函数的原型指向对象文字。
伊陵

62

为了说明,让我们创建一个函数

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

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

  1. constructor
  2. __proto__

所以当我们这样做

a.prototype 它返回

     constructor: a  // function definition
    __proto__: Object

现在您可以看到constructor,除了函数a本身,它__proto__指向ObjectJavaScript 的根目录。

让我们看看将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分配给新创建的对象。

现在,如果我们添加a.prototype.car = "BMW"并执行操作 b.car,将显示输出“ BMW”。

这是因为当JavaScript执行此代码时,它会搜索 carb,它在上属性,但没有找到使用的JavaScript b.__proto__(在步骤2中指向“ a.prototype”),而是找到了car属性,因此返回“ BMW”。


2
1. constructor不退货a()!它返回a。2. __proto__返回Object.prototype,而不是Javascript中的根对象。
doubleOrt

1
这是一个很好的答案!
john-raymon

+1这是解释什么原型实际上是一个(具有两个属性的对象)以及Javascript如何执行每段代码的最佳答案。此信息令人惊讶地难以获得。
java-addict301

53

原型VS。__proto__VS。[[原型]]

创建函数时,会自动创建一个名为prototype的属性对象(您自己没有创建它)并附加到该函数对象(constructor)上。
注意:此新原型对象还指向本机JavaScript对象,或具有本机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或just [[Prototype]]。许多浏览器为我们提供一个公共联动,它调用__proto__!。

更具体地说,__proto__实际上是属于本机JavaScript对象的getter函数。它返回无论内部和私营部门的原型联动this绑定(返回[[Prototype]]b):

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

值得注意的是ECMAScript5,您还可以使用getPrototypeOf方法获取内部的私有链接:

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


注意:此答案并不打算涵盖创建新对象或新构造函数的整个过程,而是有助于更好地理解什么是__proto__prototype以及[[Prototype]]它如何工作。


2
@Taurus,单击标题,它会指向ECMAScript规范文档。请查看第9节(普通和奇异对象的行为),它会对其进行详细说明。
Lior Elrom '17

我认为这里存在一些错误:_一个具有内部或专用链接到函数原型Foo 的新对象,您的意思是:一个具有内部或专用链接到函数Foo原型的新对象
Koray Tugay

1
谢谢@KorayTugay!是的,我拼错了:) +1
Lior Elrom

30

除了上面的好答案之外,还需要使它更清楚一点:

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

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined

实例具有__proto__具有prototype


12

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

原型图

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

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

  3. 构造函数本身就是一个函数,该函数是称为[[Function]]构造函数的系统构造函数的实例。所以我们可以说function Foo是由[[Function]]构造函数构造的。因此,__proto__我们Foo function将指向其构造函数的原型Function.prototype

  4. Function.prototype本身就是一个对象,它是由另一个名为的系统构造函数构造的[[Object]]。因此,[[Object]]是的构造函数Function.prototype。所以,我们可以说Function.prototype是的一个实例[[Object]]。所以__proto__Function.prototypeObject.prototype

  5. Object.prototype是站在原型链中的最后一个人。我的意思是还没有建造。它已经在系统中了。所以它__proto__指向null

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


只是要清楚一点:实例不具有.prototype属性?只有构造函数呢?...因此,实例与其构造函数之间的区别是:构造函数都具有1. proto 2. .prototype对象,而实例仅具有.__ proto__属性...对吗?
Shaz

@Shaz,你是对的。实例使用其原型访问其构造函数的prototype属性。
AL-zami

但是为什么在编写时为什么这样:var car = Object.create(Vehicle); 您将获得car .__ proto__ = Vehicle,但您还将获得一个指向Vehicle.prototype的car.prototype属性?
Shaz

@shaz您能提供一个jsfiddle以便我可以看到情况吗?
AL-zami

1
这里car.prototype是继承的属性。汽车从车辆功能继承“原型”属性。所以car.prototype === vehicle.prototype。“原型”属性是车辆上的属性。汽车可以通过其原型链访问它。我希望这能消除您的困惑
AL-zami

8

摘要:

__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称为“原型继承”,它的基本作用是:

  • 首先,检查属性是否位于对象本身上。如果是这样,则返回此属性。
  • 如果属性不位于对象本身上,它将“爬升原型链”。基本上,它查看属性所引用的对象__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);


7

我碰巧正在从《 You'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被一个对象作为一个特殊的属性自动创建功能,其被用于建立委派(继承)链,又名原型链。

当我们创建函数时aprototype会自动创建为on的特殊属性,a并将函数代码另存为constructoron 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

7

 JavaScript原型与__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__,依此类推,直到引用对象的原型__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运算符一起创建对象,因此这些函数中的任何一个都可以是构造函数。


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);

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


只是我会用其他方式写出来:foo .__ proto__ === foo.constructor.prototype
epeleg

6

原型

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

__proto__在查找链中用于解析方法,属性。创建对象时(使用带有new关键字的构造函数),__proto__设置为(Constructor)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

这是我(虚构的)解释,以消除混乱:

想象有一个与功能相关的假想类(蓝图/库奇刀具)。该虚构类用于实例化对象。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

现在向prototypeRobot的方法添加方法:

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
    };
}

仍在思考__proto__和原型更连贯的名称。也许原型和继承?
德米特里

我会说,prototype__proto__两者都应该避免。我们现在上课,我喜欢OOP。
哈桑·塔雷克

问题是该类是相对较新的类,并且不受真正方便的引擎(例如microsoft JScript)的支持(在C语言上工作时很不错,并且需要始终存在的快速而肮脏的脚本引擎)和nashorn javascript(所有这些都附带在jjs下安装了新的Java,这是将Java置于无需不断重新编译事物的纯动态环境中的好方法。问题是,如果类是糖,那不是问题,但不是,它提供了在较旧的js版本中没有它们就不可能实现的事情。就像扩展“功能”一样。
德米特里(Dmitry)'18年

最终,我们将获得支持。我是后端开发人员,所以没有问题,很少用js编写代码。
哈桑·塔雷克

并以某种方式继承静态成员,即从子级中注意到从父级添加新成员/删除静态成员(我想不出一种在JScript上做的方法,JScript不提供Object.assign / __ proto __ / getPrototypeOf,所以您必须修改根对象Object.prototype进行模拟)
Dmitry

4

简而言之:

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

这使您可以将属性附加到X.prototype。实例化类型为X的AFTER对象,它们仍然可以通过__proto__引用访问这些新属性,JavaScript引擎使用该引用来遍历原型链。


4

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

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

参考文献:

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

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


Object.prototype不是对象文字的属性,尝试打印将{}.prototype返回未定义的内容;但是,可以通过进行访问{}.__proto__,返回Object.prototype
doubleOrt

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都具有message属性的副本。
  3. 这两个对象a和b链接到构造函数Foo的原型对象。
  4. 在对象a和b上,我们可以在所有浏览器中使用proto属性访问Foo原型,在IE中,我们可以使用Object.getPrototypeOf(a)或Object.getPrototypeOf(b)

现在,Foo.prototype,一个。原型,以及b。 所有表示相同的对象。

    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。如果找不到,它将以a的原始链上升。自从 proto和Foo.prototype是同一对象,JavaScript将找到Greet()方法并执行它。

我希望现在 可以简化原型和原型


3

解释示例:

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

let myPuppie = new Dog()

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

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

但是myPuppie没有原型属性。

> myPuppie.prototype
>> undefined

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

MPJ的很好解释:原型与原型 -JavaScript中的 对象创建


3

我为自己制作了一张代表以下代码段的小图:

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

了解__proto__和原型

我具有经典的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

干杯!


很好解释!
StackOverflow UI

@theshinylight,tom.__proto__并且Cat.prototype严格相等,所以,tom.__proto__ === Cat.prototype 并且 Cat.prototype === tom.__proto__是真的。那么,您在图像中的箭头是什么意思?
aXuser264

黑色箭头(如果要引用的话)除对象的属性外没有其他含义。对象的prototype属性也是如此Cat(根据您的问题)。
theshinylight

2

定义

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

prototype-一个对象,包括:
=>此特定函数(5)的函数(3),ConstructorFunction.prototype可通过此构造函数(1)创建或将要创建的每个对象(4)均可访问它们
=>构造函数本身(1 )
=> __proto__此特定对象(原型对象)

__proto__(dandor proto?)-通过特定构造函数(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;

1

我将尝试四年级的解释:

事情很简单。A 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

1
不会,也prototype不会__proto__在任何时候将a用作蓝图来创建任何对象。这是模糊class语法及其前身引入的神话。正如答案所言,它仅用于查找链,并prototype用于标识constructor使用new(这是那种伪装成经典机制的一部分,这种机制使包括我在内的许多用户感到困惑)。
ChristofKälin'17

第一点应该是“我是一个函数,我建立了将委托给我的原型的新对象”
Nitin Jadhav,

1

您创建的每个函数都有一个名为的属性prototype,并且从一个空对象开始其生命。除非您将此函数用作构造函数,即使用“ new”关键字,否则该属性没有用。

这通常与__proto__对象的属性混淆。有些对象可能会感到困惑,除了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__

我希望这是有道理的。


1
prototype不用于创建__proto__对象的。__proto__,当被访问时,仅提供对该prototype对象的引用。
doubleOrt

1

使用__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

这就是为什么回答__proto__VS. prototypein JavaScript”的原因
安德烈亚斯(Andreas)

它是好还是Foo.collection.push(this)Foo.count ++
Selva Ganapathi

1

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

尝试这段代码以了解


1

只有一个对象用于原型链。这个对象显然有一个名称和一个值:__proto__是它的名称,prototype也是它的值。就这样。

为了更容易理解,请查看这篇文章顶部的图表(Dmitgram by dmitry soshnikov),您将找不到__proto__除其他内容之外的其他内容prototype价值。

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

就像在说:

let x = {name: 'john'};

x是对象名称(指针),并且{name: 'john'}是实际对象(数据值)。

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

更新:这是一个简单的具体javascript示例,以更好地说明:

let x = new String("testing") // Or any other javascript object you want to create

Object.getPrototypeOf(x) === x.__proto__; // true

这意味着,当Object.getPrototypeOf(x)得到我们的实际价值x(这是它的原型),也正是__proto__x指向。因此__proto__确实是指向的原型x。因此__proto__引用x(的指针x),prototype是的值x(其原型)。

我希望现在已经清楚了。


1

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

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

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

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`

0

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


@Derick Daniel:不知道您为什么对此投反对票,但是您所做的编辑不是我要传达的。对其进行了进一步编辑,以获取更多的间隙:)。
Jyoti Duhan

Jyoti,我没有否决你的答案,有人做了,我只是编辑了它:)
自由职业者

0

由于正确地指出

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

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

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

如果我们更改构造函数原型的内存位置,__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

-1

我的理解是:__proto__和prototype都用于原型链技术。不同之处在于,以下划线命名的函数(例如__proto__)根本不面向显式调用的开发人员。换句话说,它们仅用于某些机制,例如继承等。它们是“后端”。但是命名为不带下划线的函数是为显式调用而设计的,它们是“前端”。


3
__proto__prototype相比,还有更多功能,而不仅仅是命名约定。他们可能会或可能不会指向同一对象。参见@zyklus答案。
demisx 2014年

1
@demisx当然是您说的对,但是我的看法是名称差异暴露了功能的对比。
2014年

仅仅陈述“根据您的理解”还不够,尤其是在之前已经提供其他好的答案的时候……
ProfNandaa

-3

这是世界上最好的解释!

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

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

在函数构造函数javascript引擎中q.__proto__ = prototype,我们在编写时会自动调用此函数new Class,并在__proto__prop集中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

请享用 %)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.