说到prototype,就不得不先说下new的过程。javascript
咱们先看看这样一段代码:html
<script type="text/javascript">
var Person = function () { };
var p = new Person();
</script>
很简单的一段代码,咱们来看看这个new究竟作了什么?咱们能够把new的过程拆分红如下三步:java
<1> var p={}; 也就是说,初始化一个对象p。react
<2> p.__proto__=Person.prototype; 2个下划线+proto+2个下划线git
<3> Person.call(p);也就是说构造p,也能够称之为初始化p。github
关键在于第二步,咱们来证实一下:web
<script type="text/javascript">
var Person = function () { };
var p = new Person();
alert(p.__proto__ === Person.prototype);
</script>
这段代码会返回true。说明咱们步骤2的正确。express
那么__proto__是什么?咱们在这里简单地说下。每一个对象都会在其内部初始化一个属性,就是__proto__,当咱们访问一个对象的属性时,若是这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有本身的__proto__,因而就这样一直找下去,也就是咱们平时所说的原型链的概念。浏览器
按照标准,__proto__是不对外公开的,也就是说是个私有属性,可是Firefox的引擎将他暴露了出来成为了一个共有的属性,咱们能够对外访问和设置。cookie
好,概念说清了,让咱们看一下下面这些代码:
<script type="text/javascript">
var Person = function () { };
Person.prototype.Say = function () {
alert("Person say");
}
var p = new Person();
p.Say();
</script>
这段代码很简单,相信每一个人都这样写过,那就让咱们看下为何p能够访问Person的Say。
首先var p=new Person();能够得出p.__proto__=Person.prototype。那么当咱们调用p.Say()时,首先p中没有Say这个属性,因而,他就须要到他的__proto__中去找,也就是Person.prototype,而咱们在上面定义了Person.prototype.Say=function(){}; 因而,就找到了这个方法。
好,接下来,让咱们看个更复杂的。
var Person = function () { }; Person.prototype.Say = function () { alert("Person say"); } Person.prototype.Salary = 50000; var Programmer = function () { }; Programmer.prototype = new Person(); Programmer.prototype.WriteCode = function () { alert("programmer writes code"); }; Programmer.prototype.Salary = 500; var p = new Programmer(); p.Say(); p.WriteCode(); alert(p.Salary);
们来作这样的推导:
var p=new Programmer()能够得出p.__proto__=Programmer.prototype;
而在上面咱们指定了Programmer.prototype=new Person();咱们来这样拆分,
var p1=new Person();Programmer.prototype=p1;那么:
p1.__proto__=Person.prototype;
Programmer.prototype.__proto__=Person.prototype; ..
Programmer.prototype = new Person();
由根据上面获得p.__proto__=Programmer.prototype。能够获得p.__proto__.__proto__=Person.prototype。
好,算清楚了以后咱们来看上面的结果,p.Say()。因为p没有Say这个属性,因而去p.__proto__,也就是Programmer.prototype,也就是p1中去找,因为p1中也没有Say,那就去p.__proto__.__proto__,也就是Person.prototype中去找,因而就找到了alert(“Person say”)的方法。
其他的也都是一样的道理。
这也就是原型链的实现原理。
最后,其实prototype只是一个假象,他在实现原型链中只是起到了一个辅助做用,换句话说,他只是在new的时候有着必定的价值,而原型链的本质,其实在于__proto__!
转自:http://www.cnblogs.com/kym/archive/2010/01/09/1643062.html
另一篇:
An Object's __proto__
property references the same object as its internal [[Prototype]]
(often referred to as "the prototype"), which may be an object or null
(in the case of Object.prototype.__proto__
). This property is an abstraction error, because a property with the same name, but some other value, could be defined on the object too. If there is a need to reference an object's prototype, the preferred method is to use Object.getPrototypeOf
.
var proto = obj.__proto__;
When an object is created, its __proto__
property is set to reference the same object as its internal [[Prototype]]
(i.e. its constructor's prototype
object). Assigning a new value to __proto__
also changes the value of the internal [[Prototype]]
property, except where the object is non–extensible.
当1个对象建立时,__proto__属性被设置于引用相同的【prototype】对象。赋一个值给__proto__属性会改变【prototype】属性,除非对象不可扩展。
To understand how prototypes are used for inheritance, see the MDN article Inheritance and the prototype chain.
In the following, a new instance of Employee
is created, then tested to show that its __proto__
is the same object as its constructor's prototype
.
// Declare a function to be used as a constructor
function Employee() {
/* initialise instance */
}
// Create a new instance of Employee
var fred = new Employee();
// Test equivalence
fred.__proto__ === Employee.prototype; // true
At this point, fred
inherits from Employee
, however assigning a different object to fred.__proto__
can change that:
1
2
|
// Assign a new object to __proto__
fred.__proto__ = Object.prototype;
|
Now fred
no longer inherits from Employee.prototype
, but directly from Object.prototype
, and loses the properties it originally inherited from Employee.prototype
.
However, this only applies to extensible objects, a non–extensible object's __proto__
property cannot be changed:
1
2
3
4
|
var
obj = {};
Object.preventExtensions(obj);
obj.__proto__ = {};
// throws a TypeError
|
一篇很好的文章:
转自:http://blog.vjeux.com/2011/javascript/how-prototypal-inheritance-really-works.html
Everywhere on the web we read that Javascript has prototypal inheritance. However Javascript only provides by default a specific case of prototypal inheritance with the new
operator. Therefore, most of the explanations are really confusing to read. This article aims to clarify what is prototypal inheritance and how to really use it on Javascript.
When you read about Javascript prototypal inheritance, you often see a definition like this:
When accessing the properties of an object, JavaScript will traverse the prototype chain upwards until it finds a property with the requested name. Javascript Garden
Most Javascript implementations use __proto__
property to represent the next object in the prototype chain. We will see along this article what is the difference between __proto__
and prototype
.
__proto__
is non-standard and should not be used in your code. It is used in the article to explain how Javascript inheritance works.
The following code shows how the Javascript engine retrieves a property (for reading).
function getProperty(obj, prop) { if (obj.hasOwnProperty(prop)) return obj[prop] else if (obj.__proto__ !== null) return getProperty(obj.__proto__, prop) else return undefined } |
Let's take the usual class example: a 2D Point. A Point has two coordinates x
, y
and a method print
.
Using the definition of the prototypal inheritance written before, we will make an object Point with three properties: x
, y
and print
. In order to create a new point, we just make a new object with __proto__
set toPoint
.
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = {x: 10, y: 20, __proto__: Point}; p.print(); // 10 20 |
What is confusing is that everyone teaches Javascript prototypal inheritance with this definition but does not give this code. Instead they give something like this:
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p = new Point(10, 20); p.print(); // 10 20 |
This is completely different from the code given above. Point is now a function, we use a prototype
property, the new
operator. What the hell!?
new
worksBrendan Eich wanted Javascript to look like traditional Object Oriented programming languages such as Java and C++. In those, we use the new
operator to make a new instance of a class. So he wrote a new
operator for Javascript.
new
operator must target a function.The new
operator takes a function F
and arguments: new F(arguments...)
. It does three easy steps:
__proto__
property set toF.prototype.(设置__proto__为F.prototype,正如前面讲过的。
F
is called with the arguments passed and this
set to be the instance.Now that we understand what the new
operator does, we can implement it in Javascript.
function New (f) { /*1*/ var n = { '__proto__': f.prototype }; return function () { /*2*/ f.apply(n, arguments); /*3*/ return n; }; } |
And just a small test to see that it works.
function Point(x, y) { this.x = x; this.y = y; } Point.prototype = { print: function () { console.log(this.x, this.y); } }; var p1 = new Point(10, 20); p1.print(); // 10 20 console.log(p1 instanceof Point); // true var p2 = New (Point)(10, 20); p2.print(); // 10 20 console.log(p2 instanceof Point); // true |
The Javascript specifications only gives us the new
operator to work with. However, Douglas Crockford found a way to exploit the new
operator to do real Prototypal Inheritance! He wrote the Object.create function.
Object.create = function (parent) { function F() {} F.prototype = parent; return new F(); }; |
This looks really strange but what it does is really simple. It just creates a new object with its prototype set to whatever you want. It could be written as this if we allow the use of __proto__
:
Object.create = function (parent) { return { '__proto__': parent }; }; |
The following code is our Point example with the use of real prototypal inheritance.
var Point = { x: 0, y: 0, print: function () { console.log(this.x, this.y); } }; var p = Object.create(Point); p.x = 10; p.y = 20; p.print(); // 10 20 |
We have seen what prototypal inheritance is and how Javascript implements only a specific way to do it.
However, the use of real prototypal inheritance (Object.create and __proto__) has some downsides:
__proto__
is non-standard and even deprecated. Also native Object.create and Douglas Crockford implementation are not exactly equivalent.new
construction. It can be up to 10 times slower.Some further reading:
If you can understand with this picture (from the ECMAScript standard) how Prototypal Inheritance works, you get a free cookie!
另一篇好文:
http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
以前我对Javascript的原型链中, 原型继承与标识符查找有些迷惑,
如, 以下的代码:
今天看到了以下这个图:
另外, 在Javascript Object Hierarchy看到:
The prototype is only used for properties inherited by objects/instances created by that function. The function itself does not use the associated prototype.
也就是说, 函数对象的prototype并不做用于原型链查找过程当中,(就是:原型仅仅用于被函数建立的对象或实例,函数自己不使用相关的原型,能够类比类方法和对象方法的区别)
今天在firefox下发现(由于firefox经过__proto__暴露了[[prototype]]), 真正参与标识符查找的是函数对象的__proto__,
而, 显然的:
另外, 也解释了,
An Object's __proto__
property references the same object as its internal [[Prototype]]
(often referred to as "the prototype"), which may be an object or, as in the default case of Object.prototype.__proto__,
null
. This property is an abstraction error, because a property with the same name, but some other value, could be defined on the object too. If there is a need to reference an object's prototype, the preferred method is to use Object.getPrototypeOf
.
A __proto__
pseudo property has been included in §B.3.1 of the draft ECMAScript ed. 6 specification (note that the specification codifies what is already in implementations and what websites may currently rely on).
var proto = obj.__proto__;
一个对象的__proto__
属性和本身的内部属性[[Prototype]]指向一个相同的值
(一般称这个值为原型),原型的值能够是一个对象值也能够是null
(好比说Object.prototype.__proto__的值就是null
).该属性可能会引起一些错误,由于用户可能会不知道该属性的特殊性,而给它赋值,从而改变了这个对象的原型. 若是须要访问一个对象的原型,应该使用方法Object.getPrototypeOf
.
__proto__
属性已经被添加在了ES6草案 §B.3.1中.
不要认为__proto__和prototype相等。
When an object is created, its __proto__
property is set to reference the same object as its internal [[Prototype]]
(i.e. its constructor's prototype
object). Assigning a new value to __proto__
also changes the value of the internal [[Prototype]]
property, except where the object is non–extensible.
To understand how prototypes are used for inheritance, see the MDN article Inheritance and the prototype chain.
当一个对象被建立时,它的 __proto__
属性和内部属性[[Prototype]]指向了相同的对象
(也就是它的构造函数的prototype
属性).改变__proto__
属性的值同时也会改变内部属性[[Prototype]]的值
,除非该对象是不可扩展的.
想要知道如何使用原型来实现继承,查看MDN文章继承和原型链.
In the following, a new instance of Employee
is created, then tested to show that its __proto__
is the same object as its constructor's prototype
.
// 声明一个函数做为构造函数function Employee() { /* 初始化实例 */ } // 建立一个Employee实例 var fred = new Employee(); // 测试相等性 fred.__proto__ === Employee.prototype; // true
这是, fred
继承了 Employee
, 可是若是给fred.__proto__
赋另一个对象值,则会改变它的继承对象:
// Assign a new object to __proto__ fred.__proto__ = Object.prototype;
如今,fred不在继承于
Employee.prototype
, 而是直接继承了Object.prototype
, 也就丢失了全部从Employee.prototype
继承来的属性.
但是,这只适用于可扩展的 对象,一个不可扩展的对象的 __proto__
属性是不可变的:
1
|
<code
class
=
" language-js"
><span
class
=
"token keyword"
> </span></code>
|
var obj = {}; Object.preventExtensions(obj); obj.__proto__ = {}; // throws a TypeError
Note that even Object.prototype
's __proto__
property can be redefined as long as the chain leads to null:
var b = {}; Object.prototype.__proto__ = { hi: function () {alert('hi');}, __proto__: null }; b.hi();
If Object.prototype
's __proto__
had not been set to null
, or had not been set to another object whose prototype chain did not eventually lead explicitly to null
, a "cyclic __proto__ value" TypeError would result since the chain must eventually lead to null
(as it normally does on Object.prototype
).
参考:https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/proto
上面的
bject.prototype.__proto__不能改为
bject.prototype.prototype.
为何?
咱们能够:
function func(){};
alert(typeof Object.prototype);//Object,不是Function
alert(typeof func); //Function。
能够看出Object.prototype是一个object,没有prototype属性.alert( Object.prototype.prototype);显示undefined。
(从这里咱们能够看出Object 是 一个function,typeof Object 为function。)
prototype
is a property of a Function object. It is the prototype of objects constructed by that function.
只有函数才有prototype属性,对象没有。
咱们能够看stackoverflow上的一个问题:
This figure again shows that every object has a prototype. Constructor function Foo also has its own
__proto__
which is Function.prototype, and which in turn also references via its__proto__
property again to the Object.prototype. Thus, repeat, Foo.prototype is just an explicit property of Foo which refers to the prototype of b and c objects.
var b =new Foo(20);var c =new Foo(30);
What are the __proto__
and the prototype
properties?
要仔细理解这幅图 typeof Object=='function' 为true,说明Object类型为function。
Foo.prototype.__proto__ === Object.prototype 为true。
我的理解:上面的b->Foo.prototype-->Object.prototype组成了一条链,但b没有在本身中找到相应的属性和方法时,就会向上去寻找 。咱们能够这么理解,继承与prototype无关,而与__proto__有关。?咱们在这里简单地说下。每一个对象都会在其内部初始化一个属性,就是__proto__,当咱们访问一个对象的属性时,若是这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有本身的__proto__,因而就这样一直找下去,也就是咱们平时所说的原型链的概念。
参考:http://www.cnblogs.com/youxin/archive/2013/03/08/2950751.html
能够看到,Function.prototype是函数Foo的__proto__。咱们只要在Function.prototype增长了一个方法,全部的函数均可以调用这个方法,如《javascript精粹》中的一个例子:
Function.prototype.method=function(name,func){ if(!this.prototype[name]){ this.prototype[name]=func; } return this; }; Foo.method("say2",function(){alert("say2");}); //和上面的话做用同样:Foo.prototype.say2=function(){alert("say2");}; var c=new Foo(); c.say2();
下面的这段代码是我编的。
function Foo(){}
var b=new Foo();
alert(Foo.prototype==Foo.__proto__); //false
alert( Foo.__proto__); //function Empty(){}
alert(Foo.prototype); //[object object]
alert(Foo.prototype.constructor); //function Foo(){}
与上图对应的代码:
// a constructor function function Foo(y) { // which may create objects // by specified pattern: they have after // creation own "y" property this.y = y; } // also "Foo.prototype" stores reference // to the prototype of newly created objects, // so we may use it to define shared/inherited // properties or methods, so the same as in // previous example we have: // inherited property "x" Foo.prototype.x = 10; // and inherited method "calculate" Foo.prototype.calculate = function (z) { return this.x + this.y + z; }; // now create our "b" and "c" // objects using "pattern" Foo var b = new Foo(20); var c = new Foo(30); // call the inherited method b.calculate(30); // 60 c.calculate(40); // 80 // let's show that we reference // properties we expect console.log( b.__proto__ === Foo.prototype, // true c.__proto__ === Foo.prototype, // true // also "Foo.prototype" automatically creates // a special property "constructor", which is a // reference to the constructor function itself; // instances "b" and "c" may found it via // delegation and use to check their constructor b.constructor === Foo, // true c.constructor === Foo, // true Foo.prototype.constructor === Foo // true b.calculate === b.__proto__.calculate, // true b.__proto__.calculate === Foo.prototype.calculate // true );
具体参考:http://dmitrysoshnikov.com/ecmascript/javascript-the-core/
答案1:
__proto__
is internal property of an object, pointing to its prototype. Current standards provide an equivalent Object.getPrototypeOf(O)
method, though de facto standard __proto__
is quicker.
You can find instanceof
relationships by comparing a function's prototype
to an object's__proto__
chain, and you can break these relationships by changing 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;
Here Point
is a constructor function, it builds an object (data structure) procedurally. myPoint
is an object constructed by Point()
so Point.prototype
gets saved to myPoint.__proto__
at that time.
答案2:
__proto__
is the actual object that is used in the lookup chain to resolve methods, etc. prototype
is the object that is used to build __proto__
when you create an object with new
:
(new Foo).__proto__ ===Foo.prototype (newFoo).prototype ===undefined
转自:http://stackoverflow.com/questions/9959727/what-is-the-difference-between-proto-and-prototype-in-javascript
几乎任何对象有一个[[prototype]]属性,在标准中,这是一个隐藏属性。该属性指向的是这个对象的原型。
那么一个对象的[[prototype]]属性究竟怎么决定呢?这是由构造该对象的方法决定的。据我所知有三种构造一个对象的方法:var person1 = { name: 'cyl', sex: 'male' };
function Person(){}
var person1 = new Person();
var person1 = { name: 'cyl', sex: 'male' }; var person2 = Object.create(person1);
Object.create = function(p) { function f(){} f.prototype = p; return new f(); }
然而虽说[[prototype]]是一个隐藏属性,但不少浏览器都给每个对象提供.__proto__这一属性,这个属性就是上文反复提到的该对象的[[prototype]]。因为这个属性不标准,所以通常不提倡使用。ES5中用Object.getPrototypeOf函数得到一个对象的[[prototype]]。ES6中,使用Object.setPrototypeOf能够直接修改一个对象的[[prototype]]
--------------------------------
至于什么原型链之类的,都很好理解,这里就不说了。
__proto__(隐式原型)与prototype(显式原型)
1. 是什么NOTE Function objects created using Function.prototype.bind do not have a prototype property or the [[Code]], [[FormalParameters]], and [[Scope]] internal properties. ----- ECMAScript Language Specification
隐式原型指向建立这个对象的函数(constructor)的prototype
2. 做用是什么ECMAScript does not use classes such as those in C++, Smalltalk, or Java. Instead objects may be created in various ways including via a literal notation or via constructors which create objects and then execute code that initialises all or part of them by assigning initial values to their properties. Each constructor is a function that has a property named “prototype” that is used to implement prototype-based inheritance and shared properties.Objects are created by using constructors in new expressions; for example, new Date(2009,11) creates a new Date object. ---- ECMAScript Language Specification
Every object created by a constructor has an implicit reference (called the object’s prototype) to the value of its constructor’s “prototype” ---- ECMAScript Language Specification
道格拉斯在2006年写了一篇文章,题为 Prototypal Inheritance In JavaScript。在这篇文章中,他介绍了一种实现继承的方法,这种方法并无使用严格意义上的构造函数。他的想法是借助原型能够基于已有的对象建立新对象,同时还不比所以建立自定义类型,为了达到这个目的,他给出了以下函数:
function object(o){ function F(){} F.prototype = o; return new F() }
----- 《JavaScript高级程序设计》P169
//如下是用于验证的伪代码 var f = new F(); //因而有 f.__proto__ === F.prototype //true //又由于 F.prototype === o;//true //因此 f.__proto__ === o;
所以由Object.create(o)建立出来的对象它的隐式原型指向o。好了,对象的建立方式分析完了,如今你应该可以判断一个对象的__proto__指向谁了。
好吧,仍是举一些一眼看过去比较疑惑的例子来巩固一下。
function Foo(){}
var foo = new Foo()
Foo.prototype.__proto__ === Object.prototype //true 理由同上
function Bar(){} //这时咱们想让Foo继承Bar Foo.prototype = new Bar() Foo.prototype.__proto__ === Bar.prototype //true
//咱们不想让Foo继承谁,可是咱们要本身从新定义Foo.prototype Foo.prototype = { a:10, b:-10 } //这种方式就是用了对象字面量的方式来建立一个对象,根据前文所述 Foo.prototype.__proto__ === Object.prototype
注: 以上两种状况都等于彻底重写了Foo.prototype,因此Foo.prototype.constructor也跟着改变了,因而乎constructor这个属性和原来的构造函数Foo()也就切断了联系。
既然是构造函数那么它就是Function()的实例,所以也就指向Function.prototype,好比 Object.__proto__ === Function.prototype
4. instanceof//设 L instanceof R
//经过判断
L.__proto__.__proto__ ..... === R.prototype ?
//最终返回true or false
Function instanceof Object // true Object instanceof Function // true Function instanceof Function //true Object instanceof Object // true Number instanceof Number //false
首先,要明确几个点:
1.在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。所以,它们都会具备对象共有的特色。
即:对象具备属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例可以访问在构造函数原型中定义的属性和方法。
2.方法(Function)
方法这个特殊的对象,除了和其余对象同样有上述_proto_属性以外,还有本身特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含全部实例共享的属性和方法(咱们把这个对象叫作原型对象)。原型对象也有一个属性,叫作constructor,这个属性包含了一个指针,指回原构造函数。
好啦,知道了这两个基本点,咱们来看看上面这副图。
1.构造函数Foo()
构造函数的原型属性Foo.prototype指向了原型对象,在原型对象里有共有的方法,全部构造函数声明的实例(这里是f1,f2)均可以共享这个方法。
2.原型对象Foo.prototype
Foo.prototype保存着实例共享的方法,有一个指针constructor指回构造函数。
3.实例
f1和f2是Foo这个对象的两个实例,这两个对象也有属性__proto__,指向构造函数的原型对象,这样子就能够像上面1所说的访问原型对象的全部方法啦。
另外:
构造函数Foo()除了是方法,也是对象啊,它也有__proto__属性,指向谁呢?
指向它的构造函数的原型对象呗。函数的构造函数不就是Function嘛,所以这里的__proto__指向了Function.prototype。
其实除了Foo(),Function(), Object()也是同样的道理。
原型对象也是对象啊,它的__proto__属性,又指向谁呢?
同理,指向它的构造函数的原型对象呗。这里是Object.prototype.
最后,Object.prototype的__proto__属性指向null。
总结:1.对象有属性__proto__,指向该对象的构造函数的原型对象。2.方法除了有属性__proto__,还有属性prototype,prototype指向该方法的原型对象。