果然,感觉有些东西不整理一下还是很容易忘记的,很多时候有需要不断地去复习,感觉JavaScript这门语言总体上不能算是特别难,但是知识点特别杂(坑也特别多...),感觉最好还是能够梳理出一个整体架构出来
好了,废话不多说,今天大致上总结一下ES5中的继承模式,大致上还是参照《JavaScript高级程序设计》上来的。
- 原型模式
function Person (name, age) { this.name = name; this.age = age; } ? Person.prototype.sayName = function () { return this.name; } Person.prototype.sayAge = function () { return this.age; } ? function Student (name, age, school) { this.name = name; this.age = age; this.school = school; } ? Student.prototype = new Person(); Student.prototype.saySchool = function () { return this.school; } ? let stu = new Student(‘zhang‘, 18, ‘zust‘); console.log(stu.getName()); // ‘zhang‘ ?
以上的继承方式是比较好理解的,当访问Student实例的sayName()方法时,先遍历实例方法(无匹配),再搜索
原型对象Person实例(无匹配), 最后搜索Person.prototype对象上,得到sayName()方法。
- 借用构造函数
function Person(name, age){ this.name = name; this.age = age; } ? Person.prototype.sayName = function () { return this.name; } ? Person.prototype.sayAge = function () { return this.age; } ? function Student(name, age, school){ Person.call(this, name, age); this.school = school; } ?
所谓的借用构造函数是借用父类的构造函数来设置自己的属性,进一步避免了代码的重复。
以上是单纯使用了借用构造函数实现的继承,可以看到在子类中通过重用父类的构造方法为子类设置属性,但是仅仅使用借用构造函数,子类将无法继承父类构造函数原型中的方法。
- 组合式继承(原型模式与借用构造函数的组合)
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.sayName = function () { return this.name; } Person.prototype.sayAge = function () { return this.age; } ? function Student(name, age, school) { Person.call(this, name, age); this.school = school; } ? Student.prototype = new Person(); ?
以上的继承方式是原型模式和借用构造函数模式的组合方式,通过原型链的方式继承父类构造函数原型对象上的方法,使用借用构造函数重用父类构造函数中的代码。相当于是对于原型链继承模式的优化,将父类构造函数中的代码加以重用。
- 原型式继承
let sup = {name: ‘zhang‘, age: 18}; let extend = function (obj) { function F () {}; F.prototype = obj; return new F(); } ? let sub = extend(sup); console.log(sub.name);
就以上的继承方式而言,个人感觉与以下实现方式并没有太大区别
let sup = {name: ‘zhang‘, age: 18}; let sub = {}; Object.setPrototypeOf(sub, sup); console.log(sub.name);
在子类对象创建的过程中,所有的父类变量将会被子类共享,尤其是引用类型的变量
const sup = {name: ‘zhang‘, age: 18, arr: [‘a‘, ‘b‘, ‘c‘]} ? const extend = function (obj) { function F(){}; F.prototype = obj; return new F(); } const a = extend(sup); const b = extend(sup); console.log(a.arr); // [‘a‘, ‘b‘, ‘c‘] b.arr.push(‘d‘); console.log(a.arr); // [‘a‘, ‘b‘, ‘c‘, ‘d‘]
在原型上定义了一个引用类型的属性arr,然后通过继承创建两个对象,通过对象b访问arr属性时,由于对象b上并没有arr属性,因此,会访问b的原型对象,也就是sup对象中的arr属性,这是所有子类对象共享父类对象中的属性的实质。
ES5中通过Object.create()方法实现原型式继承的标准API
- 寄生式继承
function createPerson (obj) { var clone = Object.create(obj); clone.getName = function () { return this.name; } return clone; } ? var person = {name: ‘zhang‘, age: 18}; var p = createPerson(person); console.log(person.name); // ‘zhang‘
寄生式继承是将原型式继承以及增加实例方法这两个步骤封装成一个工厂函数,然后将生成的对象返回
代码还是比较简单的,但是具体是干嘛用的,emmmmmm...所以,不再赘述
- 寄生组合式继承
function Person (name, age) { this.name = name; this.age = age; } ? Person.prototype.getName = function () { return this.name; } ? Person.prototype.getAge = function () { return this.age; } ? function Student (name, age, school) { Person.call(name, age); this.school = school; } ? Student.prototype = Object.create(Person.prototype); Student.prototype.getSchool = function () { return this.school; }
这种继承方式可以看做是组合式继承的优化,我们可以看到,其实这种方式与组合式继承其实并没有太大区别,区别仅仅在于设置Student.prototype的方式不同。组合式继承是通过new Person()的方式产生一个原型对象,而寄生组合式继承是通过Object.create()方法产生一个经过浅复制得到原型对象的一个副本。
原文地址:https://www.cnblogs.com/zhangzhengsmiling/p/10987234.html