JavaScript学习总结--创建对象(4_原型扩展)

上一节说到,我们使用原型+构造函数混合的方式创建了一个对象,这个对象很好的区分了实例对象的私有属性和它们的共享属性,代码是这样的

function Person(name,age,job){
  this.name=name;
  this.age=age;
  this.job=job;
}
Person.prototype.sayName=function(){
  console.log(this.name);
}
var person_01=new Person("Sakura",22,"前端开发");
var person_02=new Person("Misaka",20,"网页设计");

那么问题又来了,当我们需要在Person类的原型上添加更多的属性和方法时,就不可避免的要一遍又一遍的重写Person.prototype.XXX=XXX

很显然我们是不愿意这样写的

我们知道原型实际上也是一个对象,是对象那它就可以用字面量的方式重写

理所当然的我们可以这样写

//省略之前代码
Person.prototype={
  sayName:function(){
    console.log(this).name;
  },
  sex:"man",
  country:"China"
}

但是这里有一个问题需要注意,我们知道原本Person的原型对象有一个constructor属性,指向Persou构造函数本身

而当我们用字面量的方式重写了原型对象以后,就相当于抹去了它原本的所有属性,直接将一个新对象赋值给了prototype对象,那么这时原本它隐含的constructor就被改写了,重写后的原型对象constructor属性指向就变成了Object,而非原本的Person,所以这里们需要人为的改写原型对象的constructor属性

Person.prototype={
  constructor:Person,
  //...  
}

保证通过字面量重写后的原型对象和构造函数保持连接的关系

重写原型时有一点非常重要

我们先来看一个例子

function Person(name,age){
  this.name=name;
  this.age=age;
}
var person_01=new Person("Sakura",22,"前端开发");
//注意这里先实例化了对象person_01,然后才在原型上添加了sayName方法
Person.prototype.sayName=function(){
  console.log(this.name);
}

person_01.sayName();        //Sakura

这里我们先实例化了对象,然后才添加了sayName方法,而调用后是没有问题的,因为当我们调用sayName方法时,它会先从构造函数内部寻找,没有找到则继续往上在袁兴中查找,实例与原型的链接是一个指针,一个引用,这也说明我们随时可以用这种方式给原型添加新的属性和方法

但是,当我们实例化person_01对象后再用字面量的方式重写原型对象,就有问题了

function Person(name,age){
  this.name=name;
  this.age=age;
}
var person_01=new Person("Sakura",22,"前端开发");

Person.prototype={
  sayName:function(){
    console.log(this.name);
  }
}

person_01.sayName();        //error

原本在原型上添加方法和属性时,实例对象person_01始终与原型保持连接关系(通过__proto__),所以无论何时给Person原型添加属性方法都能被实例对象寻找到

但是上面说到,当我们用字面量重写原型对象后,实际上是为原型赋值了一个新对象,而这个新的原型还没有和实例对象person_01建立连接,也就是说此时person_01的__proto__属性指向的是重写前的原型对象,而非重写后的新原型对象,调用时,从重写前的原型对象里并不能找到sayName方法,所以发生了错误

所以通过字面量重写原型有两个非常重要的问题需要注意

1.重写后的原型constructor指向Object,需要人为的修改constructor属性指向原本的构造函数

2.一定不能在重写原型之前实例化对象,这样会切断实例化对象与新原型的链接,导致无法调用新原型中的方法

 

待续

...

posted @ 2016-06-02 13:59  Sakura_大表哥  阅读(549)  评论(0编辑  收藏  举报