Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

面试 | 你需要知道的 JS 继承 #15

Open
lurenacm opened this issue Jun 20, 2021 · 0 comments
Open

面试 | 你需要知道的 JS 继承 #15

lurenacm opened this issue Jun 20, 2021 · 0 comments

Comments

@lurenacm
Copy link
Owner

大家好,我是林一一,今天这篇文章是关于 JS 中的继承和模拟实现 new 的,我尽量将文章讲的通俗易懂,我们开始阅读吧 😁

001 继承

继承指的是,子类继承父类的方法。JS 中的继承是基于原型和原型链实现的。对原型和原型链不熟悉的先看看 面试|你不得不懂得 JS 原型和原型链

  • 继承的目的:让子类的实例也同样具备父类的属性和公共方法。

思考1:实例 c1 具备哪些属性和方法

function Parent(){
    this.name = 'parent'
}

Parent.prototype.getParentName = function() {
    console.log('Parent')
}

function Child(){
    this.name = '一一'
    var name = '二二'
}

Child.prototype.getChildName = function() {
    console.log('Child')
}

var c1 = new Child
dir(c1)

实例 c1 具备 name="林一一",和原型链上的 getChildName (这里忽略Object上的属性方法)。对这里有疑问的可以看看 面试|你不得不懂得 JS 原型和原型链。如果 c1 想获取 Parent 中的属性和方法该怎么获取?

最简单的原型继承

子类的原型等于父类的实例即可实现。原因通过原型链的向上查找机制,子类可以获取父类的方法和属性。

// 一句话一句代码即可
Child.prototype = new Parent

prototype 原型继承中父类的私有属性和公共属性都会变成子类的公共方法。原型继承是指向查找的过程不是拷贝实现的。需要注意的是,继承的父类实例是堆内存地址是唯一的,堆内存中的某一个属性值改变后,子类的实例继承到的就是改变后的属性。

  • 缺陷:原型继承是把父类的私有属性和共有属性都定义成了子类原型上的共有属性,如果想要父类的私有属性成为子类的私有属性,原型继承是不能实现的。

call 继承

使用 call 继承解决私有属性私有化之前要明白,构造函数是怎样创建私有属性的,构造函数中通过 this 指向才可以给实例创建私有属性,那么使用 call 就可以改变父类中 this 的指向

function Child(){
    Parent.call(this)
    this.name = '一一'
    var name = '二二'
}

上面 Parent 中的 this 就会被写入到子类中,实例化子类时就可以创建私有的属性。

  • 缺陷:call 继承只能继承父类的私有属性不能继承父类的共有属性。call 继承相当于拷贝了一份父类的私有属性。

组合继承1(call继承+子类原型链__proto__指向)

上面提到过 call 继承只能实现子类继承父类的私有属性,那么我们可以只获取父类的共有属性赋予给子类的原型即可。即Child.prototype.__proto__ = Parent.prototype

function Parent(){
    this.name = 'parent'
}

Parent.prototype.getParentName = function() {
    console.log('Parent')
}

function Child(){
    this.name = '一一'
    var name = '二二'
    Parent.call(this)
}

Child.prototype.__proto__ = Parent.prototype

Child.prototype.getChildName = function() {
    console.log('Child')
}

var c1 = new Child()
dir(c1)

组合继承call和父类原型.jpg

  • 缺陷:__proto__并不是所有浏览器都提供的,IE第版本就不支持

组合继承2(call继承 + Object.create()) 推荐使用

  • 先介绍一下 Object.create(obj),这个方法可以创建一个空对象,且这个空对象的原型链__proto__可以指向 obj,即换句话说使用 Object.create() 可以拷贝一份对象的属性,所以这个方法也可以作为浅拷贝的一种。
let obj = {
    name = '林一一'
}
let a  = Object.create(obj)
console.log(a.__proto__)

Object.create.jpg

  • 函数的 prototype 属性也是一个对象,同样使用 Object.create() 也可以拷贝父类原型的共有属性和方法。这句话相当于 Child.prototype = Object.create(Parent.prototype)
function Parent() {
    this.name = 'parent'
}

Parent.prototype.getParentName = function() {
    console.log('Parent')
}

function Child() {
    this.name = '一一'
    Parent.call(this)
}

Child.prototype = Object.create(Parent.prototype)

// 子类的 constructor 被覆盖,可以重新加上
Child.prototype.constructor = Child

Child.prototype.getChildName = function() {
    console.log('Child')
}

class 中的 extend

ES6 中的 class 实现其实是基于 JS 中的原型和原型链的。

class Parent{
    constructor(){
        this.name = 'parent'
    }

// 等价于 Parent.prototype.getName = function(){...}
    getParentName() {
        console.log(this.name)
    }
}

class Child extend Parent{
    constructor(){
        super()
        this.age = 18
    }
    getChildName() {
        console.log(this.name)
    }
}

classExtends.jpg

总结

  • 原型继承是 JS 继承中最简单的实现方式,但是不能区分私有属性和共有属性
  • 组合继承中,使用 call 继承+改变子类 proto 指向的继承是最合适的方式。缺点是 IE 不支持__proto__
  • 组合继承使用 call 继承和 Object.create() 可以浅拷贝一份父类原型上的方法。

002 new 构造函数

new 构造函数执行相当于普通函数执行。

function Person() {
    this.name = '林一一'
}
new Person()

结束

更多的面试系列的文章

Vue 高频原理面试篇+详细解答

面试 |call, apply, bind的模拟实现和经典面试题

面试 | JS 闭包经典使用场景和含闭包必刷题

面试 | 你不得不懂的 JS this 指向

面试 | JS 事件循环 event loop 经典面试题含答案

......

github文章合集

感谢阅读到这里,如果文章能对你有帮助或启示欢迎 star 我是林一一,下次见。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant