案例:Untitled-1
首先看下构造函数的一个简单例子:
var Box=function(){ //声明一个类
this.name=’我’;
this.age=25;
this.run=function(){
return this.name+this.age;
}
}
var box1 =new Wo(); //类实例化成对象
var box2 =new Wo();
alert(p1.run());
以上声明类的方式就叫做构造函数,这样的属性和方法就是实例属性和实例方法。
同时new了两个实例化对象box1和box2 它们的实例属性方法地址都是独立的如图:

但是new多个实例对象会造成资源的浪费所以需要公用一个地址,这时我们需要原型函数。
var Box=function(){ //声明一个类
this.prototype.name=’我’;
this.prototype.age=25;
this.prototype.run=function(){
return this.name+this.age;
}
}
var box1 =new Wo(); //类实例化成对象
var box2 =new Wo();
alert(p1.run());
原型函数只需要加prototype,以上的属性和方法就是原型属性和原型方法,地址是共享的,如图:

没有定义实例属性和方法所以是空的。
注意如果原型用字面量的方式写第二次的话,之前写的字面量原型关系就会被中断。例如
Box.prototype={ name:’我’,age:18 };
Box.prototype={ sex:’男’}; //重写了第二次,之前写的Box原型不会被继承。
我们每创建一个(构造)函数的时候就默认存在一个prototype对象,这个对象是用来存储共享的属性和方法,不存在__proto__。如果创建一个实例函数默认才会有__proto__,这个是隐藏的原型链接始终指向原型函数即使搞乱p1.constructor=’asdf’也依然能正常去获取到原型函数里的属性和方法,实例函数不存在prototype属性,但是实例函数可以通过__proto__指向prototype属性去寻找我们需要的属性和方法,所以说:__proto__存在于实例函数与原型函数之间。
上面说了每创建一个(构造)函数的时候默认存在一个prototype属性,prototype属性默认获取constructor属性,这个属性又会指向所创建的构造函数。
console.log(p1.constructor.prototype.ceshi === p1.ceshi); //完全等价
对于说到原型函数所以就要涉及到原型链,在图中我们可以看到__proto__,只要是new出现一个实例对象就会有__proto__,__proto__也就会自动指向prototype寻找prototype里面的原型属性和方法。
简单说下面向对象的工作流程:
1,声明一个类时,里面可以添加方法和属性。
2,实例化对象需要new,当new的时候JS就默认创建了一个__proto__属性,这个是JS内置的需要寻找原型函数用的。
3,当我们要调用面向对象里面的属性或者方法时,先通过__proto__一层层的寻找需要的实例属性和方法,如果找到了就不会在去找原型的了,如果找不到__proto__最终到prototype里面寻找原型属性和方法,所以说:每个实例对象里面的__proto__属性指向的是原型函数,实例对象跟new它们之前的构造函数没什么直接关系。
原型链的核心就是__proto__。
__proto__最终指向的是原型prototype。例如在类中创建了一个原型方法,我们可以通过这样的方法调用。
p1.__proto__.run(); //调用原型的run方法
p1.__proto__.run=function(){} //这样也相当于在原型中创建了方法,因为__proto__直接指向原型。


上图中prototype重复写了好几次,其实也可以用字面量方式写:
Wo.prototype={ name:'', age:'' run:function(){} } 字面量的方式写效果跟之前的一样,但是唯一不同的是Wo构造函数里面的prototype属性指向的原型对象里面的constructor属性不再是指向Wo构造函数了,如果需要重新指向Wo构造函数只需要添加一个属性即可: Wo.prototype={ constructor:Wo, name:'', age:'' run:function(){} } (实际上我也不知道constructor具体有什么用?_?)
关于构造函数和原型对象的this
function Wo() { console.log(this); //这里的this 指的是new Wo()实例化后的对象 this.name="chen"; //对外变量 var xx="xx"; //私有变量 } Wo.prototype.say=function () { console.log( this.name ); // chen console.log( this.xx ); //undefined console.log( this ); //这里的this 指的是new Wo()实例化后的对象 } new Wo().say();
推荐使用组合:
function Baba(name) { this.baba_name=name; this.color=['red','greent']; } Baba.prototype.sayname=function () { return this.baba_name; //当构造函数被new时,原型对象里面this指的是构造函数 }; function Son(name,age) { Baba.call(this,name); this.age=age; } Son.prototype=new Baba(); Son.prototype.constructor=Son; Son.prototype.sayage=function () { console.log(this.age); }; var p1=new Son('chen',22); var p2=new Son('ge',29); //son的构造函数和原型对象中都没有sayname方法,但是son的原型对象继承了new Baba(), //而Baba构造函数中的原型对象又有sayname函数,所以p1和p2共享着其实是Baba构造函数的原型对象里面的sayname函数 console.log(p1.sayname()) ; //chen console.log(p2.sayname()) ; //ge //会有人问Son.prototype=new Baba()不是继承了Baba构造函数里面的所有属性和方法了吗?所以color应该也是共享的啊? // 没错,但是别忘记了son之前还Baba.call(this,name); 也就是说son构造函数里面已经有了color对象了, // 所以就不必去son的prototype里面去找color对象了。所以修改color对象是独立私有的 p1.color.push('pink'); console.log(p1.color); // ['red','greent','pink'] console.log(p2.color); // ['red','greent']