文章内容参考自《前端跳槽面试必备技巧》
1.类的声明
/**
* 类的声明
*/
function Animal() {
this.name = 'name';
}
/**
* ES6中的类声明
*/
class Animal2 {
constructor () {
this.name = 'name';
}
}
/**
* 实例化
*/
console.log(new Animal(), new Animal2()); // 如果没有参数,可以省略括号,即new Animal
2.类的继承
(1)ES6实现继承
/**
* ES6 继承
*/
class AnimalChildren extends Animal2 {
add() {
console.log(this.name); // 调用Animal2中的属性
}
}
console.log((new AnimalChildren()).add()); // name
这个比较简单,不用太多介绍
(2)借助构造函数实现继承
/**
* 1.借助构造函数实现继承
*/
function Parent1() {
this.name = 'parent1';
}
Parent1.prototype.say = function () {}; // 无法继承此原型对象上的方法或属性
function Child1() {
Parent1.call(this); // 或者apply,这两个方法都是让Parent1构造函数的this重新定义到Child1上,因此,Child1就具有name属性
this.type = 'child1';
}
// console.log(new Child1(), new Child1().say()); // new Child1().say()无法执行
这个方法有个缺点就是无法继承此原型对象上的方法或属性
(3)借助原型链实现继承
/**
* 2.借助原型链实现继承
*/
function Parent2() {
this.name = 'parent2';
this.play = [1, 2, 3];
}
function Child2() {
this.type = 'child2';
}
Child2.prototype = new Parent2(); // Child2的原型对象赋值为Parent2的实例
console.log(new Child2());
var s1 = new Child2();
var s2 = new Child2();
console.log(s1.play, s2.play); // [1, 2, 3] [1, 2, 3]
s1.play.push(4); // 会改变s2的值 原因:s1.__proto__ === s2.__proto__
console.log(s1.play, s2.play); // [1, 2, 3, 4] [1, 2, 3, 4]
这种方法的缺点就在于,改变某个子类实例中存在于父类中的方法或属性,会导致其子类的所有实例跟着发生改变
(4)组合方式实现
/**
* 3.组合方式实现继承
*/
function Parent3() {
this.name = 'parent3';
this.play = [1, 2, 3];
}
function Child3() {
Parent3.call(this);
this.type = 'child3';
}
Child3.prototype = new Parent3(); // 缺点:Parent3.call(this)时,Parent3已经执行了一次,这里Parent3又执行一次
var s3 = new Child3();
var s4 = new Child3();
s3.play.push(4);
console.log(s3.play, s4.play);
(5)组合方式优化
/**
* 组合继承的优化1
*/
function Parent4() {
this.name = 'parent4';
this.play = [1, 2, 3];
}
function Child4() {
Parent4.call(this);
this.type = 'child4';
}
Child4.prototype = Parent4.prototype;
var s5 = new Child4();
var s6 = new Child4();
s5.play.push(4);
console.log(s5.play, s6.play);
// 判断s5是谁实例化的实例
console.log(s5 instanceof Child4, s5 instanceof Parent4); // true true 无法判断
console.log(s5.__proto__.constructor === Child4, s5.__proto__.constructor === Parent4); // false true
/**
* 组合继承的优化2(最终版)
*/
function Parent5() {
this.name = 'parent5';
this.play = [1, 2, 3];
}
function Child5() {
Parent5.call(this);
this.type = 'child5';
}
Child5.prototype = Object.create(Parent5.prototype); // 创建一个中间对象在赋值给Child5.prototype
Child5.prototype.constructor = Child5; // 必要
var s7 = new Child5();
console.log(s7 instanceof Child5, s7 instanceof Parent5); // true true 无法判断
console.log(s7.__proto__.constructor === Child5, s7.__proto__.constructor === Parent5); // true false