說到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指向該方法的原型對象。