@moshangxc
2018-08-29T06:53:58.000000Z
字数 5139
阅读 890
js 继承
ECMAScript只支持实现继承,实现继承主要的依靠原型链来实现的。下面介绍几种JS实现继承的方式,以及各自的优缺点。
实现原理:利用原型让一个引用类型继承另一个引用类型的属性和方法.本质为重写原型对象。
function Sup(){this.name = "sup";this.items = [1, 2, 3];}Sup.prototype.geName = function(){console.log(this.name);}function Sub(){this.age = 25;}Sub.prototype = new Sup();Sub.prototype.getAge =function(){console.log(this.age);}var instance = new Sub();instance.getName();
存在问题
1.继承包含引用类型值的原型,引用类型的原型属性会被所以实例共享。耦合度较高。
2.创建子类型的实例时不能向父类的构造函数传递 参数。
验证demo
var a = new Sub();console.log(a.items); //[1, 2, 3]a.items.push(4);var b = new Sub();console.log(b.items); //[1, 2, 3, 4]
function Sup(name){this.name = name;this.items = [1, 2, 3];}Sup.getItems = function(){console.log(this.items);}function Sub(name){Sup.call(this, name);}var a = new Sub();a.items.push(4);console.log(a.items); //[1, 2, 3, 4]var b = new Sub();console.log(b.items); //[1, 2, 3]
可以解决上诉的问题,但同时也存在缺陷。
父类原型链上定义的方法对子类是不可见的,若要继承方法,则父类的方法都应定义在构造函数内部,方法都是在构造函数中定义,不能复用
function Sup(name){this.name = name;this.items = [1, 2, 3];}Sup.prototype.getItems = function(){console.log("items: ", this.items);}Sup.prototype.getName = function(){console.log("name: ", this.name);}function Sub(name, age){Sup.call(this, name);this.age = age;}Sub.prototype = new Sup();Sub.prototype.constructor = Sub;Sub.prototype.getAge = function(){console.log("age: ", this.age);}var a = new Sub("lilei", 25);a.items.push(4);a.getName(); //lileia.getAge(); //25a.getItems(); //[1, 2, 3, 4]var b = new Sub("hanmeimei", 24);b.getName(); //hanmeimeib.getAge(); //24b.getItems(); //[1, 2, 3]
那么问题来了,又存在哪些缺陷呢?
构造函数和原型链上定义了重复的属性
function object(sup){function F(){}F.prototype = sup;return new F();}function createObj(obj){var clone = object(obj);clone.getName = function(){console.log(this.name);}clone.getFriends = function(){console.log(this.friends);}return clone;}var obj = {name : 'lily',friends: ['lucy', 'lilei', 'hanmeimei']}var obj1 = createObj(obj),obj2 = createObj(obj);obj1.name = 'jim';obj1.friends.push('lady gaga');// obj2.friends = ['katy perry', 'rianna', 'adele'];obj1.getName(); //jimobj1.getFriends(); //['lucy', 'lilei', 'hanmeimei', 'lady gaga']obj2.getName(); //lilyobj2.getFriends(); //['lucy', 'lilei', 'hanmeimei', 'lady gaga']
存在问题:含有应用类型的值始终会共享
具体原因上节课领导已经分析过,好好回忆一下下,是不是忘了(´・・)ノ(._.`)
function inherit(Sup, Sub){function F(){}F.prototype = Sup.prototype;var obj = new F();obj.constructor = Sub;Sub.prototype = obj;}
function Sup(name){this.name = name;this.items = [1, 2, 3];}Sup.prototype.getItems = function(){console.log("items: ", this.items);}Sup.prototype.getName = function(){console.log("name: ", this.name);}function Sub(name, age){Sup.call(this, name);this.age = age;}inherit(Sup, Sub);Sub.prototype.getAge = function(){console.log("age: ", this.age);}Sub.prototype.getName = function(){console.log("nameForSub: ", this.name);}function Sub1(name, age){Sup.call(this, name);this.age = age;}inherit(Sup, Sub1);Sub1.prototype.getAge = function(){console.log("age: ", this.age);}var a = new Sub("lilei", 25);a.items.push(4);a.getName(); //nameForSub: lileia.getAge(); //age: 25a.getItems(); //items: [1, 2, 3, 4]var b = new Sub("hanmeimei", 24);b.getName(); //nameForSub: hanmeimeib.getAge(); //age: 24b.getItems(); //items: [1, 2, 3]var c = new Sub1("jim", 23);c.getName(); //name: jimc.getAge(); //age: 23c.getItems(); //items: [1, 2, 3]
inherit函数能不能换成如下写法,有什么区别?
function inherit(Sup, Sub){Sub.prototype = Sup.prototype;}
| 继承方式 | 描述 | 好处 | 缺陷 |
|---|---|---|---|
| 原型链 | 重写子类原型链为基类的实例对象 | 易理解 | 1.无法给基类构造函数传递参数 2. 所有实例共享引用类型的属性 |
| 借用构造函数 | 子类构造函数中调用基类构造函数,作用域指向当前对象 | 解决原型链存在的问题 | 基类原型链上定义的方法属性对子类是不可见的 |
| 组合继承 | 原型链和借用构造函数组合 | 以上缺陷可以解决 | 存在重复定义的属性和方法 |
| 寄生式继承 | 构建临时构造函数,重写原型,返回新的对象 | 没想到,应用场景不多(~ o ~)~zZ | 不适用于自定义类型,引用类型属性会共享 |
| 寄生式继承 | 是否必填 | 解决综上问题 | 不易理解,待消化 |
以上内容仅个人理解,如有错误还请谅解 (〃'▽'〃)
//代码附录//1.function inherit(Sup, Sub){function F(){}F.prototype = Sup.prototype;var obj = new F();obj.constructor = Sub;Sub.prototype = obj;}function Sup(name){this.name = name;this.items = [1, 2, 3];}Sup.prototype.getItems = function(){console.log("items: ", this.items);}Sup.prototype.getName = function(){console.log("name: ", this.name);}function Sub(name, age){Sup.call(this, name);this.age = age;}inherit(Sup, Sub);Sub.prototype.getAge = function(){console.log("age: ", this.age);}Sub.prototype.getName = function(){console.log("nameForSub: ", this.name);}function Sub1(name, age){Sup.call(this, name);this.age = age;}inherit(Sup, Sub1);Sub1.prototype.getAge = function(){console.log("age: ", this.age);}var a = new Sub("lilei", 25);a.items.push(4);a.getName();a.getAge();a.getItems();var b = new Sub("hanmeimei", 24);b.getName();b.getAge();b.getItems();var c = new Sub1("jim", 23);c.getName();c.getAge();c.getItems();//2.function inherit(Sup, Sub){Sub.prototype = Sup.prototype;}function Sup(name){this.name = name;this.items = [1, 2, 3];}Sup.prototype.getItems = function(){console.log("items: ", this.items);}Sup.prototype.getName = function(){console.log("name: ", this.name);}function Sub(name, age){Sup.call(this, name);this.age = age;}inherit(Sup, Sub);Sub.prototype.getAge = function(){console.log("age: ", this.age);}Sub.prototype.getName = function(){console.log("nameForSub: ", this.name);}function Sub1(name, age){Sup.call(this, name);this.age = age;}inherit(Sup, Sub1);Sub1.prototype.getAge = function(){console.log("age: ", this.age);}var a = new Sub("lilei", 25);a.items.push(4);a.getName();a.getAge();a.getItems();var b = new Sub("hanmeimei", 24);b.getName();b.getAge();b.getItems();var c = new Sub1("jim", 23);c.getName();c.getAge();c.getItems();