涉及的面试题
原型如何实现继承?CLass如何实现继承?Class本质是什么?
首先讲一下class,当初我学习ES6的时候,出现class的时候,我蛮开心的,因为我有JAVA的基础,对class可是非常的理解。后来发现,其实JS中还是没有类的存在的,class只是一个语法糖
其本质函数还是函数
class Person {}
console.log(typeof Person) //function
原型链继承
/**
* 原型链继承的例子
* 功能: 1.获取元素改变或者获取他的innerhtml。
* 2.添加事件。
function Elem(id) {
this.elem = document.getElementById(id)
}
Elem.prototype.html = function(val) {
let elem = this.elem;
if (val) {
elem.innerHTML = val
return this //链式操作
} else {
return elem.innerHTML
}
}
Elem.prototype.on = function(type, fn) {
let elem = this.elem;
elem.addEventListener(type, fn)
return this
}
let div1 = new Elem()
console.log(div1.html())
div1.html("<p>hello World").on('click', function() {
alert('Hello')
})
function Parent()
{
this.name="parent"
}
function Child()
{
this.type='child'
}
Child.prototype=new Parent()
缺点在一个类上创建两个实例,在一个实例对象上修改属性,另一个实例对象也会被修改
function Parent() {
this.name = "parent"
this.arr = [1, 2, 3]
}
function Child() {
this.type = 'child'
}
Child.prototype = new Parent()
let s1 = new Child()
let s2 = new Child()
s1.arr.push(2222)
console.log(s2.arr)//[ 1, 2, 3, 2222 ]
console.log(s1.arr)//[ 1, 2, 3, 2222 ]
构造函数
解决引用类型共享问题
function Parent(name) {
this.name = name
this.color = ['pink', 'red']
}
function Child() {
Parent.call(this)//父级构造函数的那个类指向子构造函数的实例上(原理)
//定义自己的属性
this.value = 'test'
}
let child1 = new Child()
let child2 = new Child()
child1.color.push("white")
console.log(child1)
/*
name: undefined,
color: ['pink', 'red', 'white'],
value: 'test'
}*/
console.log(child2) //Child { name: undefined, color: [ 'pink', 'red' ], value: 'test' }
缺点就是父类的原型的方法,子类无法继承
Parent.prototype.say=function(){}
上面的say方法,子类无法拥有
解决传参问题
function Parent(name) {
this.name = name;
this.color = ['pink', 'red']
}
function Child(name) {
Parent.call(this, name)
this.value = "test"
}
let child = new Child("温清夜")
console.log(child.name) //温清夜
组合继承
组合继承是最常用的继承方式
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this.val)
}
function Child(value) {
Parent.call(this, value)
}
Child.prototype = new Parent()
const children = new Child(1)
children.getValue()//1
console.log(children instanceof Parent)//true
以上继承的方式核心是在子类的构造函数中通过Parent.call(this)继承父类的属性,然后改变子类的原型为new Parent()来继承父类的函数
这种继承的方式优点在于构造函数可以传参,不会与父类引用属性共享,可以复用父类的函数,但是也存在一个缺点就是在继承父类函数的时候调用了父类构造函数,导致子类的原型上多了不需要的父类属性,存在内存上的浪费。
寄生组合继承
这种继承方式对组合继承进行了优化,组合继承缺点是在继承父类函数时调用了构造函数,我们只需要优化这点就可以了
function Parent(value) {
this.val = value
}
Parent.prototype.getValue = function() {
console.log(this)
}
function Child(value) {
Parent.call(this, value)
}
Child.prototype = Object.create(Parent.prototype, {
constructor: {
value: Child,
enumerable: false,
writable: true,
configurable: true
}
})
以上继承实现的核心就是将父类的原型赋值给子类,并且将构造函数设置为子类,这样既解决了无用的父类属性问题,还能正确的找到子类的构造函数。
Class继承
class Parent {
constructor(value) {
this.val = value
}
getValue() {
console.log(this.val)
}
}
class Child extends Parent {
constructor(value) {
super(value)
this.val = value
}
}
let child = new Child(2)
child.getValue()//2
console.log(child instanceof Parent)//true
class实现继承的核心在于使用extends表明继承来自哪个父类,并且在子类构造函数中必须调用super,因为这段代码可以看成Parent.call(this,value).