类与实例
类的声明
1、ES6之前的声明方式
function Student() {
this.name = 'name';
}
2、ES6新定义的声明方法
class Student2 {
//constructor就是类名
constructor() {
this.name = 'name'
}
}
生成实例
实例化就是将定义的类赋具体值给变量的过程
const student1 = new Student();
const student2 = new Student2();
类与继承
如何实现继承
基本原理或者说是本质就是原型链
实现继承的几种方式以及不同点
1、通过构造函数实现继承
function Parent1(name){
this.name = name;
}
function Child1(name,age){
//使用call方法使得指向发生变化,相当于把Parent中所有方法属性都copy过来成为Child的属性和方法
Parent1.call(this,name);
//或者可以使用Parent1.apply(this,name)
this.age = age;
}
const child = new Child1('mao',25);
原理:通过call/apply函数改变this的指向,使this的指向由Parent1改变为Child1,从而实现继承
缺点:父类构造函数原型链上的方法属性无法继承
举例说明:
//这个say方法是Child1无法继承到的
Parent1.prototype.say = function() {
console.log(name + ' is' + age + ' years old')
}
2、通过原型链实现继承
function Parent2(name){
this.name = name;
this.play = [1,2,3]
}
function Child2(name,age){
this.age =age;
}
//实现继承的关键步骤
Child2.prototype = new Parent2('mao');
const child2 = new Child2('mao',25);
原理:将父类实例化对象后赋值给子类的prototype属性
缺点:如果多个子类实例化之后,任一实例化后的对象改变了原型链上的值,那么其余实例化对象继承的该值也会发生变化。
举例如下:
const s1 = new Child2();
const s2 = new Child2();
s1.play.push(4);
//此时原型链上的play值已经变为[1,2,3,4]
console.log(s2.play);
//此时打印出的s2.play值为[1,2,3,4]
3、混合式继承
组合方式,将上面两种方式直接结合起来
//缺点:父类Parent3被调用了两次,一次是call继承的时候,一次是原型链继承的时候
function Parent3(name) {
this.name = name;
}
function Child3(name,age) {
Parent3.call(this,name);
this.age = age
}
//原型链方式继承父类
Child3.prototype = new Parent3(name);
const child3 = new Child3('mao',24);
接下来我们对上面的组合继承进行优化
组合继承优化1
//优点:父类Parent3调用一次即可
//缺点:子类和父类的构造函数指向同一个,子类的constructor指的是Parent
function Parent3(name) {
this.name = name;
}
function Child3(name,age) {
Parent3.call(this,name);
this.age = age
}
//这种方式的弊端是子类和父类的构造函数指向同一个,子类的constructor指的是Parent
Child3.prototype = Parent3.prototype;
//下面这个不建议这么写,因为修改后子类和父类的constructor全部指向了子类,没法区分子类和父类
//Child3.prototype.constructor = Parent3;
const child3 = new Child3('mao',24);
//以下结果都返回为true,没法判断child3是子类还是父类的直接对象,这就印证了上面说的缺点
console.log(child3 instanceof Child3,child3 instanceof Parent3);
//这个输出的就是Parent3
console.log(child3.constructor)
来,接着对上面的继承进行优化
组合继承优化2(这个就是组合继承的完美写法了)
function Parent3(name) {
this.name = name;
}
function Child3(name,age) {
Parent3.call(this,name);
this.age = age
}
//这里用Object.create先创建一个空对象,然后这个对象的原型链就是传入的参数
//这个空对象其实就作为一个中间值,将子类和父类区分开了
Child3.prototype = Object.create(Parent3.prototype);
//此时该空对象的constructor是空,我们需要对该值赋值,让他指向子类
Child3.prototype.constructor = Child3;
const child3 = new Child3('mao',24);
//以下结果两个返回都为true
console.log(child3 instanceof Child3,child3 instanceof Parent3);
//这个输出的就是Child3
console.log(child3.constructor)