面试总结

作者: 杰米桀弥 | 来源:发表于2018-05-17 21:36 被阅读0次

    JS中的块级作用域

    1.with 2.try.. catch 3.let, const

    变量提升和函数提升

    • 包括变量和函数在内的所有声明都会在任何代码被执行前首先
      被处理
    • 函数声明比变量声明优先提升\
    • 只有声明会被提升,变量的赋值或者其他运行逻辑会留在本地

    什么叫闭包?

    闭包是能够访问另一个函数作用域中变量的函数,创建闭包:将函数作为函数的返回值;将函数作为参数传递。

    使用场景:实现对象的数据私有化;代替一些全局变量;

    什么叫原型、原型链?

    每个函数都有一个prototype属性,这个属性就是原型。原型链就是对象之间的继承链,一个对象通过的prototype指向一个父对象,父对象的prototype又指向另一个对象,最终指向Object对象。这一个关系链就是原型链

    如何优化网站性能?

    1. Http请求

    • 合并js,css文件,雪碧图减少http请求的数量,压缩文件,减少请求的大小;

    • 资源文件按需加载;

    • 合理使用缓存,sessionStorage,cookie,文件加上MD5戳;

    • 数据懒加载,比如PC端可以分页,移动端可以上拉加载

    2.HTML方面

    • 合理化使用元素,减少不必要的元素

    • 避免使用iframe,ifram很消耗资源

    3.JS方面

    • js文件放在页面底部,因为渲染网页的顺序是由上至下,如果放在顶部会等待js加载,有可能会出现空白

    • 避免在html中直接写js,而是独立一个js文件

    • 减少DOM访问和修改。合并多次操作,修改元素的样式会导致重绘,添加删除DOM,修改DOM位置导致重排 (重新排列位置);

    • 删除不需要的脚本,合理的设计结构,实现模块化增强复用性;

    4.CSS方面

    • 样式表放在开头,迅速渲染页面样式;

    • 减少行内样式吗,单独css文件可以缓存

    • 合理编写css,减少css层级

    • 添加一些必要的loading提示

    5.server方面

    • 使用CDN

    • 合理的数据查询语句,适当的缓存

    HTTP状态码

    1XX 信息状态码

    • 100 Continue: 继续发送请求

    2XX 成功状态码

    • 200 OK: 请求成功

    • 201 Created: 创建新资源请求已实现

    • 202 Acceped 服务器已接收请求,但是还未处理

    • 204 No Content 没有响应内容,跨域option就是204

    3XX 重定向状态码

    • 300 Muiltiple Choices 请求有多个资源

    • 301 Moved Permanently 请求的URL已移除

    • 304 Not Mofdified 资源未被修改

    4XX 客户端错误状态码

    • 400 Bad Request 发送了一个错误请求(参数确实或错误)

    • 401 Unauthorized 未授权

    • 403 Forbidden 请求被拒绝

    • 404 Not Found 找不到资源

    5XX 服务端错误状态码

    • 500 internal Server Error 服务器发生错误

    • 502 Bad Gateway 代理出错

    Vue相关

      a. vue和Angularjs的区别
    
    1. AngularJS采用双向数据绑定,vue默认使用单向数据绑定

    2. vue中也有双向数据绑定,angularjs是基于脏检查,而vue是基于getter和setter

    3. AngularJS属于MVVM框架,而vue相当于view层

    4. vue更容易上手,API完整有完整的生命周期;

      b. vue和Jquery的区别
    
    1. vue采用数据驱动,尽量避免DOM操作,Jquery使用核心是DOM操作 ;

    2. Jquery本质上是封装了DOM操作的函数库,vue属于一个框架;

      c. vue的原理 
    
    • 采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调
    
    Object.defineProperty(person, 'name', {
    
      set: function(newVal) {
    
        temp['name'] = newVal;
    
        console.log('为person设置新的姓名:' + newVal);
    
      },
    
      get: function() {
    
        var _name =  temp['name'] || '默认姓名';
    
        console.log('获取person的姓名:' +  _name);
    
        return _name;
    
      }
    
    });// 当person复制或取值的时候回调用set,get,
    
    
      d. vue生命周期
    
    • 一共分为8个阶段:创建前/后,载入前/后,更新前/后,销毁前/后

    • created阶段数据已经准备好了,但是html还没有渲染完成

    • mounted html已经渲染完成

    • destory 解除事件监听和dom绑定,但是dom结构还在

      e. vuex
    
    • vuex作用:管理Vue组件的状态(当出现多个视图组件依赖同一个状态,来自不同视图的行为需要变更同一个状态。)

    排序方式

    1. 冒泡排序

    相邻元素两两比较

    
    function bubbleSort(arr) {
    
        var length = arr.length;
    
        for(let i = 0; i < length; i++) {
    
          for(let j = 0; j < length - 1; j++) {
    
            if(arr[j + 1] < arr[j]) {
    
              let tem = arr[j+ 1];
    
              a[j+ 1] = a[j];
    
              a[j] = tem;
    
            }
    
          }
    
        }
    
        return arr;
    
    }
    
    
    1. 选择排序

    选择最小的

    
    function selectSort(arr) {
    
        let length = arr.length;
    
        let minIndex, temp;
    
        for(let i = 0; i < length; i++) {
    
          minIndex = i;
    
          for(let j = i + 1; j < length; j++) {
    
            if(arr[j] < arr[minIndex]) {
    
                minIndex = j;
    
            }
    
          }
    
          if(i != minIndex) {
    
              temp = arr[minIndex];
    
          arr[minIndex] = arr[i];
    
          arr[i] = temp;
    
          }
    
        }
    
        return arr;
    
    }
    
    

    3.插入排序

    类似打牌,每选择一个元素就找适合它的位置

    
    function insertSort(arr) {
    
      let length = arr.length;
    
      let newArr = [];
    
      for(let i = 1; i < length; i++) {
    
        let key = arr[i];
    
        let j = i - 1;
    
        while(arr[j] > key) {
    
          arr[j + 1] = arr[j];
    
          j--;
    
        }
    
        arr[j + 1] = key;
    
      }
    
      return arr;
    
    }
    
    

    清除浮动的方式

    1. overflow:hidden

    2. 容器元素最后添加元素,使用clear:both

    3. 伪元素

    
    .clearfix:after{
    
     content:"";//设置内容为空
    
      height:0;//高度为0
    
      line-height:0;//行高为0
    
      display:block;//将文本转为块级元素
    
      visibility:hidden;//将元素隐藏
    
     clear:both//清除浮动
    
     }
    
    .clearfix{
    
      zoom:1;为了兼容IE
    
        }
    
    

    水平垂直居中的方式

    1. margin: auto; 必须知道高度
    .item {
      postion: absoulate;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      margin: auto;
    }
    
    1. margin 高宽一半; 必须知道高度和宽度
    .item {
      postion: absoulate;
      top: 50%;
      left: 50%;
      height: 100px;
      width: 100px;
      margin-top: -50px;
      margin-left: -50px;
    }
    
    1. transform; 不需要知道高度和宽度
    .item {
      postion: absoulate;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
    }
    
    1. flex; 兼容性问题
    .item {
      dispaly: flex;
      justify-content:center;
      align-items: center;
    }
    

    实现深度克隆

    function deepClone(obj) {
      var toString = Object.prototype.toString;
      // null, undefined, {}, function
      if(!obj || typeof obj !== 'object') {
          return obj;
      }
    
      if(toString.call(obj) === '[object Date]') {
        return new Date(obj.getTime());
      }
    
      if(toString.call(obj) === '[object RegExp]') {
        var flags = [];
        if(obj.global) {
          flags.push('g');
        }
        if(obj.multiline) {
          flags.push('m');
        }
        if(obj.ignoreCase) {
          flags.push('i');
        }
        return new RegExp(obj.source, flags.join(''))
      }
      
      let temp = obj instanceof Array ? [] : {};
      for(var i in obj) {
         if(obj.hasOwnProperty(i)) {
            temp[i] = deepClone(obj[i]);
         }
      }
      return temp;
    }// 优化, 可以尾部调用递归
    

    数组去重

    1. 利用对象属性唯一
    function unique(array) {
      let obj = {};
      let newArray = [];
      for(let i = 0; i < array.length; i++) {
         if(!obj[array[i]]) {
            obj[array[i]] = true;
            newArray.push(array[i]);
         }
      }
      return newArray;
    }
    

    2.两层循环 splice

    function unique2(arr) {
        let length = arr.length;
      for(var i = 0; i < length; i++) {
        for(var j = i + 1; j < length; j++) {
            if(arr[j] == arr[i]) {
              arr.splice(j, 1);
              length --;
              j --;
            }
        }
      }
      return arr;
    }
    

    3.ES6 set 去重

    function unique3(arr) {
      return Array.from(new Set(arr));
     // return (...new Set(arr)) 扩展运算符
    }
    

    内存泄露

    • 不再用到的内存,没有及时释放就叫内存泄露
    • 垃圾回收机制:标记清除(最常用),和引用计数
    • 常见内存泄露情况:
      1. 意外的全局变量,比如未定义,直接变量提升(采用严格模式防止)
      2. 闭包过多,闭包中用到的变量不会被回收
      3. dom清空或删除时,事件未清除导致的内存泄漏,及时移除事件
      4. 循环引用(引用计数永远是1)

    事件流阶段

    捕获阶段、目标阶段、冒泡阶段

    Promise

    • Promise 好处
      将异步接口以同步的流程表现出来
    • Promise对象的两个特点:
      1. 对象的状态不受外界影响;
      2. 一旦状态改变,就
    • Promise 的三个状态
      pending,resolved,rejected
      Promise状态改变只有两种可能:从pending到fulfilled,从pending到rejected
    • Promise 内部的错误不会影响到 Promise 外部的代码(Promise会吃掉错误)
    • Promise.resolve 将现有对象转化为Promise对象
       Promise.resolve('foo')
       // 等价于
       new Promise(resolve => resolve('foo'))
      

    Promise.resolve方法的参数分成四种情况。
    (1) 参数是一个Promise对象
    原封不动返回
    (2) 参数是一个 thenable对象(有then属性方法)
    会将对象转化为Promise对象,然后立即执行其中的then方法

     let thenable = {
     then: function(resolve, reject) {
       resolve(222);
     }
    };
    Promise.resolve(thenable)
     .then(res => console.log(res));
    (3) 参数没有then方法, 或者根本不是对象
    会返回一个新的Promise对象,状态为resolved
    
    const p = Promise.then('hello');
    p.then(function(s) {
      console.log(s);
    }); // hello
    
    (4) 不带任何参数时,直接返回一个resolved状态的Promise对象
       因此可以使用Promise.then() 创建一个新的Promise对象
    
    • 使用Promise封装ajax
      let mineAjax = function(url, method, data) {
      let promise = new Promise(function(resolve, reject) {
       const handler = function() {
         if(this.readyState === 4  && this.status === 200) {
           resolve(this.responce);
         } else {
           reject(new Error(this.statusText));
         }
       };
       const client = new XMLHttpRequest();// new 一个 ajax对象
       data = getQueryString(data);// 对象数据转'&'连接的字符串
       if(method == 'post') {
         client.open(method, url);
         client.setRequestHeader('Content-type', 'application/x-www-form-urlencoded');// post 要设置header
         if(data) {
           client.send(data);
         } else {
           client.send();
         }
       }
       if(method == 'get') {
         url += data;
         client.open(method, url);
         client.send();
       } 
         client.onreadystatechange = handler;
         client.responseType = 'json';
       });
       return promise;
      }
      function getQueryString(query) {
       let result = [];
       for(let key in query) {
         result.push(`${key}=${query[key]}`);
       }
       if(result.length > 0) {
         return result.join('&');
       }
      }
      mineAjax('testurl", 'post', {data: test}).then(function(res){
       console.log(res);
      }, function(error) {
       console.log(error);
      });
      
    • Promise.prototype.then
      1. then 是写在 promise原型上
      2. then方法返回的是一个新的Promise实例
      3. 链式写法,前一个then的返回值下一个then的参数

    js写原生ajx

    1. new XMLHttpRequest;
    2. 使用open方法,设置请求方法(get/post)、url
    3. 设置发送数据,数据为(a=1&b=2)的格式
    4. 如果是post请求设置请求头 setRequestHeader('Content-type', 'application/x-www-form-urlencoded');
    5. send, 如果有数据 send(data),没有send();
    6. 服务器响应事件,onreadystatechange,当readyState == 4 && status == 200的时候表示响应成功
    • ajax readState
      0 - (未初始化)还没有调用send()方法
      1 - (载入)已调用send()方法,正在发送请求
      2 - (载入完成)send()方法执行完成,已经接收到全部响应内容
      3 - (交互)正在解析响应内容
      4 - (完成)响应内容解析完成,可以在客户端调用了

    设计模式

    • 单体模式
      概念: 单体是一个用来划分命名空间,并将一批属性和方法组织在一起的对象
      应用: 将代码封装在一个对象中,只暴露一个入口
      好处:
      1. 可以用来划分命名空间,减少全局变量的数量;
      2. 使用单例模式可以使代码组织更为一致,便于阅读和维护
      3. 可以被实例化,且实例化一次
      var Singleton = {
        attribute: true,
        method1: function() {},
        method2: function() {}
      };
    
    • 工厂模式
      概念: 用于创建对象实例,封装实例创建过程,只关心创建结果
      应用:处理一些共享相同属性的组件,或者对象,比如提示框;AngularJS factory
      缺点: 没有解决对象的识别问题,都是object
    function animal(opts) {
      var obj = new Object();
      obj.name = opts.name;
      obj.color = opts.color;
      obj.getInfo = funtion() {
        return name;
      }
    return obj;
    }
    var cat = animal({name: '波斯猫', color: '白色'});
    
    • 构造函数模式
      概念: 用于创建特定类型的对象
      优点: 解决了工厂模式无法识别类型的问题(instanceof Animal == true)
      缺点: 有些公共方法,需要重复定义
    function Animal(name, color) {
      this.name = name;
      this.color = color;
      this.getName = function() {
        return this.name;
      }
    }
    var cat = new Animal('猫', '白色');
    cat.getInfo();
    
    • 原型模式
      概念: 将属性都放在原型上;
      优点: 所有所有实例可以共享他的属性和方法
      缺点: 共享属性和方法,导致一个实例更改属性或方法就会影响其他实例
    function Animal() {}
    Animal.name = '猫';
    Animal.color = '白色';
    var cart1 = new Animal();
    var cart2 = new Animal();
    
    • 混合模式(构造函数模式和原型模式结合)
      概念:构造函数负责属性,原型模式负责公共方法或属性
       function Animal(name, color) {
         this.name = name;
         this.color = color;
       }
       Animal.prototype.getInfo = function() {
          return this.name + ' ' + this.color;
       }
      
    • 创建对象的方式:
    1. 对象字面量和Object构造函数
    2. 工厂模式:抽象了对象的实现过程,但是无法知道对象的类型
    3. 构造函数模式:new 操作符,可以判断实例类型(即instanof可以判断),缺点无法使用公共属性
    4. 原型模式:将公共属性添加到prototype中;
    5. 组合使用构造函数模式和原型模式:构造函数模式用于定义实例属性,原型模式用于定义方法和共享的属性。使用最广泛的一种方法
    6. 动态原型模式: 把初始化原型的过程也封装在构造函数中;
    • 发布订阅者模式
      概念: 一对多的映射关系,让多个观察者对象同时监听某一个主题对象,当该对象改变时,依赖于它的对象都将得到通知;
      优点:支持简单的广播通信,对象改变会自动通知订阅过的对象
      发布者和订阅者的耦合性降低
      缺点:创建订阅者需要消耗一定的时间和内存

    跨域

    为什么跨域:XHR对象只能访问同一个域中的资源,为了防止某些恶意行为,但是有时候需要跨域访问

    1. 图像Ping
    • 一个网页可以从任何网页中加载图像
    • 常用于跟踪用户点击页面或动态广告曝光次数(1px图片)
    1. JSONP (JSON with padding)
    • JSONP由回调函数和数据组成
    • 因为script 可以不受限的从其他域获取资源;
    • 有安全问题,确定JSONP是否请求失败不容易;
    1. CORS (cors origin resource sharing)
    2. 代理 nginx转发

    TCP 三次握手

    TCP核心思想:既要保证数据可靠传输,又要提高传输的效率,三次握手刚好可以满足
    在TCP/IP协议中,TCP协议提供可靠的连接服务,采用三次握手建立一个连接。
    第一次握手:客户端发送syn包到服务器;
    第二次握手:服务器确认客户端的sync包,同时发送一个sync + ack包到客户端
    第三次握手:客户端收到服务器发的包,向服务器发送确认包ACK完成三次握手

    TCP和UDP的区别

    TCP面向有链接,能正确处理丢包, UDP面向无连接,不管对方有没有收到

    HTTP

    HTTP是建立在TCP协议基础上的,http是一种短连接,是一种无状态的连接

    从输入URL到页面加载发生了什么

    1.输入URL,

    1. 浏览器根据URL查找是否有缓存,并且判断缓存是否过期,如果没过期则从缓存中读取,如果过期则需要重新读取
    2. DNS查找域名的IP地址
      • 先从浏览器缓存中找,在从操作系统缓存中找,再从路由器缓存中找
      • 没有缓存,则进行DNS递归查找
    3. 同服务器建立TCP连接,然后发起http请求
    4. 服务器收到请求并解析,将请求转发到服务程序;
    5. 服务程序读取请求并作出响应;
    6. 服务器通过TCP连接发送回浏览器;
    7. 浏览器接收响应,检查状态码,作出响应;
    8. 解析HTML文档,构建DOM树结构,下载图片、视频、css、js资源等,构建CSSOM树
      10.根据DOM树和CSSOM树构建渲染树, 执行js脚本
    9. 最后显示HTML

    浏览器缓存机制

    浏览器缓存就是把一个已经请求过的web资源(html,图片,js等)拷贝一份副本存储在浏览器中;

    • 浏览器缓存的控制
    1. 使用HTML Meta标签
    2. 使用和缓存有关的http报文
     <meta http-equiv="Pragma" content="no-cache">  
    

    项目相关

    1. Angularjs和Vue你觉得区别在哪里?
      • 从使用上看,Vue使用更为方便,有完整的api包括生命周期,文档也个更为齐全
    • Angularjs指令和组件没有区分开,都是用directive,而Vue是完全分开的
    • Vue性能更好,Angularjs 的双向绑定是基于脏检查的 ,当 watcher 越来越多时会变得越来越慢,因为作用域内的每一次变化,所有 watcher 都要重新计算。则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter;
      a. 脏值检查: 就是不关心你如何以及何时改变的数据,只关心在特定的检查阶段(UI事件,ajax事件, timeout 延迟事件),数据是否改变。
      b. angularjs賍值检查的实现:
      每一个绑定到UI上的数据 都拥有一个对应的$watch对象,这个对象会被push到watch list中, $watch包括两个函数属性
    watch = {
      name: '', // 当前watch的对象
      getNewValue: function($scope) {// 得到新值
        return newValue;
      },
      listener: function(newValue, oldValue) {// 当数据发生改变时候需要执行的操作
        ...
      }
    };
    
    

    c. 手动出发脏检查,$apply进入angular上下文,$digest触发脏检查

    gulp和webpack的区别

    两者不应该拿来比较,
    gulp属于前端流程优化工具,它可以自动刷新页面、压缩技术,css,编译less,自动化
    而webpack是模块化方案,是一个前端资源加载/打包工具,从官网的图片就可以看出Webpack 可以将多种静态资源 js、css、less 转换成一个静态文件,减少了页面的请求

    this

    • this 的绑定和函数声明的位置没有任何关系,只取决于函数的调用方式。
    • this取值情况分为4种情况:
      1. 构造函数,如果函数作为构造函数(new),那么this指向new出来的对象
      2. 函数作为对象的一个属性,并且作为对象的一个属性被调用的时候,this指向该对象(隐式绑定);
      3. 函数使用call或apply调用的时候,this的值就去传入对象的值;(显示绑定)
      4. 全局并且调用普通函数,this指向window(nodejs中指向global)
      5. 箭头函数根据外层作用域(函数或者全局)决定this

    作用域

    • 作用域在函数定义的时候就已经确定,而不是函数调用时确定
    • 作用域中变量的值是在执行过程中产生和确定的
    • 自由变量跨作用域取值要去创建函数的作用域找

    执行上下文

    执行上下文指的是以下三种数据的准备情况:

    1. 变量(包括函数表达式)的变量声明,默认赋值为undefined
    2. this的赋值;
    3. 函数声明的赋值
      通俗的讲就是把将要用到的所有变量都实现声明和赋值
      函数每被调用一次,都会产生一个新的执行上下文环境
      处于活动状态的执行上下文环境只有一个,执行不同上下文的过程,是一个压栈出栈的过程——执行上下文栈

    常用正则

    1. 去除空格
    • 所有空格
      replace(/\s*/g, '');
    • 去除两头空格
      replace(/^\s|\s$/g, '');
    • 去除左边空格
      replace(/^\s*/g, '')
    • 去除右边空格
      replace(/\s*$/g, '')
    1. 数字
    • 整数 /^\d+$/;
    • 数字 /^\d*.?\d+$/

    圣杯布局和双飞翼布局

    • 圣杯布局
      <div class="container">
        <div class="middle"><h4>中间弹性区</h4></div> 
        <div class="left"><h4>左边栏</h4></div> 
        <div class="right"><h4>右边栏</h4></div>
      </div>
      <style>
      .container {
                height: 200px;
                overflow: hidden;
                padding: 0 200px;
            }
    
            .middle {
                width: 100%;
                height: 200px;
                background-color: deeppink;
                float: left;
                
            }
    
            .left {
                width: 200px;
                height: 200px;
                background-color: blue;
                float: left;
                margin-left:-100%;
                position: relative;
                left: -200px;
            }
    
            .right {
                width: 200px;
                height: 200px;
                background-color: darkorchid;
                float: left;
                margin-left:-200px;
                position: relative;
                right: -200px;
            }
      </style>
    
    • 双飞翼布局
    <div class="container2">
        <div class="middle2"><div><h4>中间弹性区</h4></div></div> 
        <div class="left2"><h4>左边栏</h4></div> 
        <div class="right2"><h4>右边栏</h4></div>
      </div>
    .container2 {
                height: 200px;
                overflow: hidden;
                margin-top: 20px;
            }
            .left2 {
              width: 200px;
              height: 200px;
              background-color: green;
              float: left;
              margin-left: -100%;
            }
            .right2 {
                width: 200px;
                height: 200px;
                background-color: red;
                float: left;
                margin-left: -200px;
            }
            .middle2 {
                width: 100%;
                height: 200px;
                float: left;
                background-color: orange;
            }
            .co {
                margin: 0 200px;
            }
    

    清除浮动

    1、clear清除浮动(添加空div法)

    在浮动元素下方添加空div,并给该元素写css样式:   {clear:both;height:0;overflow:hidden;}
    

    2、方法:给浮动元素父级设置高度
    3、父元素overflow:hidden

    overflow: hidden;
    *zoom: 1;
    
    1. after伪类
    .clear:after{content:' ';display:block;clear:both;height:0;overflow:hidden;visibility:hidden;}
    .clear{zoom:1;}
    

    相关文章

      网友评论

        本文标题:面试总结

        本文链接:https://www.haomeiwen.com/subject/uxmpkftx.html