前端跳槽面试总结之原型链、面向对象、通信类和安全类

一、原型链

  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 要登录网站。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章