__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.prototype
在Point.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。
一个很好的方式来想想它是…
prototype
由constructor()
函数使用。 它应该真的被称为"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
属性添加到a
, prototype
属性是一个具有两个属性的对象:
-
constructor
-
__proto__
所以,当我们这样做
a.prototype
它返回
constructor: a // function definition __proto__: Object
现在你可以看到constructor
函数不过是函数本身, __proto__
指向JavaScript的根级Object
。
让我们看看当我们用new
关键字使用函数时会发生什么。
var b = new a ('JavaScript');
当JavaScript执行这个代码时,它会做4件事情:
- 它创build一个新对象,一个空对象// {}
- 它在
b
上创build__proto__
并使其指向a.prototype
使得b.__proto__ === a.prototype
- 它使用新创build的对象(在步骤#1中创build)作为其上下文(this)来执行
a.prototype.constructor
(这是对函数a
定义),因此name
属性作为“JavaScript”传递(添加this
)被添加到新创build的对象。 - 它返回新创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函数),它公开了访问对象的内部原型。
参考文献:
我知道,我迟到了,但让我试着简化它。
让我们说有一个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);
- 现在我们有两个对象,对象a和对象b。 两者都是使用构造函数Foo创build的。 记住构造函数在这里只是一个字。
- 对象a和b都有一个消息属性的副本。
- 这两个对象a和b链接到构造函数Foo的原型对象。
- 在对象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一个函数a
, prototype
会自动创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();
所以, Arary
, Function
, Object
都是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)将产生这个结果
这里parent1
是parent1
的一个实例。因此, 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
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 %)