let 、var、const的区别

  1. var 声明的变量会挂载在windows上,而let 和 const声明的变量不会
  2. var 声明的变量存在变量提升,let 和 const 不存在
  3. 同一作用域下 var 可以声明同名变量,let 和 const不可以
  4. let 和 const声明会形成块级作用域
  5. let 和 const存在暂时性死区
  6. const 一旦声明必须赋值,不能用 null 占位,声明后不能再修改,如果声明的是复合类型数据,可以修改属性

get 和 post的区别

  1. 按照Restful接口规范,get一般是查询数据,post一般是发送添加数据
  2. 从参数可见性来说,get相对隐秘性没post好,如果没有https等加密手段的话,它们的安全性是一样的不好
  3. 从传输数据大小来说,get不能大于2KB,post传参一般认为是无限制,但是每个浏览器会有自己的设置
  4. 从缓存角度,get能够被浏览器缓存,并且可以被完整记录为书签
  5. get 和 post 都是基于TCP/IP协议,所以它们能做的事情基本相同,get的参数在url上,post参数在body中,其实get也可以在body中带参,post也可以在url上带参
  6. get只能支持ASCll字符,而POST没有限制
  7. get只产生一个数据包,浏览器会把header和data一起发送出去,post会产生两个数据包 浏览器先发送header,服务器响应100 continue,浏览器再发送data,服务器响应200 ok,并不是所有浏览器都会在POST中发送2次包,Firefox就只发一次

手写冒泡

function bubble(arr){
for (let i=0;i<arr.length-1;i++){
for(let j=0;j<arr.length-1-i;j++){
if(arr[j]>arr[j+1]){
let t=arr[j];
arr[j]=arr[j+1];
arr[j+1]=t;
}
}
}
return arr;
}

手写原生ajax

GET请求

let xml=new XMLHttpRequest();
//请求方式 ,请求地址 ,是否异步(true:异步 false:同步)
xml.open('GET','https://autumnfish.cn/api/joke/list?num=3',true);
//发送请求
xml.send();
xml.onload=function(){
// 获取响应的内容 xml.responseText
console.log(xml.responseText);
}

POST请求

let xml=new XMLHttpRequest();
xml.open('POST','http://127.0.0.1:3000/api/users/login',true);
//设置请求头
xml.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
//发送请求
xml.send('usersname=xyh&password=admin');//参数
xml.onload=function (){
console.log(xml.responseText);
}

POST请求参数格式

urlencoded格式参数

//设置请求头
xml.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
//发送请求
xml.send('usersname=xyh&password=admin');//参数

json格式参数

//设置请求头
xml.setRequestHeader('Content-Type','application/json');
//发送请求
xml.send(JSON.stringify({username:'xyh',password:'admin'}));//参数

ajax状态码

属性描述
onreadystatechange存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。
  • 0: 请求未初始化
  • 1: 服务器连接已建立
  • 2: 请求已接收
  • 3: 请求处理中
  • 4: 请求已完成,且响应已就绪
  • status200: “OK”
    404: 未找到页面

    示例

    let xml=new XMLHttpRequest();
    xml.open('GET','https://autumnfish.cn/api/joke/list?num=3',true);
    xml.send();
    xml.onreadystatechange=function(){
    if(xml.readyState==4 && xml.status==200){
    console.log(xml.responseText);
    }
    }

    监听事件区别

    image-20220720144746040

    什么是webpack

    webpack是前端项目自动构建发布的一种工具 自动构建的操作包含:兼容性处理 语法转换 合并 优化 打包 压缩,比较适合单页面应用 项目的结构也需要符合webpack的要求 webpack要求项目要有两个文件 一个入口文件 一个是webpack.config.js(是一个nodejs模块) 默认情况下还有一个src目录 用于存放源代码包含入口文件 项目打包后有一个构建目录build
    打包流程:

    1. 根据入口文件 梳理各个文件之间的依赖关系 把相同类型的文件打包成chunk块
    2. 对每个块进行语法转换 兼容性处理等工作
    3. 进行打包压缩优化
    4. 输出打包好的文件

    核心配置:
    entry:配置入口文件的名称和路径

    output:配置文件打包后 存放的文件目录

    module:用于配置语法转换兼容等问题的加载器 默认支持JS和JSON 这两种文件不需要加载器

    plugins:插件 用于完成打包压缩优化等工作

    mode:开发模式(development) 和 产品模式(production) 开发模式下不需要打包压缩优化等工作提高开发效率 产品模式下需要全部工作都做完

    vue2.0双向绑定原理

    通过Object.defineProperty方法给对象添加属性,可以给属性附加get和set方法,修改属性数据会触发set方法,在set方法里面就可以修改页面元素显示。当页面元素被修改的时候触发某个事件,在事件处理函数中修改对象的属性数据,触发set方法。这样就可以实现双向绑定

    let obj={
    text:''
    }
    Object.defineProperty(obj,'text',{
    tet:'',
    get(){
    return this.tet;
    },
    set(val){
    this.tet=val;
    document.querySelector('#inp').value=val;
    document.querySelector('#inv').innerHTML=val;
    }
    });
    document.querySelector('#inp').addEventListener('keyup',function(e){
    obj.text=e.target.value;
    })

    Kapture 2022-07-20 at 23.55.37

    将如下Https请求用Promise形式改写

    wx.request({
    url:'tet',
    success(res){
    console.log(res.data);
    }
    });

    //promise封装
    function req(params){
    let host="http://localhost:3000/users/login";
    let jwtheader={'Authorization':'Bearer 令牌'};
    return new Promise((resolve,reject)=>{
    wx.request({
    url:host+params.url,
    method:params.method || 'POST',
    data: params.data || {},
    header:params.header || JWTHeader,
    success(data){
    console.log(data);
    }
    })
    })
    }

    举出三种垂直居中的方法

    <div  class="wrap">
    <div class="box"></div>
    </div>

    flex

    .wrap{
    width:300px;
    height:300px;
    border: 1px solid red;
    display:flex;
    justify-content:center;
    align-items:center;
    }
    .box{
    height:100px;
    width:100px;
    boder:1px solid blue;
    }

    position定位已知宽高

    .wrap{
    width:300px;
    height:300px;
    position:relative;
    }
    .box{
    position:absolute;
    width:100px;
    height:100px;
    top:50%;
    left:50%;
    margin-top:-50px; // 已知宽高
    margin-left:-50px; // 已知宽高
    }

    margin与定位

    .wrap{
    position: relative;
    width: 300px;
    height: 300px
    }

    .box{
    margin: auto;
    height: 100px;
    height: 100px;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    position: absolute;
    }

    position定位未知宽高

    .wrap{
    position:relative;
    }
    .box{
    position:absolute;
    top:50%;
    left:50%;
    transform:translate(-50%,-50%); // 未知宽高
    }

    总结

    1. 文本垂直居中,line-height设为与height同样的高度
    2. 绝对定位+transform,子元素中:position: absolute; top: 50%;left: 50%;translate(-50%,-50%)
    3. 绝对定位+margin,子元素中:position: absolute; top:0;bottom: 0; margin: auto;
    4. flex+副轴居中,父元素中:display: flex; align-items: center;
    5. 父元素设为表格模式,display: table-cell; vertical-align: middle;

    什么是JWT

    jwt是json web token的简写,是一种前后端交互的数据规范,用于保证服务端访问的安全性。
    jwt其实是一种json字符串规范,把一个字符串分为三个部分。
    第一部分:头部,header,字符串的简单描述
    第二个部分: payload负载,就是指携带的数据,包括签发日期,过期时间,自定义参数等等。
    第三个部分: sign,数字签名,作用是保证在接收jwt令牌之前,令牌的内容没有被恶意修改过。
    最后把三个部分用点号连接起来形成一个完整的字符串,然后进行base64编码

    session和cookie的区别

    1. cookie数据存放在客户的浏览器上,session数据放在服务器上
    2. cookie不是很安全,可以分析存放在本地的cookie并进行cookie欺骗,比如跨站脚本攻击
    3. session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,如果主要考虑到减轻服务器性能方面,应当使用cookie
    4. 单个cookie在客户端的限制是3K,就是说一个站点在客户端存放的cookie不能3K。
    5. 所以:将登陆信息等重要信息存放为session;其他信息如果需要保留,可以放在cookieE中

    sesson和cookie的关系

    1. 浏览器端第一次发送请求到服务器端,服务器端创建一个Session,同时会创建一个特殊的Cookie(name为jsessionid的固定值,value为session对象的ID),然后将该Cookie发送至浏览器端
    2. 浏览器端发送第N(N>1)次请求到服务器端,浏览器端访问服务器端时就会携带该name为jsessionid的Cookie对象
    3. 服务器端根据name为jsessionid的Cookie的value(sessionId),去查询Session对象,从而区分不同用户。

    说出至少4种vue的指令和用法

    • v-if:根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定 / 组件被销毁并重建。
    • v-show:根据表达式之真假值,切换元素的 display CSS 属性。
    • v-for:循环指令,基于一个数组或者对象渲染一个列表,vue 2.0以上必须需配合 key值 使用。
    • v-bind:动态地绑定一个或多个特性,或一个组件 prop 到表达式。
    • v-on:用于监听指定元素的DOM事件,比如点击事件。绑定事件监听器。
    • v-model:实现表单输入和应用状态之间的双向绑定
    • v-pre:跳过这个元素和它的子元素的编译过程。可以用来显示原始 Mustache 标签。跳过大量没有指令的节点会加快编译。
    • v-once:只渲染元素和组件一次。随后的重新渲染,元素/组件及其所有的子节点将被视为静态内容并跳过。这可以用于优化更新性能。

    描述一下vue中封装axios的思路和方法

    1. 封装request.js,通过axios.create()创建实例对象并导出,设置公共的主机,超时时间等等
    2. 使用创建的实例对象,设置请求拦截器和响应拦截器,在请求拦截器中可以设置统一的请求头,比如设置jwt令牌,响应拦截器可以统一对返回的结果做判断和处理,比如可以统一判断错误码进行弹框提示,提前读取data数据并返回
    3. 封装api,创建api目录,根据表名每个表创建一个xxxapi.js,每个xxxapi.js中导入request.js,封装增删改查等方法,然后导出
    4. 每个组件只需要导入需要的api即可
    //导入
    import axios from 'axios';
    //配置
    let http=axios.create({
    //设置基准路径
    baseURL:'http://localhost:8090/api/',
    //超时
    timeout:5000
    })
    //请求拦截器
    http.interceptors.request.use(res=>{
    let token=sessionStorage.getItem('token');
    res.header.Authorization=token;
    return res;
    },err=>{
    return Promise.reject(res);
    });
    //响应拦截器
    http.interceptors.response.use(res=>{
    return res.data;
    },err=>{
    return Promise.reject(res);
    })

    作用域的理解

    作用域链的作用是保证执行环境里有权访问的变量和函数是有序的,作用域链的变量只能向上访问,访问到windows对象即被终止,作用域链向下访问是不允许的。

    函数作用域内使用的变量,如果在本作用域找不到定义,就会向上一级查找,一层一层查找,直到找到全局作用域,如果都没有则返回undefined,这种一层一层类似锁链的关系,叫作用域链

    onclik 和 addEventListener区别

    1. onclik写在标签中 addEventListener写在JS中
    2. onclik只能绑定点击事假 addEventListener可以绑定多种事件
    3. 两个都可以绑定多个事件 onclik后面的事件会覆盖前面的事件 addEventListener则不会
    4. addEventListener可以精确控制事件的触发阶段 通过第三个参数来控制,默认是false冒泡阶段触发 如果为true则在事件捕获阶段重复制粘贴
    5. onclik只能对HTML元素起作用 addEventListener对象任何元素都有用

    async 和 await的区别

    async是一个修饰符 async默认会返回一个Promise对象,因此asyncd函数可以执行进行then操作,返回值即为the方法传入的函数
    await关键字只能放在async的内部 await关键字的作用就是获取promise返回的内容,获取的是promise中resolve或reject的值,如果await后面并不是一个promise,则会同步重新除处理返回unedfined

    普通函数和箭头函数的区别

    1. 写法不同,箭头函数写法更加简洁 使用箭头定义
    2. 箭头函数都是匿名函数 普通函数既有匿名函数也有具名函数
    3. 箭头函数不能使用构造方法,不能使用new
    4. 箭头函数中的this指向不同,在普通函数值中this总是指向调用它的对象 如果有构造函数this指向创建的的实例,箭头函数本身不创建this,但声明时可以捕获其上下文this给自己使用
    5. 箭头函数没有argumrnts对象,每个普通的函数调用后都有一个arguments对象
    6. 箭头函数使用apply和call时调用时不能改变this指向 只能传参数

    什么闭包

    内层函数中可以访问外层函数的作用域
    好处:变量不回收,防止全局变量污染
    坏处:造成内存泄漏

    function add(){
    let ad=0;
    return function ad(){
    ad++;
    console.log(add);
    }
    }
    const res=add();
    res();

    如何将类数组转成标准数组

    类数组就是arguments

    • Array.from();
    • 扩展运算符(…);
    • [].slice().call(类数组);

    apply call 和 bind的区别

    • applay的第二个参数是数组 callbind的第二个参数是列表
    • applycall都是立即执行函数
    • bind不是立即执行而是返回新的函数

    数组去重的方法

    //第一种
    function t1(arr){
    return Array.from(new Set(arr));
    }

    //第二种
    function t2(arr){
    for(let i=0;i<arr.length;i++){
    for (let j=i+1;j<arr.length;j++){
    if(arr[j]===arr[i]){
    arr.splice(j,1);
    j--;
    }

    }
    }
    return arr;
    }

    //第三种
    function t3(arr){
    return arr.filter((items,index)=>{
    return arr.indexOf(items,0)===index;
    })
    }

    //第四种
    function t4(arr){
    let map=new Map();
    let rear=new Array();
    for (let i=0;i<arr.length;i++){
    if(map.has(arr[i])){
    map.set(arr[i],true);
    }else{
    map.set(arr[i],false);
    rear.push(arr[i]);
    }
    }
    return rear;
    }

    //第五种
    function t5(arr){
    return [...new Set(arr)]
    }

    实现promise all

    function t1(){
    return new Promise((resolve,reject)=>{
    setTimeout(()=>{
    resolve("Task1 4秒");
    },4000)
    })
    }

    function t2(){
    return new Promise((resolve,reject)=>{
    setTimeout(()=>{
    resolve("Task2 1秒");
    },1000)
    })
    }


    function t3(){
    return new Promise((resolve,reject)=>{
    setTimeout(()=>{
    resolve("Task3 3秒");
    },3000)
    })
    }

    //实现方法
    Promise.myall=function(promise){
    let arr=[];
    let count=0;
    return new Promise((resolve,reject)=>{
    promise.forEach((items,index)=>{
    Promise.resolve(items).then((res)=>{
    arr[index]=res;
    count+=1;
    if(promise.length===count){
    resolve(arr);
    }
    }).catch(reject);
    })
    })
    }

    //测试

    Promise.all([t1(),t2(),t3]).then((res)=>{
    console.log('Promise all');
    console.log(res);
    });

    Promise.myall([t1(),t2(),t3]).then((res)=>{
    console.log('Promise myall');
    console.log(res);
    })

    image-20220726090213697

    实现promise race

    function t1(){
    return new Promise((resolve,reject)=>{
    setTimeout(()=>{
    resolve("Task1 4秒");
    },4000)
    })
    }

    function t2(){
    return new Promise((resolve,reject)=>{
    setTimeout(()=>{
    resolve("Task2 1秒");
    },1000)
    })
    }


    function t3(){
    return new Promise((resolve,reject)=>{
    setTimeout(()=>{
    resolve("Task3 3秒");
    },3000)
    })
    }

    Promise.myrace=function(promise){
    return new Promise((resolve,rejejct)=>{
    for (let items of promise){
    Promise.resolve(items).then(resolve,rejejct);
    }
    })
    }


    Promise.race([t1(),t2(),t3()]).then((res)=>{
    console.log(res);
    })


    Promise.myrace([t1(),t2(),t3()]).then((res)=>{
    console.log(res);
    })

    image-20220726091256507

    css画三角形

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
    .d1{
    width: 0px;
    height:0px;
    border-width: 150px;
    border-style: solid;
    border-color: transparent transparent pink;
    }

    .d2{
    width:0px;
    height:0px;
    border-width:150px;
    border-left: 80px solid transparent;
    border-right: 80px solid transparent;
    border-bottom: 160px solid gold;
    }
    </style>
    </head>
    <body>
    <div class="d1">
    </div>
    <hr>
    <div class="d2">

    </div>
    </body>
    </html>

    iShot_2022-07-26_09.48.59

    快速排序

    function t1(arr){
    if(arr.length<=1){
    return arr;
    }

    let mk=Math.floor(arr.length/2);
    let nk=arr.splice(mk,1)[0];

    let left=[];
    let right=[];

    for(let i=0;i<arr.length;i++){
    if(arr[i]<nk){
    left.push(arr[i]);
    }else{
    right.push(arr[i]);
    }
    }
    return t1(left).concat([nk],t1(right));
    }

    let at=[1,29,10,5,345,90,23,12];
    console.log(t1(at));//[1, 5, 10, 12, 23, 29, 90, 345]

    css画扇形

    <!DOCTYPE html>
    <html lang="en">
    <head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
    div{
    width:100px;
    height:100px;
    background-color:pink;
    border-radius: 100px 0 0;
    }
    </style>
    </head>
    <body>
    <div>

    </div>
    </body>
    </html>

    iShot_2022-07-26_10.29.02

    box-sizing有哪些属性并且说明作用

    CSS盒模型本质上是一个盒子,封装周围的HTML元素,它包括:边距,边框,填充,和实际内容。
    盒模型允许我们在其它元素和周围元素边框之间的空间放置元素。
    Content-box(标准盒模型)
    宽度和高度分别应用到元素的内容框
    在宽度和高度之外绘制元素的内边距和边框

    border-box(怪异盒模型)
    元素指定的任何内边距和边框都将在已设定的宽度和高度内进行绘制
    通过从已设定的宽度和高度分别减去边框和内边距才能得到内容的宽度和高度

    inherit: 继承其父元素的box-sizing属性

    浏览器的内核

    Trident、webkit、gecko

    HTML5新特性

    语义化标签:main、footer、header、aside、article
    增强表单、音频标签、画布、地理定位、本地存储、websocket

    HTML 和 HTML5区别

    1. 文档类型定义,H5简洁
    2. html增加大量语义化标签
    3. 图片,html5通过canvas可以直接在浏览器上绘图

    清除浮动

    1. 父元素的最后面加上一个空白div,设置clear:both
    2. 父元素也设置浮动
    3. 父元素设置overflow:hidden
    4. 父元素设置高
    5. 创建伪类样式
    .clsearfix:after{
    content:'';
    display:block;
    clear: both;
    }

    水平居中

    1. 固定宽度,父元素都不浮动,通过设置外边距margin:0 auto;
    2. 绝对定位 通过设置left:0;right:0;margin:auto;
    3. 弹性盒子 justify-content:center;
    4. 父元素都浮动的情况下 margin-left:50% transform:translateX(-50%)

    bootstrap栅格系统用于屏幕适配

    1. 手机:col-xs 小于768px;
    2. 平板电脑屏幕:col-sm 768-992px
    3. pc:col-md 992-1200px;
    4. 大PC:col-lg 1200px;

    什么是vue-loader

    vue-loader是webpack的一个插件,负责把vue模板相关的语法转换成浏览器能够解析的语法文件

    1. vue-loader解析.vue文件把template,style,script三部分 分别提取出来,把它们分别交给对应的loader去进行处理
    2. 有了vue-loader等一些loader插件 才可以使用.less.scss这些预处理css文件 .less文件一般交给css-loader处理 vue-template-compiler:对template部分进行转换

    vuex有哪几种状态和属性,分别有什么用

    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式,它采用集中式存储管理应用的所有组件的状态
    作用:多组件、多页面间的数据共享。解决了组件之间统一状态的共享问题,实现组件之间的数据持久化。
    在项目中可以用vuex存放数据,不用每次都要请求后端服务器,这就在保证了数据新鲜度的同时提高了使用性能
    属性:
    state:用于存储数据
    getters:用于获得需要计算state后得出的值,比较简单的数据转换。
    mutations:更改自身state的值
    actions:通过调用mutations修改state值,通常在这里发送异步请求
    modules:类似包的概念,封装各个state,避免冲突,便于维护

    作用域的理解

    作用域的作用是保证执行环境里面有权访问变量和函数是有序的,作用域的变量只能向上访问,访问到window即终止,作用域链的变量向下访问是不允许的,函数作用域中的变量如果在本作用域中没有找到该变量的定义,就会向上一级查找,一层一层向上找,直到找到全局作用域,如果都没有则返回unedfined,这样类似锁链的关系叫做作用域链

    vue2.x双向绑定原理

    通过Object.defineProperty方法来给对象添加属性,可以给属性附加get和set方法,修改属性触发set方法,set方法里面可以修改页面的元素显示,当页面的元素显示被修改时触发某个监听事件,当事件处理函数时修改对象的属性触发set方法,这样就可以实现数据双向绑定

    let obj={
    text:''
    }

    Object.defineProperty(obj,'text',{
    tet:'',
    set(val){
    this.tet=val;
    document.querySelector("#inv").value=val;
    document.querySelector("#ind").innerHTML=val;
    },
    get(){
    return this.tet;
    }
    });
    document.querySelector("#inv").addEventListener('keyup',function(e){
    obj.text=e.target.value;
    });

    v-for的key的作用和你的设置方式

    Dom的变化会引起虚拟dom的对比操作,通过虚拟dom对比的变化来进行视图更新,没有key更新视图会全部删除然后重新渲染,消耗资源较高,有key值后通过对比,已存在的不需要重复操作以节约性能,且key最好是元素的唯一ID,不能是数组的index,因为数组有可能在容易地方添加元素,而导致数组index起不到唯一标识的目的,vue依旧会全部重新渲染,所以可以使用数组元素中不重复的属性值作为key

    vue声明周期函数的作用

    生命周期用于描述vue对象从创建到销毁的过程,这个过程分为几个阶段,每个阶段都对应的函数,这些函数叫做生命周期,也叫钩子函数,生命周期函数用于开发人员在不同时期进行相应的逻辑处理
    beforecreate:创建前el没有挂载,datat为unedfined
    create:创建后data有了,通常在这个阶段发送请求
    beforemount:挂载前,数据初始化完毕,但是没有解析到界面上
    mounted:挂载后data解析到页面上
    beforeupdate:更新前
    updated:更新后
    deforedestroy:销毁前
    destroyed:销毁后 组件的属性方法都销毁

    vue组件传值,兄弟传值

    1. 父传子 使用组件的props获取父元素传的值
    2. 子传父 通过指定事件传值 用$emit(‘函数名’,参数)
    3. 兄弟传值 创建一个中间vue对象,通过对象的属性来传值 使用$emit(‘函数名’,参数)发送数据,使用$on(‘函数名’,function(参数){})接收数据
    4. 使用本地存储 localStorage sessionStorage
    5. 使用vuex数据共享

    微信小程序页面间的传值方式

    1. 使用navigator标签 通过url属性按照get方式传值
    2. wx.navigateTo({url:‘’}) 传值
    3. 通过getcurrentPages() 获取页面栈传值
    4. 通过本地存储缓存传值
    5. 父传子 通过properties属性获取父元素的值
    6. 子传父 通过自定义事件传值 通过e.detail.属性名获取值

    判断一个字符串中出现次数最多的字符串 统计这个次数

    function t1(str){
    let o={};
    for (let i=0;i<str.length;i++){
    let k=str.charAt(i);
    if(o[k]){
    o[k]++;
    }else{
    o[k]=1;
    }
    }
    let max=0;
    let index='';
    for (let tu in o){
    if(o[tu]>max){
    max=o[tu];
    index=tu;
    }
    }
    console.log(max,index);
    return max;
    }

    消除行内块的间隙

    1. 给父元素设置 font-szie=0;
    2. 设置display:block