__proto__ VS. 原型在JavaScript中

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

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

__proto__prototype属性有什么区别?

在这里输入图像描述

这个数字是从这里取的。

__proto__是在查找链中用来parsing方法的实际对象,等等__proto__是用于在用new创build对象时用于构build__proto__的对象:

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

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

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

你可以通过比较一个函数的prototype和一个对象的__proto__链来findinstanceof关系,你可以通过改变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是一个构造函数,它构build一个对象(数据结构)。 myPoint是由Point()构造的一个对象,所以Point.prototypePoint.prototype被保存到myPoint.__proto__中。

Prototype属性是在声明函数时创build的。

例如:

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

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

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

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

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

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

创buildPerson的两个实例,这两个对象可以调用Person.prototype的age属性为person1.age,person2.age。

在上面的图片中,你可以看到Foo是一个函数对象,因此它有一个到Function.prototype的__proto__链接,而这个链接又是Object的一个实例,并且有一个到Object.prototype的__proto__链接。 Proto链接在Object.prototype中的__proto__结尾处指向null。

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

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

下面的代码为instanceof运算符提供了一个更好的理解:

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

一个很好的方式来想想它是…

prototypeconstructor()函数使用。 它应该真的被称为"prototypeToInstall" ,因为这就是它的原因。

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

原型VS. __proto__ VS. [[原型]]

创build函数时,会自动创build一个名为prototype的属性对象(您自己并不创build它),并将其附加到函数对象( 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 to to the prototype object without declaring it first. Foo.prototype.myName = function () { return 'My name is ' + this.name; } 

如果您将使用new关键字从Foo创build一个新对象,那么您基本上会创build一个新的对象,该对象具有与我们前面讨论的函数原型Foo内部或专用链接

 var b = new Foo(); b.[[Prototype]] === Foo.prototype // true 

该函数的对象的私有链接称为[[Prototype]] 。 许多浏览器为我们提供了一个名为__proto__公共链接!

更具体地说, __proto__实际上是属于本地JavaScript Object的getter函数 ,并且返回this绑定的内部 – 私有原型连接(返回b )的[[Prototype]]

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

值得注意的是,从ECMAScript5开始,您也可以使用getPrototypeOf方法获取内部专用链接:

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

注意:这个回答并不是要覆盖创build新对象或新构造函数的整个过程,而是为了更好地理解__proto__prototype[[Prototype]]以及它是如何工作的。

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

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

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

  1. constructor
  2. __proto__

所以,当我们这样做

a.prototype它返回

  constructor: a // function definition __proto__: Object 

现在你可以看到constructor函数不过是函数本身, __proto__指向JavaScript的根级Object

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

 var b = new a ('JavaScript'); 

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

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

现在,如果我们添加a.prototype.car = "BMW"并做b.car ,输出“宝马”出现。

这是因为当JavaScript执行这个代码时,它在b上searchcar属性,它没有find那么JavaScript使用b.__proto__ (它被指向在步骤#2中的'a.prototype')并且发现car属性,所以返回“宝马”。

希望这可以帮助!!!!!!

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

 function Person(name){ this.name = name }; var eve = new Person("Eve"); eve.__proto__ == Person.prototype //true eve.prototype //undefined 

实例__proto__原型

理解它的另一个好方法是:

 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__

简单地说:

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

这允许您将属性附加到X.prototype AFTERtypes的对象已经实例化后,它们仍然可以通过__proto__引用访问这些新的属性,JavaScript引擎使用这个引用来遍历原型链。

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

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

让我们说有一个function

  function Foo(message){ this.message = message ; }; console.log(Foo.prototype); 

Foo函数将有一个原型对象链接。 所以,每当我们在JavaScript中创build一个函数,它总是有一个原型对象链接到它。

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

  var a = new Foo("a"); var b = new Foo("b"); console.log(a.message); console.log(b.message); 
  1. 现在我们有两个对象,对象a和对象b。 两者都是使用构造函数Foo创build的。 记住构造函数在这里只是一个字。
  2. 对象a和b都有一个消息属性的副本。
  3. 这两个对象a和b链接到构造函数Foo的原型对象。
  4. 在对象a和b上,我们可以在所有浏览器中使用proto属性访问Foo原型,在IE中我们可以使用Object.getPrototypeOf(a)或Object.getPrototypeOf(b)

现在,Foo.prototype,a。 原型和b。 原始都表示相同的对象。

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

以上所有将返回true。

正如我们所知,在JavaScript中可以dynamic添加属性。 我们可以将属性添加到对象

  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构build的任何其他对象中访问。

在执行a.Greet()时,JavaScript将首先在属性列表中的对象a中searchGreet。 没有find,它会在一个原始链上升。 由于a。 proto和Foo.prototype是同一个对象,JavaScript会findGreet()方法并执行它。

我希望现在原型和原型被简化了一下。

我碰巧在学习你不知道JS的原型:这个&Object Prototypes ,这是一本了解下面的devise的精彩的书,并澄清了这么多的错误概念(这就是为什么我试图避免使用inheritance和像instanceof东西) 。

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


什么是原型?

JavaScript中的对象有一个内部属性,在规范中表示为[[Prototype]] ,它只是对另一个对象的引用。 几乎所有的对象在创build时都会被赋予一个非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是一个自动创build的对象,作为一个函数的特殊属性,用来build立代理(inheritance)链,也就是原型链。

当我们创build一个函数aprototype会自动创build为一个特殊的属性,并将函数代码保存为prototype上的constructor

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

我很想把这个属性当作存储函数对象的属性(包括方法)的地方。 这也是为什么在JS中的实用function定义像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都是function。 我应该承认,这刷新了我对JS的印象。 我知道函数是JS中的一等公民,但它似乎是build立在函数上的。

__proto__prototype什么区别?

__proto__引用在每个对象上都可以引用其[[Prototype]]属性。

prototype是一个自动创build的对象,它是一个函数的特殊属性,用来存储函数对象的属性(包括方法)。

有了这两个,我们可以在脑海中绘制出原型链。 就像这张照片所示:

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

总体思路: ———————————————– ————————————————– ———–

Instances use __ proto __ to access the prototype of its constructor function.

Prototype是函数对象的一个​​属性。每当一个函数被声明时,它就会带有一个原型属性。如果我们像下面这样声明一个名为Parent_func的函数( it is also called constructor function ):

 function Parent_func(){ //.................. } 

构造函数附带一个名为Parent_func.prototype原型属性,它是一个对象,所以它可以添加新的方法和属性。它具有如下的接口:

 Parent_func.prototype = { constructor:Parent_func, //other properties } 

如果我们创build了这个构造函数的新实例,新创build的实例将会有一个名为__ proto __的方法,这个方法将被赋予构造函数的原型。

 var parent1 = new Parent_func(); 

console.log(parent1)将产生这个结果

这里parent1parent1的一个实例。因此, parent1将有一个__ proto __ ,它将被分配Parent_func.prototype

 parent1.__ proto __ = Parent_func.prototype 

Thus we can say instances use __ proto __ to access the prototype of the constructor function.

附加信息: ———————————————– ————————————————-

(__ proto __)inheritance(父子关系):


假设我们有一个名为Child()的父类旁边的构造函数。

 function Child(){ ................. } 

由于Child也是一个构造函数,它也有一个prototype属性。我们希望孩子inheritanceParent_func 。我们可以使用Child.prototype

 Child.prototype = new Parent_func(); 

现在Child从父类inheritance。如果我们创build一个Child()构造函数的实例

 var child1 = new Child(); 

所以,

 child1.__ proto __ === new Parent() 

child1 .__ proto __现在指向一个恰好是Parent构造函数实例的对象,所以现在它将inheritanceParent_func的所有方法和属性,包括它的原型。

所以

 child1.__ proto __.__ proto __ === Parent_func.prototype 

console.log(child1)会导致这样的事情!

Thus prototype chaining works in classical javascript

** 现在我将解释一下这个问题附带的图像 :**

正如我们已经知道__ proto __被实例用来访问它的构造函数的原型:

在这里输入图像描述

1.首先我们创build了一个构造函数Foo(){}

2.构造函数Foo有一个原型属性,指向它的原型是Foo.prototype (见图)。

3.构造函数是函数,它是[[Function]]对象的实例。所以可以说函数Foo是由[[Function]]对象构造的,所以Foo的__ proto __表示Function.prototype

4. [[Function]]对象inheritance自[[Object]],所以Function.prototype的 __ proto __指向Object.prototype

5. Object.prototype是原型链中的最后一个人,所以它的__ proto __指向null

6.现在来到Foo的实例。当我们使用新的Foo()创build一个实例时,它创build一个实例。 Foo它是这些实例的构造函数。在这里我们创build了两个实例(x和y)。 x和y的__ proto __因此指向Foo.prototype

我会尝试四年级的解释:

事情很简单。 prototype是应该如何构build的一个例子。 所以:

  • 我是一个function ,我创build类似于我的prototype新对象

  • 我是一个object ,我用我的__proto__作为例子

certificate

 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 

你创build的每个函数都有一个名为prototype的属性,它作为一个空对象而开始。 这个属性是没有用的,直到你使用这个函数作为构造函数,即与“新”关键字。

这经常与对象的__proto__属性混淆。 有些人可能会感到困惑,除了对象的prototype属性可能会让他们成为对象的原型。 但是,这不是事实。 prototype用于获取从函数构造函数创build的对象的__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__ 

定义

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

prototype – 一个包含以下内容的对象:
这个特定的ConstructorFunction.prototype (5)的函数(3)可以被通过这个构造函数(1)创build或将被创build的每个对象(4)
=>构造函数本身(1)
=> __proto__这个特定的对象(原型对象)

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

原型

原型是Function的一个属性。 这是通过使用具有新关键字的(构造函数)函数来创build对象的蓝图。

__proto__

在查找链中使用__proto__来parsing方法,属性。 当一个对象被创build(使用带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 

这是我的(想象的)解释清楚混乱:

想象一下,有一个虚构的类(蓝图/ coockie刀具)与function相关联。 那个虚构的类被用来实例化对象。 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 

现在给机器人的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 }; } 

proto属性是Object.prototype上的一个简单的访问器属性,由getter和setter函数组成。 最终会咨询Object.prototype的proto的属性访问将会find这个属性,但是不访问Object.prototype的访问将不会find它。 如果在查询Object.prototype之前发现其他proto属性,那么该属性将隐藏在Object.prototype上find的属性。

proto getter函数公开了一个对象的内部[[Prototype]]的值。 对于使用对象字面值创build的对象,此值为Object.prototype。 对于使用数组文字创build的对象,此值是Array.prototype。 对于函数,这个值是Function.prototype。 对于使用new fun创build的对象,其中fun是由JavaScript提供的内置构造函数之一(Array,Boolean,Date,Number,Object,String等等 – 包括随着JavaScript演变而添加的新构造函数),此值为总是fun.prototype。 对于使用新乐趣创build的对象,其中fun是脚本​​中定义的函数,该值是fun.prototype的值。 (也就是说,如果构造函数没有显式返回其他对象,或者fun.prototype自创build实例以来已被重新分配)。

原型设置器允许对象的[[Prototype]]被突变。 该对象必须根据Object.isExtensible()进行扩展:如果不是,则引发TypeError。 提供的值必须是一个对象或null。 提供任何其他价值将无济于事。

要了解原型如何用于inheritance,请参阅指南文章inheritance和原型链。

我的理解是:__proto__和原型都是为原型链技术服务的。 不同之处在于用下划线(如__proto__)命名的函数并不是针对显式调用的开发者的。 换句话说,他们只是像inheritance等一些机制,他们是“后端”。 但是没有下划线的函数是为了明确调用而devise的,它们是“前端”的。

!!!THIS IS THE BEST EXPLANATION IN THE WORLD!!!!!

 var q = {} var prototype = {prop: 11} q.prop // undefined q.__proto__ = prototype q.prop // 11 

in function constructors javascript engine call this q.__proto__ = prototype automatically when we write new Class , and in to the __proto__ prop set 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 

Enjoy %)