什么是继承 => 就是让一个对象使用了不属于自己的属性和方法
继承的作用 => 将相关的构造函数之间的公共方法提取出来,放在一个公共的构造函数上,节省空间
八种继承的方法:
(本文栗子全部使用 Student 构造函数继承 Person 类)
// 准备一个公共的被继承的构造函数 function Person(name) { this.name = name || 'person' this.age = 18 } Person.prototype.eat = function () { console.log('eatting') }
此构造函数在 new Person 的时候会得到一个对象:
{ name: 'person', age: 18, __proto__: { eat: function () {}, constructor: Person, __proto__: Object.prototype } }
1、原型继承
借助原型链
/* 一、原型继承 function Student() {} Student.prototype = new Person 将来我们 new Student 的时候会得到一个什么东西 var s = new Student s = { __proto__: Student.prototype { name: 'person', age: 18, __proto__: Person.prototype { eat: function () {}, __proto__: Object.prototype } } } 优点: 使用简单,好理解 缺点: 原型链多了一层,并且这一层没什么用 */ function Student() { this.name = 'lilei' } Student.prototype = new Person var s = new Student console.log(s)
2、借用继承
借用构造函数,使用 call 方法
/* 一、借用构造函数继承 function Student() { // 这个 Student 函数里面的 this 指向谁? s // this 就是 s Person.call(this) } Person 是一个函数 - 当函数和 new 连用的时候 this 指向实例 - 普通调用 Person() this 指向 window - call 是在调用函数的时候直接强行改变 this 指向 将来你 new Student 的时候 { name: 'person', age: 18, __proto__: Student.prototype { constructor: Student, __proto__: Object.prototype } } 优点: 直接把属性变成自己的了 缺点: 没有父类原型上的东西 */ function Student() { Person.call(this) } var s = new Student() console.log(s)
3、组合继承
将原型继承和借用继承组合使用
// 一、组合继承 function Student() { Person.call(this) } Student.prototype = new Person // 将来我们 new Student 的时候 // - 对象里面的属性由借用来的 Person 来 // - 原型由 new Person 来 // { // name: 'person', // age: 18, // __proto__: new Person { // name: 'person', // age: 18, // __proto__: Person.prototype { // eat: function () {}, // constructor: Person, // __proto__: Object.prototype // } // } // } // 优点: 属性继承来变成自己的,原型也继承过来了 // 缺点: 第一层原型没用,继承的原型多走一步
4、拷贝继承
使用 for in 循环,将父类的属性和方法放到子类的 prototype 里面
/* 一、拷贝继承 function Student() { var p = new Person for (var key in p) { Student.prototype[key] = p[key] } } 将来我们 new Student 的时候 { __proto__: Student.prototype { name: 'person', age: 18, eat: function () {}, constructor: Student, __proto__: Object.prototype } } 优点: 属性和方法都继承来放在我自己的原型上了 缺点: for in 循环,相当消耗性能的一个东西 */ function Student() { var p = new Person for (var key in p) { Student.prototype[key] = p[key] } } var s = new Student console.log(s)
5、寄生式继承
new 一个 Person 函数
/* 一、寄生继承 function Student() { var p = new Person return p } 将来当你 new Student 的时候 得到的是什么,但是我得到的是 Person 的实例 优点: 完美的继承了属性和方法 缺点: 根本没有自己的东西了 */ function Student() { this.gender = '男' var p = new Person return p } Student.prototype.fn = function () {} var s = new Student console.log(s)
6、寄生式组合继承1
组合了 借用继承+寄生式继承的一部分(寄生prototype)
/* 一、寄生式组合继承1 function Student() { Person.call(this) } Student.prototype = Person.prototype 将来我们 new Student 的时候会得到 { name: 'person', age: 18, __proto__: Person.prototype { eat: function () {}, constructor: Person, __proto__: Object.prototype } } // 我没有自己的原型,我想自己的原型上添加成渝啊你的时候,就是向父类的原型上添加 有点: 原型的东西不需要多走一步 缺点: 没有自己的原型 */ function Student() { Person.call(this) } Student.prototype = Person.prototype Student.prototype.fn = function () {} var s = new Student console.log(s) console.log(Person.prototype)
7、寄生式组合继承2
组合了 借用继承+原型继承+寄生式继承的一部分(寄生prototype)
/* 一、寄生式组合继承2 function Student() { Person.call(this) } (function () { function Abc() {} Abc.prototype = Person.prototype Student.prototype = new Abc })() 将来 new Student 的时候会得到 { name: 'person', age: 18, __proto__: new Abc { __proto__: Person.prototype { eat: function () {} } } } 优点: 属性继承来是自己的,方法也继承来了,组合式继承的中间哪个环节多余的属性没有了 缺点: 就是多了一个 空环,导致我访问继承的方法的时候要多走一步 */ function Student() { Person.call(this) } (function () { function Abc() { this.constructor = Student } Abc.prototype = Person.prototype Student.prototype = new Abc })() var s = new Student console.log(s) // function Student() { // Person.call(this) // } // // 为什么要一个自执行函数? =》 为了保护私有变量不去污染全局 // (function () { // function Abc() {} // Abc.prototype = Person.prototype // Student.prototype = new Abc // })() // function Student() { // Person.call(this) // } // // 为什么要一个自执行函数? =》 为了保护私有变量不去污染全局 // function Abc() {} // Abc.prototype = Person.prototype // Student.prototype = new Abc // // 将来我 new Abc 的时候 // { // __proto__: Person.prototype { // eat: function () {} // } // } // // 将来我new Student 的时候 // { // __proto__: new Abc { // __proto__: Person.prototype { // eat: function () {} // } // } // }
8、混搭式继承
组合了 借用继承+for in 继承父类的prototype
/* 一、混搭式继承 function Student() { Person.call(this) } (function () { var obj = Person.prototype for (var key in obj) { Student.prototype[key] = obj[key] } })() 将来我们 new Student 的时候 { name: 'person', age: 18, __proto__: Student.prototype { constructor: Student, eat: function () {}, __proto__: Object.prototype } } 优点: 属性原型都有了,没有多余的空环,constructor 直接指向自己 缺点: for in循环,没有缺点 */ function Student() { Person.call(this) } (function () { var obj = Person.prototype for (var key in obj) { Student.prototype[key] = obj[key] } })() Student.prototype.fn = function () {} var s= new Student console.log(s) console.log(Person.prototype)