es5创建对象与继承
继承的六种实现方式
1.原型链继承
让子类共享父类的方法,其关键实现就是让一个原型对象指向另一个类型的实例
1 function Parent(){ 2 this.colors = ['blue','green']; 3 } 4 Parent.prototype.addColor = function(c){ 5 this.colors.push(c); 6 } 7 function Child(){ 8 } 9 Child.prototype = new Parent(); 11 const c = new Child(); 12 c.addColor('gray'); 13 14 const other = new Child(); 15 console.log(other.colors); //['blue', 'green', 'gray']
问题:父类实例如果有引用类型成员,所有子类都共享这些成员。请看下面的代码:
function Animal() { this.friends = ['dog', 'cat']; } function Dog() {} Dog.prototype = new Animal(); const dog1 = new Dog(); const dog2 = new Dog(); dog1.friends.push('rabbit'); console.log(dog1.friends); // ['dog', 'cat', 'rabbit'] console.log(dog2.friends); // ['dog', 'cat', 'rabbit'] // dog2 也被修改了
2. 构造函数继承
将子类构造函数的this显示绑定到父类身上。这样子类的构造函数身上就显示具有父类身上的属性。。
1 function Parent(){ 2 this.colors = ['blue','green']; 3 this.addColor = function(c){ 4 this.colors.push(c); 5 } 6 } 7 function Child(){ 8 Parent.call(this); 9 } 10 const c = new Child(); 11 c.addColor('gray'); 12 13 const other = new Child(); 14 console.log(other.colors); //['blue', 'green']
问题:
实例方法(例如上面第3行的addColor),会在内存中被创建多次,浪费内存空间。
父类的原型方法无法被继承,代码如下:
function Parent() { this.name = 'Parent'; } Parent.prototype.sayName = function() { console.log(this.name); }; function Child() { Parent.call(this); // 继承父类属性 } const child = new Child(); child.sayName(); // Uncaught TypeError: child.sayName is not a function
3.组合继承(原型链继承+构造函数继承)
是 JavaScript 中最常用的继承方式之一。它结合了 原型链继承 和 构造函数继承 的优点,使子类可以:
-
通过构造函数继承父类的实例属性(避免共享引用类型)。
-
通过原型链继承父类的方法(保证方法共享,节省内存)。
1 function Parent(){ 2 this.colors = ['blue','green']; 3 } 4 Parent.prototype.addColor = function(c){ 5 this.colors.push(c); 6 } 7 function Child(){ 8 Parent.call(this); //第一次调用构造函数 9 } 10 // 继承方法 11 Child.prototype = new Parent() //第二次调用构造函数 12 //上面整个原型对象都被覆盖了,而new Parent的实例是没有构造函数成员的 13 Child.prototype.constructor = Child 14 const c = new Child(); 15 c.addColor('gray'); 16 17 const other = new Child(); 18 console.log(other.colors); //['blue', 'green']
缺点: 需要调用两次构造函数,性能上还可以进一步优化
4.寄生组合继承(最完美的方式)
-
实例:通过
Parent.call(this)继承父类构造函数中的属性,避免了父类构造函数被重复调用。每个实例都有自己的属性,避免了原型链继承中共享引用类型属性的问题。 -
共享方法:通过
Object.create(Parent.prototype)继承父类原型上的方法,保证了子类共享方法,不会重复定义。
1 function Parent(name) {
2 this.name = name
3 this.colors = [‘red’, ‘blue’, ‘green’]
4 }
5 Parent.prototype.sayName = function () {
6 console.log(this.name)
7 }
8 function Child(name, job) {
9 // 继承属性
10 Parent.call(this, name)
12 this.job = job
13 }
14 // 继承
15 Child.prototype = Object.create(Parent.prototype)
16 // 修复constructor
17 Child.prototype.constructor = Child
18 var instance = new Child(‘Jiang’, ‘student’)
19 instance.sayName()
ES6新增了一个Object.setPrototypeOf,可以直接创建关联,而且不用手动添加constructor属性,使用该方法时,第15步-17步可简写为Object.setPrototypeOf(Child.prototype, Parent.prototype)

浙公网安备 33010602011771号