javascript prototype原型链的原理
说到prototype,就不得不先说下new的过程。
我们先看看这样一段代码:
<script type="text/javascript">
var Person = function () { };
var p = new Person();
</script>
很简单的一段代码,我们来看看这个new究竟做了什么?我们可以把new的过程拆分成以下三步:
<1> var p={}; 也就是说,初始化一个对象p。
<2> p.__proto__=Person.prototype; 2个下划线+proto+2个下划线
<3> Person.call(p);也就是说构造p,也可以称之为初始化p。
关键在于第二步,我们来证明一下:
<script type="text/javascript">
var Person = function () { };
var p = new Person();
alert(p.__proto__ === Person.prototype);
</script>
这段代码会返回true。说明我们步骤2的正确。
那么__proto__是什么?我们在这里简单地说下。每个对象都会在其内部初始化一个属性,就是__proto__,当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去__proto__里找这个属性,这个__proto__又会有自己的__proto__,于是就这样一直找下去,也就是我们平时所说的原型链的概念。
按照标准,__proto__是不对外公开的,也就是说是个私有属性,但是Firefox的引擎将他暴露了出来成为了一个共有的属性,我们可以对外访问和设置。
好,概念说清了,让我们看一下下面这些代码:
<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.
Example
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.
Prototypal Inheritance Definition
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 |
Javascript Weird Prototypal Inheritance
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!?
How new
works
Brendan 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.
- C++ has the notion of constructor, that initializes the instance attributes. Therefore, the
new
operator must target a function. - We need to put the methods of the object somewhere. Since we are working on a prototypal language, let's put it in the prototype property of the function.
The new
operator takes a function F
and arguments: new F(arguments...)
. It does three easy steps:
- Create the instance of the class. It is an empty object with its
__proto__
property set toF.prototype.(设置__proto__为F.prototype,正如前面讲过的。
- Initialize the instance. The function
F
is called with the arguments passed andthis
set to be the instance. - Return 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 |
Real Prototypal Inheritance in Javascript
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 |
Conclusion
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:
- Not standard:
__proto__
is non-standard and even deprecated. Also native Object.create and Douglas Crockford implementation are not exactly equivalent. - Not optimized: Object.create (native or custom) has not yet been as heavily optimized as the
new
construction. It can be up to 10 times slower.
Some further reading:
- Douglas Crockford: Prototypal Inheritance
- MDC Documentation: __proto__
- John Resig: getPrototypeOf
- Javascript Garden: Object.prototype
- Dmitry Shoshnikov: OOP: ECMAScript Implementation
- Angus Croll: Understanding Javascript prototypes
- Yehuda Katz: Understanding JavaScript Function Invocation and “this”
Bonus
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的原型链中, 原型继承与标识符查找有些迷惑,
如, 如下的代码:
- function Foo() {};
- var foo = new Foo();
- Foo.prototype.label = "laruence";
- alert(foo.label); //output: laruence
- alert(Foo.label);//output: undefined
今天看到了如下这个图:
另外, 在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__,
- function Foo() {};
- var foo = new Foo();
- Foo.__proto__.label = "laruence";
- alert(Foo.label); //output: laruence
- alert(foo.label);//output: undefined
而, 显然的:
- function Foo() {};
- alert(Foo.__proto__ === Foo.prototype); //output: false
另外, 也解释了,
- alert(Object.forEach); // undefined
- Function.prototype.forEach = function(object, block, context) {
- for (var key in object) {
- if (typeof this.prototype[key] == "undefined") {
- block.call(context, object[key], key, object);
- }
- }
- };
- alert(Object.forEach);
- alert(Function.forEach);
- alert(Object.forEach === Function.forEach); // true
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相等。
Description
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文章继承和原型链.
Example
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
js中__proto__和prototype的区别和关系?
几乎任何对象有一个[[prototype]]属性,在标准中,这是一个隐藏属性。该属性指向的是这个对象的原型。
那么一个对象的[[prototype]]属性究竟怎么决定呢?这是由构造该对象的方法决定的。据我所知有三种构造一个对象的方法:- 这个对象是通过对象字面量构造出来的。
var person1 = { name: 'cyl', sex: 'male' };
- 这个对象是由构造函数构造出来的。
function Person(){} var person1 = new Person();
- 这个对象是由函数Object.create构造的。
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__ === .constructor.prototype是不对的,如果一个对象是通过Object.create函数构造出来的,.那其__proto__就不一定是.constructor.prototype了
__proto__(隐式原型)与prototype(显式原型)
1.是什么- 显式原型 explicit prototype property:
Note:通过Function.prototype.bind方法构造出来的函数是个例外,它没有prototype属性。(感谢 同学的答案让我知道这一点)
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
- 隐式原型 implicit prototype link:
Note: Object.prototype 这个对象是个例外,它的__proto__值为null
- 二者的关系:
隐式原型指向创建这个对象的函数(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
- 隐式原型的作用:构成原型链,同样用于实现基于原型的继承。举个例子,当我们访问obj这个对象中的x属性时,如果在obj中找不到,那么就会沿着__proto__依次查找。
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
3. __proto__的指向
__proto__的指向到底如何判断呢?根据ECMA定义 'to the value of its constructor’s "prototype" ' ----指向创建这个对象的函数的显式原型。所以关键的点在于找到创建这个对象的构造函数,接下来就来看一下JS中对象被创建的方式,一眼看过去似乎有三种方式:(1)对象字面量的方式 (2)new 的方式 (3)ES5中的Object.create() 但是我认为本质上只有一种方式,也就是通过new来创建。为什么这么说呢,首先字面量的方式是一种为了开发人员更方便创建对象的一个语法糖,本质就是 var o = new Object(); o.xx = xx;o.yy=yy; 再来看看Object.create(),这是ES5中新增的方法,在这之前这被称为原型式继承,
道格拉斯在2006年写了一篇文章,题为 Prototypal Inheritance In JavaScript。在这篇文章中,他介绍了一种实现继承的方法,这种方法并没有使用严格意义上的构造函数。他的想法是借助原型可以基于已有的对象创建新对象,同时还不比因此创建自定义类型,为了达到这个目的,他给出了如下函数:
function object(o){
function F(){}
F.prototype = o;
return new F()
}
----- 《JavaScript高级程序设计》P169
所以从实现代码 return new F() 中我们可以看到,这依然是通过new来创建的。不同之处在于由 Object.create() 创建出来的对象没有构造函数,看到这里你是不是要问,没有构造函数我怎么知道它的__proto__指向哪里呢,其实这里说它没有构造函数是指在 Object.create() 函数外部我们不能访问到它的构造函数,然而在函数内部实现中是有的,它短暂地存在了那么一会儿。假设我们现在就在函数内部,可以看到对象的构造函数是F, 现在
//以下是用于验证的伪代码
var f = new F();
//于是有
f.__proto__ === F.prototype //true
//又因为
F.prototype === o;//true
//所以
f.__proto__ === o;
因此由Object.create(o)创建出来的对象它的隐式原型指向o。好了,对象的创建方式分析完了,现在你应该能够判断一个对象的__proto__指向谁了。
好吧,还是举一些一眼看过去比较疑惑的例子来巩固一下。
- 构造函数的显示原型的隐式原型:
- 内建对象(built-in object):比如Array(),Array.prototype.__proto__指向什么?Array.prototype也是一个对象,对象就是由 Object() 这个构造函数创建的,因此Array.prototype.__proto__ === Object.prototype //true,或者也可以这么理解,所有的内建对象都是由Object()创建而来。
- 自定义对象
function Foo(){}
var foo = new Foo()
Foo.prototype.__proto__ === Object.prototype //true 理由同上
(1)
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. instanceofinstanceof 操作符的内部实现机制和隐式原型、显式原型有直接的关系。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指向该方法的原型对象。