JavaScript原型鏈與繼承|記一次面試經歷

前言

這篇文章裏面記錄了我一次面試Node.js後端開發崗位時,二面的面試官問個人關於JavaScript原型鏈方面的知識,當面手寫代碼😱。javascript

但願這篇文章能對今年要找web前端後者Node.js後端開發工做的同窗有所幫助。前端

必備概念

prototype:不管何時,只要建立了一個新的函數,就會根據一個特定的規則爲該函數建立一個prototype屬性,只有函數纔有prototype屬性。java

proto:全部對象都包含一個__proto__屬性指向它的構造函數的prototypeweb

constructor:全部對象都包含constructor屬性,這個屬性包含一個指向prototype屬性所在函數的指針。面試

場景再現

二面那天下着大雨🌧,面試的時間約的是早上的9:30。半身溼透的我在hr的帶領下來到了會議室,不一會進來了一個年齡大約40歲的人,手裏拿了幾張白紙。編程

在我進行完必備的禮儀後,他也作了簡單的介紹(部門經理)。後端

....bash

他問:你帶筆了嗎?app

我說:帶了。函數

他說:這幾張紙你拿着,一會要寫代碼,輕鬆點,咱們開始吧~

衣服溼的太多,當時確實有點冷🥶

請模擬實現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# 繼承

相關文章
相關標籤/搜索