function Person(name,age){ this.name=name; this.age=age; } Person.prototype.sayHello=function(){ alert("使用原型获得Name:"+this.name); } var per=new Person("alin",21); per.sayHello(); //输出:使用原型获得Name:alin
在函数Person里面自定义了属性name和age,而prototype是咱们的属性集合,也就是说,我要添加sayHello这个属性到Person,则要这样写:Person.prototype.sayHello,就能添加Person的属性。javascript
(咱们能够简单的把prototype看作是一个模板,新建立的自定义对象都是这个模板prototype的一个拷贝,其实准确来讲,不该该说是一个拷贝,而是一个链接,只不过这种连接是不可见,新实例化的对象内部有一个看不见的_Proto_指针,指向原型对象)。java
使用原型来优化代码:函数
function add(x,y){ return x+y; } function subtract(x,y){ return x-y; } console.log(add(1,3));
var Calculator = function(){ }; Calculator.prototype = { add:function(x,y){ return x+y; }, subtract:function(x,y){ return x-y; } }; console.log((new Calculator()).add(1,3));
var Calculator = function () {}; Calculator.prototype = function(){ add = function(x,y){ return x+y; }, subtract = function(x,y){ return x-y; } return{ add:add, subtract:subtract } }(); console.log((new Calculator()).add(1,3));
var foo = { x: 10, y: 20 };
解析:当你定义一个函数对象的时候,其内部就有这样一个链表关系。声明foo对象,自带了_proto_的属性,而这个属性指向了prototype,从而实现对象的扩展(例如继承等操做)。优化
再看一个栗子:this
var a = { x: 10, calculate: function (z) { return this.x + this.y + z } }; var b = { y: 20, __proto__: a }; var c = { y: 30, __proto__: a }; b.calculate(30); // 60
附上另外说明:spa
一、一个没有继承操做的函数的_proto_都会指向Object.prototype,而Object.prototype都会指向null。prototype
二、因此,也能够很明显知道,为什么null是原型链的终端。设计
理解了__proto__这个属性连接指针的本质。。再来理解constructor。指针
prototype默认的有一个叫作constructor的属性,指向这个函数自己。
通常construtor就是咱们平时对函数设置的实例化对象code
如上图:SuperType是一个函数,下面包括他的原型对象prototype,原型对象指向了构造函数的指针,而构造函数指回像了原型对象的内部指针,这样就造成了链式关系了。
就是说,当一个函数对象被建立时候,Function构造器产生的函数对象会运行相似这样的一行代码:
this.prototype = {constructor:this};
这个prototype对象是存放继承特征的地方。由于js没有提供一个方法去肯定哪一个函数是打算用来作构造器,因此每一个函数都会获得一个prototype对象。constructor属性没有什么用,重要的是prototype对象。
实现原型链有一种基本模式,其代码大体以下:
function A(){ this.Aproperty = "111"; } A.prototype.getA = function(){ return this.Aproperty; }; function B(){ this.Bproperty = "222"; } B.prototype = new A();//B继承A B.prototype.getB = function(){ return this.Bproperty; }; var C = new B(); console.log(C.getA());//111
以上定义了两个类型A和B。每一个类型分别有一个属性和一个方法。它们的主要区别是B继承了A,而继承是经过建立A的实例,并将实例赋给B.prototype实现的。实现的本质是重写原型的对象,代之以一个新的类型的实例。换句话说,原来存在于A的实例中的全部属性和方法,如今也存在于B.prototype中了。在确立了继承关系以后,咱们给B.prototype添加了一个方法,这样就继承A的属性和方法的基础上又添加了一个新方法。
如图:
另一个很重要的链式继承模式:
function A(x){ this.x = x; } A.prototype.a = "a"; function B(x,y){ this.y = y; A.call(this,x); } B.prototype.b1 = function(){ alert("b1"); } B.prototype = new A(); B.prototype.b2 = function(){ alert("b2"); } B.prototype.constructor = B; var obj = new B(1,3);
就是说把B的原型指向了A的1个实例对象,这个实例对象具备x属性,为undefined,还具备a属性,值为"a"。因此B原型也具备了这2个属性(或者说,B和A创建了原型链,B是A的下级)。而由于方才的类继承,B的实例对象也具备了x属性,也就是说obj对象有2个同名的x属性,此时原型属性x要让位于实例对象属性x,因此obj.x是1,而非undefined。第13行又定义了原型方法b2,因此B原型也具备了b2。虽然第9~11行设置了原型方法b1,可是你会发现第12行执行后,B原型再也不具备b1方法,也就是obj.b1是undefined。由于第12行使得B原型指向改变,原来具备b1的原型对象被抛弃,天然就没有b1了。
第12行执行完后,B原型(B.prototype)指向了A的实例对象,而A的实例对象的构造器是构造函数A,因此B.prototype.constructor就是构造对象A了(换句话说,A构造了B的原型)。
alert(B.prototype.constructor)出来后就是"function A(x){...}" 。一样地,obj.constructor也是A构造对象,alert(obj.constructor)出来后就是"function A(x){...}" ,也就是说B.prototype.constructor===obj.constructor(true),可是B.prototype===obj.constructor.prototype(false),由于前者是B的原型,具备成员:x,a,b2,后者是A的原型,具备成员:a。如何修正这个问题呢,就在第16行,将B原型的构造器从新指向了B构造函数,那么B.prototype===obj.constructor.prototype(true),都具备成员:x,a,b2。
若是没有第16行,那是否是obj = new B(1,3)会去调用A构造函数实例化呢?答案是否认的,你会发现obj.y=3,因此仍然是调用的B构造函数实例化的。虽然obj.constructor===A(true),可是对于new B()的行为来讲,执行了上面所说的经过构造函数建立实例对象的3个步骤,第一步,建立空对象;第二步,obj.__proto__ === B.prototype,B.prototype是具备x,a,b2成员的,obj.constructor指向了B.prototype.constructor,即构造函数A;第三步,调用的构造函数B去设置和初始化成员,具备了属性x,y。虽然不加16行不影响obj的属性,但如上一段说,却影响obj.constructor和obj.constructor.prototype。因此在使用了原型继承后,要进行修正的操做。
关于第十二、16行,总言之,第12行使得B原型继承了A的原型对象的全部成员,可是也使得B的实例对象的构造器的原型指向了A原型,因此要经过第16行修正这个缺陷。
文章说明:我的查看各类资料,原创所得,观点不必定准确,欢迎各路大牛勘误,小女子感激涕零。