一. 前言
继承是面向对象非常重要的一特性,几乎所有编程语言都拥有各自的实现方法,也成了面试必问题。下面我从实际代码出发来简述JavaScript中的继承的实现方式,分别从es5和es6两方面说明,从浅至深,希望能帮助您加深理解。
二. ES5实现方式
其核心就是明白构造函数,实例,和原型对象之间的关系。先明白以下名词和以下规则。
- (1)protype:原型对象.
- (2)proto:原型属性。
- (3)每一个构造函数都拥有一个prototype对象。
- (4) 每一个对象都拥有一个原型属性。
公用父类文件:
// Person.js
function Person(name,age) {
this.name = name || 'Person';
this.age = age || 12;
console.log('Person constructed');
}
Person.prototype = {
sayName : function() {
console.log('this Name:', this.name);
},
array: [1,2,3,4,5]
}
module.exports = Person;
(1) 原型链
// student.js
const Person = require("./Person");
function Student(name,age) {
this.name = name || "student";
this.age = age || 16;
}
Student.prototype = new Person();
let s = new Student('student',16);
console.log(s); // { name: 'student', age: 16 }
console.log(s.sayName()); // this name: student;
// 相当于s.__proto_ === Student.prototype; s.__proto__.__proto__ === Student.prototyp.__proto === Person.prototype
console.log(s.__proto__.__proto__); // { sayName: [Function: sayName], array: [ 1, 2, 3, 4, 5 ] }
// 问题1对应代码
let s2 = new Student('s2', 22);
let s3 = new Student('s3', 25);
s2.array.push(5)
console.log('s2.array.push[5],result is:',s2.array) // s2.array.push[5],result is: [ 1, 2, 3, 4, 5, 5 ]
console.log('s3.array is:',s3.array); // s3.array is: [ 1, 2, 3, 4, 5, 5 ]
执行结果如图:
问题1:原型链继承的问题或者缺点?
(2) 借用构造函数
/** 借用构造函数完成继承 */
const Person = require('./Person');
function Teacher(name,age) {
Person.call(this,name,age);
console.log('Teacher constructed');
}
const teacher = new Teacher('萧凯', 22);
console.log(teacher); //
// 以下会报错,问题2处对应代码
try {
teacher.sayName();
} catch (error) {
console.log(error);
}
代码运行结果如图所示:
问题2:借用构造函数存在的问题,优缺点?
(3)组合继承方式
const Person = require('./Person');
function Student (name ,age) {
Person.call(this,name,age);
this.age = 24;
console.log('Student constructed');
}
Student.prototype = new Person();
Student.prototype.constructor = Student;
const s = new Student('student1',23);
console.log(s);
console.log(s.sayName());
// 缺点缺点:无论在什么情况下,都会调用两次超类型构造函数,一次是在创建子类型原型的时候,一次是在子类型构造函数的内部
// 修改1, 实际是浅拷贝
Student.prototype = Object.create(Person.prototype); // 相当于 Student.prototype.__proto__ = Person.prototype
const person = new Person('Person',11);
const s2 = new Student('萧红','222');
console.log(s2);
console.log(s2.sayName());
console.log(Student.prototype.__proto__ === Person.prototype,12345)
s2.array.push(3);
console.log('--------修改1----------');
console.log(s2.array);
console.log(person.array);
console.log('------------------');
console.log('s2.__proto__ === Student.prototype:',s2.__proto__ === Student.prototype); // true
console.log('Student.prototype === Person.prototype',Student.prototype === Person.prototype) // false
console.log('Student.prototype.__proto__ === Person.prototype',Student.prototype.__proto__ === Person.prototype) // true
// 修改2
Object.setPrototypeOf(Student,Person.prototype)
const p2 = new Person('Person',11);
const s3 = new Student('萧红','222');
console.log(s3);
console.log(s3.sayName());
s3.array.push(3);
console.log('--------修改2----------');
console.log(s3.array);
console.log(p2.array);
console.log('------------------');
console.log('s2.__proto__ === Student.prototype:',s2.__proto__ === Student.prototype); // true
console.log('Student.prototype === Person.prototype',Student.prototype === Person.prototype) // false
console.log('Student.prototype.__proto__ === Person.prototype',Student.prototype.__proto__ === Person.prototype) // true
运行结果如图所示:
问题3:请问组合继承方式最大的缺点是什么?有什么优化的方法?您会怎么优化?
改进方法:可以减少构造函数的调用一次,.在子类原型对象构造的时候,可以使用Object.create()和Object.setPrototypeOf()方法代替,参见代码中的修改1和修改2。
如 a = Object.create(c), 相当于 a.__proto__ = c; 修改1中我们使用了此方法。
如 Object.setPrototypeOf(A,B),相当于A.prototype === B; 修改2中我们使用了该方法。
参考方法
MDN Oject相关技术 ECMAScript6 阮一峰 第三版
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!