面试题

151 阅读12分钟

http协议和https协议

http: 超文本传输协议,基于TCP/IP协议传输数据,应用最广泛的一种网络数据,所有的www文件都必须遵守这个标准。
https: 由SSL/TLS+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http安全。主要可以分为两种:一种是建立一个信息安全通道,保证数据传输的安全,另一种是确认网站的真实性。

区别:

http是超文本传输协议,信息是明文传输,https是具有安全性的ssl/tls加密传输协议。
https需要到CA申请证书
http和https使用的是完全不同的连接方式,http的端口是80,https的端口是443
http的连接很简单是无状态的,https是由ssl/tls+http协议构建的可进行加密传输、身份认证的网络协议,比http安全。

https的缺点:

https协议握手比较费时,会使页面的加载时间延长近50%,增加10%~20%的耗电。
https连接缓存不如http高效,会增加数据开销和功耗,
SSL证书需要钱,SSL证书通常需要绑定IP,不能在同一个IP上绑定多个域名
https协议的加密范围有限,在黑客攻击、拒绝服务攻击、服务器劫持方面起不到什么作用

实践建议

建议保留http,在切换的时候可以做http和https兼容,方式:去掉页面链接中的http头部,这样可以自动匹配http头和https头
参考链接: blog.csdn.net/qq_35745940…

mobx等、setstate 等

var、let、const理解

let声明和const声明,两个都是块级作用域,且var有变量提升,在let中,使用的变量一定要进行声明。
var可以重复声明,let不可以
var不受限于块级,let受限于块级
var可以在声明的上面访问变量,let有暂存死区,在声明上面访问会报错。
const声明后必须赋值,且不可变量否则会报错

react性能优化

react和vue的生命周期

vue的生命周期:1. beforeCreate(){}--->2.Create--->3.beforeMount---->4.mounted --->5.beforeUpdate--->6updated---->7.beforeDestroy ---->8.destoryed

beforeCreate(){
   //this.say()//这里会报错  this没有
},
created(){ //这里可以使用this  数据请求
    this.username="leson";
},
beforeMount(){//页面结构加载完成以前
},
mounted(){//页面结构完成
    //写dom操作  定时器 
    //事件  window.onscroll      
},      
updated(){
    console.log(this.userage);
},

react报错的时候如何看的

vue data为什么是个函数而不是对象

vue组件是可复用的vue实例,一个组件被创建好之后,可能被用在各个地方,组件被用了多少次,组件中的data数据都应该是互相隔离,互不影响的,基于这一理念,组件每复用一次,data数据就会被复制一次,当某一处复用的地方组件内data数据被改变时,其他复用地方组件的data数据不受影响。
如果data是对象的话,当被复用时,复用对象和源对象都会指向同一个内存地址,互相之间会互相影响,所以要是函数。

vue 渲染时 key 起到什么作用

key是虚拟dom对象的标识,当数据发生变化时,vue会根据新数据生成新的虚拟dom,随后vue进行新虚拟dom与旧虚拟dom的差异比较:
旧虚拟DOM中找到新虚拟DOM相同的key:若虚拟DOM中内容没变,直接使用之前的真实DOM,若虚拟DOM中内容变了,则生成新的真实DOM,随后替换掉页面中之前的真实DOM
旧虚拟DOM中未找到与新虚拟DOM相同的key:创建新的真实DOM随后渲染到页面

用index做key会引发的问题:

若对数据进行:逆序添加、逆序删除等破环顺序操作会产生没有必要的真实DOM更新

盒模型是什么

盒模型主要定义为:content、padding、margin、border
盒模型分为标准盒模型和IE盒模型
标准盒模型:windth = content; box-sizing:content-box; IE盒模型:width = padding+border+content; box-sizing:border-box;

css两个隐藏属性的区别

display:none;使元素不显示,不在占据空间; viability:hidden;元素隐藏的同时占据空间;

redux的执行流程

浏览器的缓存机制

浏览器的缓存机制就是把一个请求过的web资源拷贝一份副本存储存在浏览器中;
缓存会根据进来的请求保存输出内容的副本,当一下个请求到来的时候,如果是相同的url,缓存会根据缓存机制决定是直接使用副本响应访问请求,还是向服务器再次发送请求
比较常见的就是浏览器会缓存访问过的页面,当再次访问这个URL地址的时候,如果网页没有更新就不会再次下载网页,而是直接使用本地缓存的网页
只有当网站明确标识已更新,浏览器才会再次下载网页

跨域的解决方案

请求url的协议、域名、端口三者之间任意一个与当前页面url不同的即为跨域
1.通过设置Access-Control-Allow-Origin为*
2.jsonp进行跨域[jsonp只支持get方法] 3.使用proxy代理解决跨域

git工具应的操作流程

git init 初始化项目
git status 查看当前目录下文件的状态
git add (文件名 | .)添加到暂存盘,文件名代表某文件,"."代表所有文件
git commit -m "备注" 提交到git本地仓库,产生新版本,引号中的备注必须写
git log 查看所有提交的记录
git clone 链接 克隆远程仓库,进行连接
git checkout -b [branch] 新建一个分支,并切换到该分支
git checkout [branch] 切换到某分支
git branch -d [branch-name] 删除分支
git merge [branch] 合并指定分支到当前分支
git push 将本地仓库push到远程仓库\

事件循环[先执行同步任务,在执行异步任务,执行一次同步任务,异步任务执行一轮,就是这种机制无限循环]

先执行同步再执行异步
所有同步任务在主线程上执行,形成一个执行栈
主线程之外,存在一个任务队列,异步任务有了运行结果,就在任务队列中放置一个事件
一旦主线程的栈中所有同步执行完,系统就会读取任务队列
主线程要做的就是从任务队列中去实践,执行事件,执行完毕,再取事件,再执行事件,这样不断读取事件,执行事件的循环机制叫事件循环机制
先promise ---> .then ---> settimeout
先执行微任务再执行宏任务

css定位

position:static静态定位用于取消定位
position:relative相对定位,没有脱离标准流,在页面中占位置
position:absolute绝对定位,脱离了标准流,在页面中不占位
position:fixed固定定位,脱离了标准流,在页面中不占位

promise的理解

参考: www.jianshu.com/p/f6d4371dd…

js数组的常用方法

1. Array.push(),向数组的末尾添加一个或多个元素,并返回新的数组长度。原数组改变。

var arr = [1,2,3,4];
arr.push(5,6,7);
arr = [1,2,3,4,5,6,7];

2. Array.pop(),删除并返回数组的最后一个元素,若该数组为空,则返回undefined。原数组改变。

var arr = [1,2,3,4,5];
var del = arr.pop(); //6
arr = [1,2,3,4,5]

3. Array.unshift(),向数组的开头添加一个或多个元素,并返回新的数组长度。原数组改变。

var arr = [1,2,3,4,5,6,7];
var res = arr.unshift(0); //8
arr = [0,1,2,3,4,5,6,7]

4. Array.shift(),删除数组的第一项,并返回第一个元素的值。若该数组为空,则返回undefined。原数组改变。

var arr = [1,2,3,4,5,6];
var res = arr.shift();//1
arr = [2,3,4,5,6,7];

5. Array.concat(arr1,arr2…),合并两个或多个数组,生成一个新的数组。原数组不变。

var arr = [1,2,3,4,5,6,7];
var arr1 = ['a','b','c'];
var arr2 = ['x','y','z'];
var res = arr.concat(arr1,arr2);//[1,2,3,4,5,6,7,'a','b','c','x','y','z'];
arr = [1,2,3,4,5,6,7];

6. Array.join(),将数组的每一项用指定字符连接形成一个字符串。默认连接字符为 “,” 逗号。

var arr = [1,2,3,4];
var str = arr.join();//1,2,3,4
var str1 = arr.join('-');//1-2-3-4

7. Array.reverse(),将数组倒序。原数组改变。

var arr = [1,2,3,4];
arr.reverse()//[4,3,2,1];

8. Array.sort(),对数组元素进行排序。按照字符串UniCode码排序,原数组改变。

①从小到大

var sortNum = function(a,b){
    return a - b;
}
arr.sort(sortNum)

②从大到小

var sortNum = function(a,b){
    return b - a;
}
arr.sort(sortNum)

③按照数组对象中的某个值进行排序

var arr = [{name:"a",age:12},{name:"b",age:14},{name:"c",age:10}];
function fn(params){
    return function sortAge(a,b){
        return a[params] - b[params]
    }
}
arr.sort(fn('age'));// [{name:"c",age:10},{name:"a",age:12},{name:"b",age:14}]

9.Array.map(function),原数组的每一项执行函数后,返回一个新的数组。原数组不变。(注意该方法和forEach的区别)。 map 会返回一个新的数组,不会改变原来的数组,foreach不会反悔新数组,允许对原数组进行修改

10.Array.slice() 按照条件查找出其中的部分内容

参数:

array.slice(n, m),从索引n开始查找到m处(不包含m)

array.slice(n) 第二个参数省略,则一直查找到末尾

array.slice(0)原样输出内容,可以实现数组克隆

array.slice(-n,-m) slice支持负参数,从最后一项开始算起,-1为最后一项,-2为倒数第二项

返回值:返回一个新数组

是否改变原数组:不改变

11.Array.splice(index,howmany,arr1,arr2…) ,用于添加或删除数组中的元素。从index位置开始删除howmany个元素,并将arr1、arr2…数据从index位置依次插入。howmany为0时,则不删除元素。 原数组改变。

12.Array.forEach(function),用于调用数组的每个元素,并将元素传递给回调函数。原数组不变。(注意该方法和map的区别,若直接打印Array.forEach,结果为undefined)。

13.Array.filter(function),过滤数组中,符合条件的元素并返回一个新的数组。

14.Array.every(function),对数组中的每一项进行判断,若都符合则返回true,否则返回false。

15.Array.some(function),对数组中的每一项进行判断,若都不符合则返回false,否则返回true。

16.Array.reduce(function),reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。

17.indexOf() 检测当前值在数组中第一次出现的位置索引

参数:array.indexOf(item,start) item:查找的元素 start:字符串中开始检索的位置。

返回值:第一次查到的索引,未找到返回-1。

是否改变原数组:不改变。

11、includes()

判断一个数组是否包含一个指定的值

参数:指定的内容

返回值:布尔值

是否改变原数组:不改变。

接着面试官可能还会问你: 原数组改变的方法有:push pop shift unshift reverse sort splice 不改变原数组的方法有:concat map filter join every some indexOf slice forEach

ts的理解和作用

同源的理解

怎么判断数据类型

var arr = [1,2,3]
1. typeof arr
2. arr instanceof Array
3. (arr).constructor
4. Object.prototype.toString.call(arr)

浏览器输入url的过程

  1. 浏览器输入url
  2. 根据域名解析出IP地址
    1.检查浏览器缓存,有缓存:返回,没有缓存:下一步
    2.检查系统缓存hosts文件
    3.检查网络中路由器的dns缓存
    4.递归查询,优先查找其他域名服务器,看有没有,没有在查找本地域名服务器,本地域名服务器用迭代查询查找
    5.迭代查询不断向上访问查找
  3. 根据找到饿IP建立tcp连接进行三次握手
  4. 发送http请求
  5. 如果发生重定向,状态码是3开头,就返回第一步,继续匹配重定向的服务器
  6. 向重定向的服务器发送http请求
  7. 服务器处理请求,发送html响应
  8. tcp断开连接
  9. 根据响应,得到html渲染出界面
  10. 其他内容比如图片URL,返回第一步重新请求,如果请求过,就从浏览器缓存中得到

手写:

封装组件、重复渲染

输出8个console.log

console.log
console.table
console.error
console.info
console.debug
console.time
console.timeEnd
console.count

使用vue点击改变字体颜色,刷新页面颜色也不会丢失

this.$router.replace({
  name: 'Home',
  query: {
    color: 'red'
  }
})
/**  刷新当前界面 */
this.$router.go(0)

判断数组,至少两个

//方法一:
var arr = [];
arr instanceof Array
//方法二:
console.log([].constructor == Array);  //true
console.log({}.constructor == Object);  //true
console.log("string".constructor == String); //true
console.log((123).constructor == Number);  //true
console.log(true.constructor == Boolean);  //true
//方法三:
function isArray(o) {
    return Object.prototype.toString.call(o);
}
var arr=[2,5,6,8];
var obj={name:'zhangsan',age:25};
var fn = function () {}
console.log(isArray(arr)); //[object Array]
console.log(isArray(obj)); //[object Object]
console.log(isArray(fn));  //[object function]

防抖、节流

// 防抖
function debounce (callback,delay) {
    var t = null;
    return function () {
        clearTimeout(t);
        t = setTimeout(callback,delay);
    }
}
window.onscroll = debounce(function(){
    console.log("调用了一次");
},500)

// 节流;
function throttle (callback,duration){
    var lastTime = new Date().getTime();
    return function () {
        var now = new Date().getTime();
        if(now - lastTime > 500){
            callback();
            lastTime = now;
        }
    }
}
window.onscroll = throttle(function(){
    console.log("调用了一次");
},500)

邮箱的正则表达式

var emal = new RegExp(/^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/);
//邮箱
emal.test('aaa@qq.com')

var url = new RegExp(/^(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$/)
//url

var phone = new RegExp(/^1(3\d|4[5-9]|5[0-35-9]|6[567]|7[0-8]|8\d|9[0-35-9])\d{8}$/)
//手机号

参考: www.cnblogs.com/fozero/p/78…

回调函数的链式调用(用promise)

let checkLogin=()=> {
  return new Promise((resolve,reject)=>{
    let flag=document.cookie.indexOf("userId")!=-1?true:false;
    if(flag=true){
      resolve({
        status:0,
        result:true
      });
    }else{
      reject("error");
    }
  });
}
let getuseInfo=()=>{
  return new Promise((resolve,reject)=>{
    let useInfo={
      status:0,
      userId:101
    }
    resolve(useInfo);
  })
}
checkLogin().then((res)=>{
  console.log("Login Success");
  return getuseInfo();
},(error)=>{
  console.log(`error:${error}`);
}).then(res=>{
  console.log(`userId:${res.userId}`);
});
//Promise.all()的使用
Promise.all([checkLogin(),getuseInfo()]).then(([res1,res2])=>{
  console.log("Login Success");
  console.log(`userId:${res2.userId}`);
})

var arr = [1,2,3,4,5,6]的随机排序

方法一:
var arr =[1,2,3,4,3];
function fn(arr){
    var arr1 = arr.concat();
    arr1.sort(function(n1,n2){
        return Math.random() - 0.5;
    })
    return arr1
}
fn(arr)
方法二:
var arr = [1,2,3,4,3];
function fn2(arr){
    var result = [];
    var arr2 = arr.concat();
    (function(){
        if(!arr2.length){return}
        var index = Math.floor(Math.random()*arr2.length);
        result = result.concat(arr2.splice(index,1));
        arguments.callee();
    })();
    return result;
}
fn2(arr)

实现数组去重

方法一:
var arr =[1,1,2,3,4];
let res = []
for (let i = 0; i < arr.length; i  ) {
    if (res.indexOf(arr[i]) == -1) {
        res.push(arr[i])
    }
}
方法二:
var arr = [1,1,2,3,4]
[...new Set(arr)]
方法三:
var arr = [1,1,2,3,4]
Array.from(new Set(arr))

css手写三角形

div{
    width:0;
    height:0;
    border:3px solid transparent;
    border-top-color:red;
}

使用vue做一个弹窗组件,点击叉号关闭弹窗

<template>
    <transition name="move" appear>
        <div class="message" v-if="visible">
            <span>{{message}}</span>
            <span class="close" @click="closeMessage">X</span>
        </div>
    </transition>
</template>
<script>
export default {
  name: 'message',
  props: {
    message: {
      type: String,
      default: '内容'
    },
    visible: {
      type: Boolean,
      default: false
    },
    duration: {
      type: Number,
      default: 0
    }
  },
  data () {
    return {
      timer: null
    }
  },
  watch: {
    visible (val) {
      if (val) {
        this.autoClose()
      }
    }
  },
  mounted () {
    this.autoClose()
  },
  methods: {
    autoClose () {
      let _this = this
      if (this.duration !== 0) {
        clearTimeout(this.timer)
        this.timer = setTimeout(() => {
          _this.closeMessage()
        }, _this.duration + 500)
      }
    },
    closeMessage () {
      this.$emit('close', false)
    }
  }
}
</script>
<style scoped lang="scss">
.message{
  min-width: 200px;  
  border: 1px solid #ccc;
  position: fixed;
  left: 50%;
  top: 50%;
  transform: translate(-50%,-50%);
  transition: opacity .3s,transform .4s,top .4s;
  padding: 15px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  .close{
    color: #666;
    cursor:pointer;
  }
  &.move-enter,&.move-leave-to{
    opacity: 0;
    top: 0;
  }
  &.move-enter-active,&.move-leave-active{
    transition: 0.3s linear;
  }
}
</style>

// Main.js
import message from './message.vue'
import Vue from 'vue'
let vm
const createMessage = (propsData) => {
  if (Vue.prototype.$isServer) return
  propsData = propsData || {}
  if (typeof propsData === 'string') {
    propsData = {
      message: propsData
    }
  }
  const Ctor = Vue.extend(message)
  vm = new Ctor({ propsData }).$mount()
  vm.$on('close', flag => {
    vm.visible = flag
  })
  document.body.appendChild(vm.$el)
  return vm
}
export default {
  install (vue) {
    vue.component(message.name, message)
    vue.prototype.$BMessage = createMessage
  }
}
//调用页面
this.$BMessage({
    visible: true,
    message: 'hello world',
    duration: 3000
})

执行结果

async function async1(){
    console.log('1');
    await async2();
    console.log('2')
}
async function async2(){
    console.log('3')
}
console.log('4');
setTimeout(function(){
    console.log('5');
},0)
async1();
new Promise(resolve=>{
    console.log('6');
    reslove();
}).then(function(){
    console.log('7')
})
console.log('8')

//4、1、3、6、8、2、7、5


async function async1() {
  console.log('async1 start');
  await async2();
  console.log('async1 end');
}
async function async2() {
  console.log('async2');
  return new Promise(function(){
      console.log('a')
  }).then(function(){
      console.log('b')
  })
}
 
console.log('script start');
setTimeout(function() {
  console.log('setTimeout');
}, 0)
async1();
new Promise(function(resolve) {
  console.log('promise1');
  resolve();
}).then(function() {
  console.log('promise2');
});
console.log('script end');

//script start---> async1 start--->async2--->a--->promise1--->script end--->async1 end--->promise2--->setTimeout

查找字符串中出现最多次数的字母

var str="ddasdasdasdasdasf";
function text(str){
    var num=0;
    var value='';
    var json={}
    for(var i=0;i<str.length;i++){
        if(!json[str[i]]){
            json[str[i]]=[];
        }
        json[str[i]].push(str[i]);
    }
    for(var i in json){
        if(num<json[i].length){
            num=json[i].length;
            value=i;
        }
    }
    console.log('出现最多次数的是:'+value+'总共出现:'+num+'次');
}
text(str)