前端跳槽面試總結之原型鏈、面向對象、通信類和安全類

一、原型鏈

  1. 對於原型鏈,會從創建對象的方式、原型、構造函數、實例、原型鏈、instanceof 的原理、new 運算符這幾個方面分析。
  2. 對於創建對象的方式,如下所示:
  • 字面量的方式,如下所示:
      var o1 = {name: 'o1'};
      var o2 = new Object({name: 'o2'});
    
  • 構造函數的方式,如下所示:
      var M = function (name) { this.name = name; };
      var o3 = new M('o3');
    
  • Object.create 的方式,如下所示:
      var p = {name: 'p'};
      var o4 = Object.create(p);
    
  1. 對於原型、構造函數、實例、原型鏈這幾個的關係,如下所示:
  • JavaScript 中,每當定義一個對象(函數也是對象)時候,對象中都會包含一些預定義的屬性。其中每個函數對象都有一個prototype 屬性,這個屬性指向函數的原型對象,使用原型對象的好處是所有對象實例共享它所包含的屬性和方法
  • 原型鏈解決的主要是繼承問題。每個對象擁有一個原型對象,通過 proto 指針指向其原型對象,並從中繼承方法和屬性,同時原型對象也可能擁有原型,這樣一層一層,最終指向 null(Object.proptotype.__proto__ 指向的是null)。這種關係被稱爲原型鏈(prototype chain),通過原型鏈一個對象可以擁有定義在其他對象中的屬性和方法
  • prototype 是構造函數的屬性,__proto__ 是每個實例都有的屬性,可以訪問 [[prototype]] 屬性,實例的 __proto__ 與其構造函數的 prototype 指向的是同一個對象
  • 原型鏈是原型對象創建過程的歷史記錄,當訪問一個對象的某個屬性時,會先在這個對象本身屬性上查找,如果沒有找到,則會去它的__proto__ 隱式原型上查找,即它的構造函數的prototype,如果還沒有找到就會再在構造函數的prototype__proto__中查找,這樣一層一層向上查找就會形成一個鏈式結構
  • 所有函數的__proto__都是指向Functionprototype,構造函數new出來的對象__proto__指向構造函數的prototype,非構造函數實例化出的對象或者對象的prototype__proto__指向ObjectprototypeObjectprototype指向null
  1. 對於 instanceof 的原理,instanceof主要用於判斷某個實例是否屬於某個類型,也可用於判斷某個實例是否是其父類型或者祖先類型的實例。instanceof 主要的實現原理就是隻要右邊變量的 prototype 在左邊變量的原型鏈上即可。因此,instanceof 在查找的過程中會遍歷左邊變量的原型鏈,直到找到右邊變量的 prototype,如果查找失敗,則會返回 false
  2. 對於 new 運算符,如下所示:
  • 一個新對象被創建,它繼承自 foo.prototype
  • 構造函數 foo 被執行,執行的時候,相應的參數會被傳入,同時上下文 this 會被指定爲這個新實例。new foo 等同於 new foo(),只能用在不傳遞任何參數的情況
  • 如果構造函數返回了一個對象,那麼這個對象會去取代整個 new 出來的結果。如果構造函數沒有返回對象,那麼 new 出來的結果爲步驟一創建的對象
    6.對於原型鏈的代碼,如下所示:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>原型鏈</title>
  </head>
  <body>

    <script type="text/javascript">
     
      M.prototype.say = function () {
          console.log('say hi');
      };
      var o5 = new M('o5');


      var new2 = function (func) {
          var o = Object.create(func.prototype);
          var k = func.call(o);
          if (typeof k === 'object') {
              return k;
          } else {
              return o;
          }
      };

    </script>
  </body>
</html>

二、面向對象

  1. 對於面向對象,分爲類與實例和類與繼承,類與實例包括類的聲明、生成實例,類與繼承包括實現繼承和繼承的幾種方式。
  2. 對於類的聲明,如下所示:
  • 類的聲明,代碼如下
    var Animal = function () {
        this.name = 'Animal';
    };
    
    
  • es6class 的聲明
    
    class Animal2 {
        constructor () {
            this.name = 'Animal2';
        }
    }
    
  1. 對於生成實例,如下所示:
  console.log(new Animal(), new Animal2());
  1. 對於類與繼承的實現及方式,如下所示:
  • 藉助構造函數實現繼承,但是缺點是 child1 沒有繼承 Parent1 原型對象的方法,代碼如下所示:
  function Parent1 () {
      this.name = 'parent1';
  }
  Parent1.prototype.say = function () {

  };
  function Child1 () {
      Parent1.call(this);
      this.type = 'child1';
  }
  console.log(new Child1(), new Child1().say());
  • 藉助原型鏈實現繼承,但是缺點是 s1 改變的東西,s2 也會看到,代碼如下所示:
  function Parent2 () {
      this.name = 'parent2';
      this.play = [1, 2, 3];
  }
  function Child2 () {
      this.type = 'child2';
  }
  Child2.prototype = new Parent2();

  var s1 = new Child2();
  var s2 = new Child2();
  console.log(s1.play, s2.play);
  s1.play.push(4);
  • 組合方式,Parent3 初始化了兩次,指向 Parent3 構造函數,代碼如下所示:
  function Parent3 () {
      this.name = 'parent3';
      this.play = [1, 2, 3];
  }
  function Child3 () {
      Parent3.call(this);
      this.type = 'child3';
  }
  Child3.prototype = new Parent3();
  var s3 = new Child3();
  var s4 = new Child3();
  s3.play.push(4);
  console.log(s3.play, s4.play);
  • 組合繼承的優化一,但是缺點是指向 Parent4 的構造函數,無法區分實例是由父類創建的,還是子類創建的,代碼如下所示:
  function Parent4 () {
      this.name = 'parent4';
      this.play = [1, 2, 3];
  }
  function Child4 () {
      Parent4.call(this);
      this.type = 'child4';
  }
  Child4.prototype = Parent4.prototype;
  var s5 = new Child4();
  var s6 = new Child4();
  console.log(s5, s6);

  console.log(s5 instanceof Child4, s5 instanceof Parent4);
  console.log(s5.constructor);
  • 組合繼承的優化二,代碼如下所示:
  function Parent5 () {
      this.name = 'parent5';
      this.play = [1, 2, 3];
  }
  function Child5 () {
      Parent5.call(this);
      this.type = 'child5';
  }
  Child5.prototype = Object.create(Parent5.prototype);

三、通信類

  1. 對於通信類,分爲 同源策略及限制、前後端的通信、創建 ajax 的過程和 跨域通信的方式。
  2. 對於同源策略及限制,同源策源限制從一個源加載的文檔或腳本如何與來自另一個源的資源進行交互,這是一個用於隔離潛在惡意文件的關鍵的安全機制,如下所示:
  • Cookie、LocalStorage和IndexDB 無法讀取
  • DOM 無法獲得
  • Ajax 請求不能發送
  1. 對於前後端的通信,如下所示:
  • Ajax
  • WebSocket
  • CORS
  1. 對於創建 ajax 的過程,如下所示:
  • XMLHttpRequest 對象的工作流程
  • 兼容性處理(XMLHttpRequest只有高級瀏覽器中支持,低版本中要用xmlhttp=new ActiveXObject(“Microsoft.XMLHTTP”);
  • 事件的觸發條件
  • 事件的觸發順序
  1. 對於跨域通信的方式,如下所示:
  • JSONP
  • Hash
  • postMessage
  • WebSocket
  • CORS
  1. jsonp.js 的代碼,如下所示:
/**
 * 功能類庫
 */
 /**
  * [util 工具類]
  * @type {Object}
  */
 var util = {};

 /**
  * [function 返回數組的指定項]
  * @param  {[type]} array [description]
  * @param  {[type]} item  [description]
  * @return {[type]}       [description]
  */
 util.indexOf = function (array, item) {
     for (var i = 0; i < array.length; i++) {
         if (array[i] === item) {
             return i;
         }
     }
     return -1;
 };

 /**
  * [function 判斷是否爲函數]
  * @param  {[type]} source [description]
  * @return {[type]}        [description]
  */
 util.isFunction = function (source) {
     return '[object Function]' === Object.prototype.toString.call(source);
 };

 /**
  * [isIE 判斷是不是ie]
  * @return {Boolean} [如果是ie返回版本號,不是則返回false]
  */
 util.isIE = function () {
     var myNav = navigator.userAgent.toLowerCase();
     return (myNav.indexOf('msie') != -1) ? parseInt(myNav.split('msie')[1]) : false;
 };

 /**
  * [function 對象淺複製]
  * @param  {[type]} dst [description]
  * @param  {[type]} obj [description]
  * @return {[type]}     [description]
  */
 util.extend = function (dst, obj) {
     for (var i in obj) {
         if (obj.hasOwnProperty(i)) {
             dst[i] = obj[i];
         }
     }
 };

 /**
  * [function 獲取一個隨機的5位字符串]
  * @param  {[type]} prefix [description]
  * @return {[type]}        [description]
  */
 util.getName = function (prefix) {
     return prefix + Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 5);
 };

 /**
  * [function 在頁面中注入js腳本]
  * @param  {[type]} url     [description]
  * @param  {[type]} charset [description]
  * @return {[type]}         [description]
  */
 util.createScript = function (url, charset) {
     var script = document.createElement('script');
     script.setAttribute('type', 'text/javascript');
     charset && script.setAttribute('charset', charset);
     script.setAttribute('src', url);
     script.async = true;
     return script;
 };

 /**
  * [function jsonp]
  * @param  {[type]} url      [description]
  * @param  {[type]} onsucess [description]
  * @param  {[type]} onerror  [description]
  * @param  {[type]} charset  [description]
  * @return {[type]}          [description]
  */
 util.jsonp = function (url, onsuccess, onerror, charset) {
     var callbackName = util.getName('tt_player');
     window[callbackName] = function () {
         if (onsuccess && util.isFunction(onsuccess)) {
             onsuccess(arguments[0]);
         }
     };
     var script = util.createScript(url + '&callback=' + callbackName, charset);
     script.onload = script.onreadystatechange = function () {
         if (!script.readyState || /loaded|complete/.test(script.readyState)) {
             script.onload = script.onreadystatechange = null;
             // 移除該script的 DOM 對象
             if (script.parentNode) {
                 script.parentNode.removeChild(script);
             }
             // 刪除函數或變量
             window[callbackName] = null;
         }
     };
     script.onerror = function () {
         if (onerror && util.isFunction(onerror)) {
             onerror();
         }
     };
     document.getElementsByTagName('head')[0].appendChild(script);
 };

/**
 * [json 實現ajax的json]
 * @param  {[type]} options [description]
 * @return {[type]}         [description]
 */
 util.json = function (options) {
     var opt = {
         url: '',
         type: 'get',
         data: {},
         success: function () {},
         error: function () {},
     };
     util.extend(opt, options);
     if (opt.url) {
         var xhr = XMLHttpRequest
            ? new XMLHttpRequest()
            : new ActiveXObject('Microsoft.XMLHTTP');
         var data = opt.data,
             url = opt.url,
             type = opt.type.toUpperCase(),
             dataArr = [];
         for (var k in data) {
             dataArr.push(k + '=' + data[k]);
         }
         if (type === 'GET') {
             url = url + '?' + dataArr.join('&');
             xhr.open(type, url.replace(/\?$/g, ''), true);
             xhr.send();
         }
         if (type === 'POST') {
             xhr.open(type, url, true);
             xmlhttp.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
             xhr.send(dataArr.join('&'));
         }
         xhr.onload = function () {
             if (xhr.status === 200 || xhr.status === 304) {
                 var res;
                 if (opt.success && opt.success instanceof Function) {
                     res = xhr.responseText;
                     if (typeof res ==== 'string') {
                         res = JSON.parse(res);
                         opt.success.call(xhr, res);
                     }
                 }
             } else {
                 if (opt.error && opt.error instanceof Function) {
                     opt.error.call(xhr, res);
                 }
             }
         };
     }
 };

 /**
  * [function crc32加密]
  * @param  {[type]} str [description]
  * @return {[type]}     [description]
  */
 util.crc32 = function (url) {
     var a = document.createElement('a');
     a.href = url;
     var T = (function () {
         var c = 0,
             table = new Array(256);
         for (var n = 0; n != 256; ++n) {
             c = n;
             c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
             c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
             c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
             c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
             c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
             c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
             c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
             c = ((c & 1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
             table[n] = c;
         }
         return typeof Int32Array !=== 'undefined' ? new Int32Array(table) : table;
     })();
     var crc32_str = function (str) {
         var C = -1;
         for (var i = 0, L = str.length, c, d; i < L;) {
             c = str.charCodeAt(i++);
             if (c < 0x80) {
                 C = (C >>> 8) ^ T[(C ^ c) & 0xFF];
             } else if (c < 0x800) {
                 C = (C >>> 8) ^ T[(C ^ (192 | ((c >> 6) & 31))) & 0xFF];
                 C = (C >>> 8) ^ T[(C ^ (128 | (c & 63))) & 0xFF];
             } else if (c >= 0xD800 && c < 0xE000) {
                 c = (c & 1023) + 64;
                 d = str.charCodeAt(i++) & 1023;
                 C = (C >>> 8) ^ T[(C ^ (240 | ((c >> 8) & 7))) & 0xFF];
                 C = (C >>> 8) ^ T[(C ^ (128 | ((c >> 2) & 63))) & 0xFF];
                 C = (C >>> 8) ^ T[(C ^ (128 | ((d >> 6) & 15) | ((c & 3) << 4))) & 0xFF];
                 C = (C >>> 8) ^ T[(C ^ (128 | (d & 63))) & 0xFF];
             } else {
                 C = (C >>> 8) ^ T[(C ^ (224 | ((c >> 12) & 15))) & 0xFF];
                 C = (C >>> 8) ^ T[(C ^ (128 | ((c >> 6) & 63))) & 0xFF];
                 C = (C >>> 8) ^ T[(C ^ (128 | (c & 63))) & 0xFF];
             }
         }
         return C ^ -1;
     };
     var r = a.pathname + '?r=' + Math.random().toString(10).substring(2);
     if (r[0] != '/') {
         r = '/' + r;
     }
     var s = crc32_str(r) >>> 0;
     var is_web = location.protocol.indexOf('http') > -1;
     return (is_web ? [location.protocol, a.hostname] : ['http:', a.hostname]).join('//') + r + '&s=' + s;
 };

 export default util;

  1. 對於通信類,代碼如下所示:
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>通信類</title>
  </head>
  <body>
    <script type="text/javascript">
      // 創建ajax
      // 參考jsonp.js
    </script>

    <script src="http://www.abc.com/?data=name&callback=jsonp" charset="utf-8"></script>

    <script type="text/javascript">
      // jsonp({
      //     data: {
      //
      //     },
      // });
    </script>
    <script type="text/javascript">
      /**
       * 跨域通信的幾種方法
       */

      // jsonp工作原理,參考jsonp.js


      // 利用hash,場景是當前頁面 A 通過iframe或frame嵌入了跨域的頁面 B
      // 在A中僞代碼如下:
      var B = document.getElementsByTagName('iframe');
      B.src = B.src + '#' + 'data';
      // 在B中的僞代碼如下
      window.onhashchange = function () {
          var data = window.location.hash;
      };

      // postMessage
      // 窗口A(http:A.com)向跨域的窗口B(http:B.com)發送信息
      Bwindow.postMessage('data', 'http://B.com');
      // 在窗口B中監聽
      Awindow.addEventListener('message', function (event) {
          console.log(event.origin);
          console.log(event.source);
          console.log(event.data);
      }, false);

      // Websocket

      var ws = new WebSocket('wss://echo.websocket.org');

      ws.onopen = function (evt) {
          console.log('Connection open ...');
          ws.send('Hello WebSockets!');
      };

      ws.onmessage = function (evt) {
          console.log('Received Message: ', evt.data);
          ws.close();
      };

      ws.onclose = function (evt) {
          console.log('Connection closed.');
      };

      // CORS
      // url(必選),options(可選)
      fetch('/some/url/', {
          method: 'get',
      }).then(function (response) {

      }).catch(function (err) {
        // 出錯了,等價於 then 的第二個參數,但這樣更好用更直觀
      });
    </script>
  </body>
</html>

四、安全類

  1. 安全類,分爲 CSRFXSS
  2. 對於 CSRF 的基本概念,CSRF 通常稱爲跨站請求僞造,英文名Cross-site request forgery, 縮寫 CSRF
  3. 對於 CSRF 的攻擊原理,登錄過後記錄 cookie,其他網站利用接口,用cookie 攻擊,引誘點擊。
  4. 對於 CSRF 的防禦措施,如下所示:
  • Token 驗證
  • Referer 驗證
  • 隱藏令牌
  1. 對於 XSS 的基本概念,XSS 通常稱爲 跨站腳本攻擊,英文名 cross-site script,縮寫 XSS
  2. 對於 XSS 的攻擊原理,Scripting 是可以獲取頁面數據、獲取 Cookies、劫持前端邏輯、發送請求。
  3. 對於 XSS 的防禦措施,如下所示:
  • 對於 JavaScript 代碼,轉義 '\' 或者轉換成 json
  • 按白名單保留部分標籤和屬性
  • 使用 js-xss 這個第三方庫
  1. CSRFXSS 的區別,XSS 是向頁面注入 js 運行,CSRF 是利用本身的漏洞去執行接口,CSRF 要登錄網站。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章