<script type="text/javascript"> function People(name){ this.name = name; this.job = "程序员"; } //这里是和构造函数模式继承的区别所在,因为把方法定义在了原型对象上。所以可解决函数复用的问题。把可复用的定义在原型对象上,所有实例都可以共享 //把引用类型的数据定义在构造函数中,就不会共享(每次创建都会分配新的内存空间) People.prototype.sayname = function(){ console.log(this.name); } function Person(name,age){ //person继承people方法的属性 People.call(this,name); this.age = age; } //每次new一个新的上下文,导致引用类型的数据不会共享 Person.prototype = new People(); Person.prototype.constructor = Person; Person.prototype.sayage = function(){ console.log(this.age); } var stu = new Person("prj",21); stu.job = "ceo"; console.log(stu.job); stu.sayname(); stu.sayage(); var stu1 = new Person("wxj",20); console.log(stu1.job); stu1.sayname(); stu1.sayage(); </script>
这种方法的名称叫做:组合继承方式。所谓组合是,原型继承和构造函数继承方法的组合。
单独使用这两种中的任何一个都会有比较明显的问题:原型链继承,会导致超类构造函数中的引用类型数据共享。构造函数模式继承:这种方式,使得函数的可复用性完全丧失,如果一个函数可以重复使用的话,每次都会为这个函数分配空间,如果这样的函数很多的话,就会造成内存空间的浪费。
组合继承方式集合了他们的优点:原型链方式的函数可复用和构造函数模式的内容封闭,引用类型不会共享。
唯一有点遗憾的地方是:组合继承最大的 问题就是无论什么情况下,都会调用两次超类型构造函数:一次是在创建子类型原型的时候,另一次是 在子类型构造函数内部。这样的后果是:第一次调用时,会使name属性和job属性出现在实例上,第二次调用会使name属性和job属性出现在原型上。就像这样:
虽然这并不影响我们想要的所有功能,但是精益求精的coder,还是想出了解决办法,就是我们要说的第二种方式:
寄生组合式继承:
这种继承方式解决了上面那种方式带来的缺点:上面的缺点在于,让实例出现在了不该出现的地方,归根接底,是在new 构造函数的时候出的问题,因为job属性和name属性,已经出现在了该出现的位置,我们这次只想继承超类的原型。ok,那么我们需要将超类的prototype拷贝一份,送给子类就可以了。
<script type="text/javascript"> function People(name){ this.name = name; this.job = "程序员"; } //这里是和构造函数模式继承的区别所在,因为把方法定义在了原型对象上。所以可解决函数复用的问题。把可复用的定义在原型对象上,所有实例都可以共享 //把引用类型的数据定义在构造函数中,就不会共享 People.prototype.sayname = function(){ console.log(this.name); } function Person(name,age){ //person继承people方法的属性 People.call(this,name); this.age = age; } //每次new一个新的上下文,导致引用类型的数据不会共享 // Person.prototype = new People(); // Person.prototype.constructor = Person; (function(sub,sup){ var prototype = sup.prototype; prototype.constructor = sub; sub.prototype = prototype; })(Person,People) Person.prototype.sayage = function(){ console.log(this.age); } var stu = new Person("prj",21); stu.job = "ceo"; console.log(stu.job); stu.sayname(); stu.sayage(); console.log(stu); var stu1 = new Person("wxj",20); console.log(stu1.job); stu1.sayname(); stu1.sayage(); </script>
唯一改变的地方在于红色代码部分:使用寄生的方式,将父类的prototype赋值给了子类的prototype;
可以发现子类的原型中,没有了name和job属性
原创学习博客,欢迎交流,转载说明噢~~~