随身笔记
随身笔记

构造函数、原型函数和原型链的关系

案例: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 它们的实例属性方法地址都是独立的如图:

func1

 

但是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,以上的属性和方法就是原型属性和原型方法,地址是共享的,如图:

 

func2

 

没有定义实例属性和方法所以是空的。

注意如果原型用字面量的方式写第二次的话,之前写的字面量原型关系就会被中断。例如
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_pic
g_h_h

上图中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']

 

 

fun1

Js中Prototype、__proto__、Constructor、Object、Function关系介绍

《请问js中给function添加的属性去哪儿了?有什么用途?》

没有标签
首页      前端资源      JavaScript笔记      构造函数、原型函数和原型链的关系

随身笔记

构造函数、原型函数和原型链的关系
案例:Untitled-1 首先看下构造函数的一个简单例子: var Box=function(){ //声明一个类 this.name='我'; this.age=25; this.run=function(){ return this.name+this.age; } …
扫描二维码继续阅读
2014-09-22