写了2年前端从来不用面向对象?_前端用不到面向对象

function UserRole(name) {
    this.name = name;
}

function Login() {
    UserRole.call(this, 'userName01');
    this.type = 'edutior';
}

console.log(new Login());
/**
{
    "name": "userName01",
    "type": "edutior"
}
*/

通过使用call方法,子类能够获取父类的属性值。然而,这种方式存在一个问题,就是无法继承父类原型对象中的方法

💡(ES5+)第二种:借助原型链

接下来,让我们来看一种借助原型链实现继承的方式。以下是示例代码:

function UserRole(name, routers) {
    this.name = name;
    this.routes = routers;
}

function Login() {
    this.type = 'edutior';
}

Login.prototype = new UserRole('userName01', [1,2,3]);

console.log(new Login());
/**
{
    "type": "edutior"
    [[Prototype]]: {
        "name": "userName01",
        "routes": [1,2,3]
    }
}
*/

使用原型链继承时,子类能够访问父类的方法和属性。然而,这种方式存在一个潜在的问题。

举个例子,明明我只改变了login01的play属性,为什么login02也跟着变了呢?

const login01 = new Login();
const login02 = new Login();
login01.routes.push(4)
console.log(login01.routes, login02.routes);
// [1,2,3,4]  [1,2,3,4]

如果我们修改了一个实例的属性,其他实例也会受到影响,因为它们共享同一个原型对象

💡(ES5+)第三种:将前两种组合

我们可以将前两种继承方式进行组合,解决各自的问题。以下是示例代码:

function UserRole(name, routers) {
    this.name = name;
    this.routes = routers;
}

function Login() {
    UserRole.call(this, 'userName01', [1,2,3]);
    this.type = 'edutior';
}

Login.prototype = new UserRole('userName01', [1,2,3]);

const login01 = new Login();
const login02 = new Login();
login01.routes.push(4)
console.log(login01.routes, login02.routes);
// [1,2,3,4]  [1,2,3]

通过这种组合方式,我们解决了之前的问题。然而,这种方式会导致父类的构造函数被执行两次,强迫症非常难受。

💡(ES5+)第四种:组合继承的优化

为了优化组合继承的方式,我们可以进行一些改进。以下是示例代码:

function UserRole(name, routers) {
    this.name = name;
    this.routes = routers;
}

function Login() {
    UserRole.call(this, 'userName01', [1,2,3]);
    this.type = 'edutior';
}

Login.prototype = UserRole.prototype;

const login01 = new Login();
console.log(login01)
/**
{
    "name": "userName01",
    "routes": [1,2,3],
    "type": "edutior"
    [[Prototype]]: {
    	constructor: UserRole(name, routers)
    }
}
*/

通过将子类的原型直接指向父类的原型,并修复子类构造函数的引用,我们避免了父类构造函数被执行两次的问题。

但是这个时候又出现了一个新的问题:

子类实例的构造函数是UserRole,显然这是不对的,应该是Login!

💡(ES5+推荐)第五种:寄生组合继承

最后,我要介绍的是一种最推荐的继承方式:寄生组合继承。以下是示例代码:

function UserRole(name, routers) {
    this.name = name;
    this.routes = routers;
}

function Login() {
    UserRole.call(this, 'userName01', [1,2,3]);
    this.type = 'edutior';
}

Login.prototype = Object.create(UserRole.prototype);
Login.prototype.constructor = Login;

const login01 = new Login();
console.log(login01)
/**
{
    "name": "userName01",
    "routes": [1,2,3],
    "type": "edutior"
    [[Prototype]]: {
    	constructor: Login()
    }
}
*/

寄生组合继承是一种接近完美的继承方式。它解决了属性共享和方法继承的问题,并且避免了父类构造函数被执行多次的情况。

✨“寄生组合继承”在ES6的编译过程中是怎么运用的

如果我们使用ES6的extends关键字进行继承,并编译成ES5的代码,会得到类似以下的JavaScript代码:

function _possibleConstructorReturn(self, call) {
    // ...
    return call && (typeof call === 'object' || typeof call === 'function') ? call : self;
}

function _inherits(subClass, superClass) {
    // ...
    // 注意这里
    subClass.prototype = Object.create(superClass && superClass.prototype, {
        constructor: {
            value: subClass,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}

var Parent = function Parent() {
    // 验证是否是 Parent 构造出来的 this
    _classCallCheck(this, Parent);
};

var Child = function (_Parent) {
    _inherits(Child, _Parent);

    function Child() {
        _classCallCheck(this, Child);

        return _possibleConstructorReturn(this, (Child.__proto__ || Object.getPrototypeOf(Child)).apply(this, arguments));
    }

    return Child;
}(Parent);

你可以看到,在编译后的JavaScript代码中,实际上也是采用了寄生组合继承的方式来实现继承。

同时,它还使用了Object.setPrototypeOf来继承父类的静态方法,又进一步改进了第五种方法所忽略的地方。

❓只要使用了“继承”,就是好的面向对象设计吗?

先说结论:不一定!

假设现在后台管理系统中有N个不同的角色,每个角色都有login,level,content三个方法。

class Role{
  constructor(name) {
    this.name = name;
  }
  login(){
    console.log("login!");
  }
  level(){
    console.log("level!")
  }
  content(){
    console.log("content!")
  }
}
class otherRole extends Role{}



### 最后

除了简历做到位,面试题也必不可少,整理了些题目,前面有117道汇总的面试到的题目,后面包括了HTML、CSS、JS、ES6、vue、微信小程序、项目类问题、笔试编程类题等专题。

* **[开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】](https://bbs.csdn.net/topics/618166371)**

  ![](https://img-blog.csdnimg.cn/img_convert/64ce8432d0f753e43f93972ad19fcd72.png)


![](https://img-blog.csdnimg.cn/img_convert/d508b1ae6a5e7d5e7d5daf668e9eccea.png)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值