JavaScript原型链与继承|记一次面试经历

3,028 阅读4分钟

前言

这篇文章里面记录了我一次面试Node.js后端开发岗位时,二面的面试官问我的关于JavaScript原型链方面的知识,当面手写代码😱。

希望这篇文章能对今年要找web前端后者Node.js后端开发工作的同学有所帮助。

必备概念

prototype:无论什么时候,只要创建了一个新的函数,就会根据一个特定的规则为该函数创建一个prototype属性,只有函数才有prototype属性。

proto:所有对象都包含一个__proto__属性指向它的构造函数的prototype

constructor:所有对象都包含constructor属性,这个属性包含一个指向prototype属性所在函数的指针。

场景再现

二面那天下着大雨🌧,面试的时间约的是早上的9:30。半身湿透的我在hr的带领下来到了会议室,不一会进来了一个年龄大约40岁的人,手里拿了几张白纸。

在我进行完必备的礼仪后,他也做了简单的介绍(部门经理)。

....

他问:你带笔了吗?

我说:带了。

他说:这几张纸你拿着,一会要写代码,轻松点,我们开始吧~

衣服湿的太多,当时确实有点冷🥶

请模拟实现new操作符

这道题考察的是使用new操作符调用构造函数所经历的阶段:

  1. 创建一个新的对象;
  2. 将构造函数的作用域赋给新的对象;
  3. 执行构造函数中的代码;
  4. 返回新的对象;
 function analog_new(constructor, ...rest) {
    if (typeof constructor !== 'function') {
        return constructor;
    }
    //创建新的对象,关联构造函数的原型对象
    const _constructor = Object.create(constructor.prototype);
    //执行构造函数
    const obj = constructor.apply(_constructor, rest);
    //如果构造函数执行结果是对象则返回执行结果
    if (typeof obj === 'object') {
        return obj;
    } else {
        return _constructor;
    }
 };

什么是继承

继承、封装、多态是面向对象编程的基本特性。通过继承子类不仅可以具有父类的方法和属性还可以加入新的属性和方法或者修改父类的属性和方法。

官方描述: 继承是面向对象的编程的一种基本特性。 借助继承,能够定义可重用(继承)、扩展或修改父类行为的子类。 成员被继承的类称为基类。 继承基类成员的类称为派生类。

js如何实现继承

通过原型链可以实现继承。

js实现继承有哪些方式

  1. 借用构造函数
  2. 原型链
  3. 组合继承

请写出来

这里面借用构造函数实现继承原型链继承当时并没有问我缺点,是我在写文章的时候加上去的。

借用构造函数实现继承

 function Animal(type) {
    this.type = type;
 }

 function Duck() {
    //继承Animal
    Animal.call(this,'duck');
 }

 const duck = new Duck();
 console.log(duck.type);//duck

缺点:不能继承Animal原型链上的属性

 function Animal(type) {
    this.type = type;
 }

 Animal.prototype.walk = function (){
    console.log('walk');
 }

 function Duck() {
    //继承Animal
    Animal.call(this,'duck');
 }

  const duck = new Duck();
  console.log(duck.type);//duck
  duck.walk();//Error:duck.walk is not a function

原型链继承

 function Animal(type) {
     this.type = type;
 }
 Animal.prototype.walk = function () {
     console.log('walk...');
 }

 function Duck() { }
 Duck.prototype = new Animal('duck');//将Duck的原型对象赋值为Animal的实例实现继承

 const duck = new Duck();
 console.log(duck.type);//duck
 duck.walk();//walk...

缺点:当某一个实例修改原型链上某一个属性时,如果实例类型是引用类型,那么其它实例的属性也会被修改。

 function Animal(type) {
    this.type = type;
    this.colors = ['yellow'];
 }
 Animal.prototype.walk = function () {
    console.log('walk...');
 }

 function Duck() { }
 Duck.prototype = new Animal('duck');//将Duck的原型对象赋值为Animal的实例实现继承


 const normal_duck = new Duck();//正常的鸭子
 const variation_duck = new Duck();//变异的鸭子
 variation_duck.colors.push('black');//变异的鸭子有yellow和black两种颜色

 //修改variation_duck对象的color属性,normal_duck对象的color属性也发生了变化
 console.log(normal_duck.colors);//[ 'yellow', 'black' ]
 console.log(variation_duck.colors);//[ 'yellow', 'black' ]

组合继承

 function Animal(type) {
    this.type = type;
    this.color = ['yellow'];
 }
 Animal.prototype.walk = function () {
    console.log('walk...');
 }

 function Duck() {
    Animal.call(this, 'duck');
 }
 Duck.prototype = Object.create(Animal.prototype);
 Duck.prototype.constructor = Duck;

 const normal_duck = new Duck();//正常的鸭子
 const variation_duck = new Duck();//变异的鸭子
 variation_duck.color.push('black');//变异的鸭子有yellow和black两种颜色

 //修改variation_duck对象的color属性,normal_duck对象的color属性未发生了变化
 console.log(normal_duck.color);//[ 'yellow' ]
 console.log(variation_duck.color);//[ 'yellow', 'black' ]

总结

说实在的第一次遇到当面手写代码还是有些紧张。这种情况应该比较少吧!后面还写了其它的一些和原型链无关的知识,这里就不写了。但是在后面类似这样的互动比较多:面试官让你手写一段代码,然后在提出问题不断的这样反复...

经过近两个小时的鏖战,最终HR找我谈了薪资。

这个分享一下个人经验:

  1. 在保证答题速度的前提下,一定要注意字迹的工整。
  2. 代码命名一定要规范,尽量把自己知道的都写/说出来。
  3. 在沟通的过程中保持使用双手将纸递给面试官。

最后最各位2020都能找到有自己喜欢的工作。❤❤❤

参考

<<javascript高级程序设计>>
C# 继承

我的专栏

Node.js入门与实战

一文搞懂Node.js异步编程

Node.js后端开发系列之sequelize零基础快速入门实战