继承的方案以及优缺点
1. 通过原型链实现继承
1 | // 1.定义父类构造函数 |
优点: 子类可以继承父类的方法
缺点:
- 第一,我们通过直接打印对象是看不到这个属性的;
- 第二,这个属性会被多个对象共享,如果这个对象是一个引用类型,那么就会造成问题;
- 第三,不能给Person传递参数(让每个stu有自己的属性),因为这个对象是一次性创建的(没办法定制化);
2. 借用构造函数继承
1 | // 1.定义父类构造函数 |
在子类中可以通过apply或call调用都可以
优点:属性不会被共享,可以给父类传入参数
缺点:父类的方法不能复用,子类实例的方法每次都是单独创建的。
3. 组合继承
核心:原型式继承和构造函数继承的组合,兼具了二者的优点。
1 | // 1.定义父类构造函数 |
优点:
- 父类的方法可以被复用
- 父类的引用属性不会被共享
- 子类构建实例时可以向父类传递参数
缺点:无论什么情况都会调用两次父类方法,这种被覆盖的情况造成了性能上的浪费。
4. 原型式继承
历史:这种模式最早是道格拉斯·可罗克福德(Douglas Crockford,著名的前端大师,JSON的创立者)在2006年写的一篇文章说起:Prototypal Inheritance in JavaScript(在JavaScript中使用原型式继承)
1 | function createObject(o) { |
优缺点和原型链继承一样,父类的方法可以复用,但父类的引用属性会被子类实例共享,子类构建不能向父类传递参数
ECMAScript 5 通过新增 Object.create()方法规范化了原型式继承。这个方法接收两个参数:一 个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。在传入一个参数的情况下, Object.create()与 object()方法的行为相同。
所以上面的代码可以转换成
1 | Student.prototype = createObject(Person.prototype) |
5. 寄生式继承
- 寄生式(Parasitic)继承是与原型式继承紧密相关的一种思想, 并且同样由道格拉斯·克罗克福德(Douglas Crockford)提出和推 广的;
- 寄生式继承的思路是结合原型类继承和工厂模式的一种方式;
- 即创建一个封装继承过程的函数, 该函数在内部以某种方式来增强对象,最后再将这个对象返回;
1 | function createStudent(person) { |
6. 寄生组合式继承
组合继承是比较理想的继承方式, 但是存在两个问题:
- 问题一: 构造函数会被调用两次: 一次在创建子类型原型对象的时候, 一次在创建子类型实例的时候.
- 问题二: 父类型中的属性会有两份: 一份在原型对象中, 一份在子类型实例中
寄生组合式继承就可以解决这两个问题
优缺点:完美!
1 | // 创建对象的过程 |
7. class extend继承(ES6中的继承)
在ES6中用这种方式写的继承,最后都会转成ES5的代码,继承的原理式一样的,extend相当于式上面寄生组合式继承的一种语法糖。
1 | class Person { |
对象方法的补充
1 | var obj = { name: "beichen”} |
hasOwnProperty
对象是否有某一个属于自己的属性(不是在原型上的属性)
1
2
3console.log(info.hasOwnProperty("name")) // false
console.log(info.hasOwnProperty("address")) // truein/for in操作符
判断某个属性是否在某个对象或者对象的原型上
1
2
3
4
5
6console.log("name" in info) // true
console.log("address" in info) //
for(var key in info) {
console.log(key) // address, name
}tips: for in 遍历不仅仅是自己对象上的内容,也包括原型对象上的内容
Object上的属性和方法也能找到,但是他们的enmuerable为false,不可被遍历。
instanceof
用来判断类(构造函数)和对象之间的关系。
1
2
3
4
5
6
7
8
9function Person() {}
function Student() {}
inherit(Student, Person)
// stu是实例对象,Student可以看成是一个类(构造函数)
var stu = new Student()
console.log(stu instanceof Student) // true
console.log(stu instanceof Person) // true
console.log(stu instanceof Object) // true简洁一点说就寻找Student/Person/Object是否在stu的原型链上constructor所指的对象上
isPrototypeOf
判断对象之间的继承。但是用的比较少。
1
2
3
4console.log(Student.prototype.isPrototypeOf(stu)) // true
console.log(Person.prototype.isPrototypeOf(stu)) // true
console.log(Object.prototype.isPrototypeOf(stu)) // true简单说就是判断Student.prototype(原型)是否在stu的原型脸上