前端面试题集合


position包含几种属性?absolute和relative的区别?

static:默认状态、没有定位、正常流
inherit:从父元素集成position属性的值
fixed:生成绝对定位的元素(相对于浏览器窗口进行定位)
absolute:生成绝对定位的元素(相位与static定位以外的第一个父元素定位)
relative:生成相对定位的元素(相对于其正常位置定位)

前端性能优化方式

减少HTTP请求、使用内容发布网络、压缩组件、使用Expire头、JS放底部、CSS放顶部、避免CSS表达式等

什么是MVVM框架?

Model-View-ViewModel

数据绑定 + 视图刷新,跟MVC一样,主要目的是分离视图(View)和模型(Model)

数据驱动视图

利用@media screen实现网页布局的自适应。

XSS和CSRF如何攻防?

**XSS(Cross Site Scripting)**是跨站脚本攻击,为了区分CSS,所以缩写为XSS。恶意攻击者往Web页面里插入恶意Script代码,当用户浏览该页之时,嵌入其中Web里面的Script代码会被执行,从而达到恶意攻击用户的目的。

XSS漏洞修复

1.将重要的cookies标记为HTTP ONLY。
2.只允许用户输入我们期望的数据。如年龄框只能输入数字。
3.对数据进行HTTP Encode处理。
4.过滤或者移除特殊的HTML标签。
5.过滤JS事件的标签。

CSRF攻击的思想
用户浏览并登陆信任网站A;通过验证,在用户处产生X的cookie;用户在没有登出X的时候,浏览危险网站B;B要求访问第三方网站A,发出一个请求;根据这个请求,浏览器使用刚才产生的cookie直接访问A。

CSRF的防御
1.在表单里增加Hash值,以认证这确实是用户发送的请求,然后在服务器端进行Hash值验证。
2.验证码:每次的用户提交都需要用户在表单中填写一个图片上的随机字符串。

CSS实现垂直水平居中

常用的:父元素相对定位(position:relative),子元素绝对定位(absolute),width:200px;height:200px; top:50%;left:50%;margin-top:-100px;margin-left:-100px;

为何v-for要用key

快速查找到节点,减少渲染次数,提升渲染性能

vue组件如何通信

1.父子组件props和this.$emit
2.ref 链:父组件要给子组件传值,在子组件上定义一个 ref 属性,这样通过父组件的 r e f s 属性就可以获取子组件的值了,也可以进行父子,兄弟之间的传值 ( refs 属性就可以获取子组件的值了,也可以进行父子,兄弟之间的传值)

3.事件总线bus:使用一个空的VUE实例作为事件总线,自定义事件event.on event.o f f e v e n t . off event.offevent.emit
4 provide inject组件通信
5.vuex
6.attrs和listeners 仅仅是传递数据,而不做中间处理,attrs里存放的是父组件中绑定的非Props属性,listeners里存放的是父组件中绑定的非原生事件。

ajax请求应该放在哪个生命周期?

mounted,因为js是单线程,ajax异步获取数据

如何自定实现v-model

多个组件有相同逻辑,如何抽离?

使用mixin 对公共部分的逻辑进行抽离

何时使用keep-alive?

缓存组件不需要重复渲染,多个静态tab页切换,优化性能

vue为何是异步渲染,$nextTick何用?

因为如果不采用异步更新,那么每次更新数据都会对当前组件进行重新渲染,

$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调,在修改数据之后使用 $nextTick,则可以在回调中获取更新后的 DOM

vue常见性能优化方式?

1.合理使用v-if和v-show,
2.合理使用computed,
3.v-for加key,
4.自定义事件,dom事件及时销毁,
5.合理使用异步组件,
6.合理使用keepalive,
7.data层级不要太深,
8.使用vue-loader在开发环境做模板编译,
9.前端通用性能优化(如图片懒加载/减少 HTTP请求数/合理设置 HTTP缓存/资源合并与压缩/合并 CSS图片/将 CSS放在 head中/避免重复的资源请求/切分到多个域名),
10.使用ssr

说说vue的动态组件。

多个组件通过同一个挂载点进行组件的切换,is的值是哪个组件的名称,那么页面就会显示哪个组件

说一下vue的生命周期/钩子函数都有哪些?

双向数据绑定的理解?

vue采用数据劫持结合发布者-订阅者模式的方式,通过 Object.defineProperty劫持data属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。

vue组件中data为什么函数返回一个对象

因为组件是用来复用的,因为js里对象是引用关系,如果data是对象形式,那么data的作用域是没有隔离的,在多个子组件时,会被外部因素影响,如果data是一个函数,那么每个实例可以独自拥有一份返回对象的拷贝,组件实例之间的data属性值不会互相影响

按钮权限怎么做?

在点击左侧菜单,存储全部权限,每次点击单个时候,去计算获取当前页面的按钮权限,封装一个button组件,然后在需要的地方引用

vue声明周期都在哪些场景中使用?

1.beforeCreate(){}

创建前,访问不到data当中的属性以及methods当中的属性和方法,可以在当前生命周期创建一个loading,在页面加载完成之后将loading移除

2.created(){}

创建后,当前生命周期执行的时候会遍历data中所有的属性,给每一个属性都添加一个getter、setter方法,将data中的属性变成一个响应式属性

3.beforeMount(){}

模板与数据进行结合,但是还没有挂载到页面上。因此我们可以在当前生命周期中进行数据最后的修改

4.mounted(){}

当前生命周期数据和模板进行相结合,并且已经挂载到页面上了,因此我们可以在当前生命周期中获取到真实的DOM元素

5.beforeUpdate(){}

当数据发生改变的时候当前生命周期就会执行,因此我们可以通过当前生命周期来检测数据的变化

当前生命周期执行的时候会将更新的数据与模板进行相结合,但是并没有挂载到页面上,因此我们可以在当前生命周期中做更新数据的最后修改

6.updated(){}

数据与模板进行相结合,并且将更新后的数据挂载到了页面上。因此我们可以在当前生命周期中获取到最新的DOM结构

7.beforeDestroy(){}

当前生命周期中我们需要做事件的解绑 监听的移除 定时器的清除等操作

8.destroyed(){}

当前生命周期执行完毕后会将vue与页面之间的关联进行断开

GET和POST的区别

get参数通过url传递,post放在request body中
get请求在url中传递的参数是有长度限制的,而post没有
post比get更安全,因为get参数都暴漏在url中,所以不能用来传递敏感信息
get请求只能进行url编码,而post支持多种编码方式
get请求会浏览器主动cache,而post支持多种编码方式
get请求参数会被完整保留在浏览器历史记录里,而post中的参数不会被保留
get和post本质上就是TCP链接,并无差别,但由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同
get产生一个TCP数据包;post产生两个

cookie和seesion区别

cookie数据存放在客户的浏览器上,session存放在服务器
cookie不是很安全,别人可以分析存放在本地的COOKIE进行COOKIE欺骗,考虑安全应该使用seesion
session会在一定事件内保存在服务器上,当访问增多,会比较占用你的服务器的性能,考虑到减轻服务器性能方面,应当使用cookie
单个cookie保存的数据不能超过4k,很多浏览器都限制一个站点最多保存20个cookie

跨域的方法

jsonp:是通过script标签的src属性来实现跨域的,通过src传过去一个函数,把数据放在函数的实参调用就可以拿到数据,由于是用src的链接,所以jsonp只支持get方式
cors:改变请求头信息,客户端加:Origin:地址。服务器:Access-Control-Allow-Origin:地址.支持IE10以上。
webpack:devServer里配置proxy:{api:’地址’};
nginx反向代理:

call,apply,bind方法

  • call和bind的参数是依次传参,一一对应的;
  • 但apply只有两个参数,第二个参数为数组
  • call和apply都是对函数进行直接调用,而bind方法返回的仍是一个函数

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

普通函数可以有匿名函数,也可以有具体名函数,但是箭头函数都是匿名函数。

箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
普通函数的this指向调用它的那个对象

怎样理解Vue的单向数据流?

数据总是从父组件传到子组件,子组件没有权利修改父组件传过来的数据,只能请求父组件对原数据进行修改

vue-router是什么?有哪些组件?vue-router 路由钩子函数是什么?

路由管理器

钩子函数种类有:
全局的路由钩子函数:beforeEach、afterEach(一般用于全局进行权限跳转)
单个的路由钩子函数:beforeEnter、beforeLeave(路由内部钩子,一般在路由表里)
组件内的路由钩子函数:beforeRouteEnter、beforeRouteLeave、beforeRouteUpdate

axios是什么?如何使用它?

传统的Ajax是基于XMLHttpRequest(XHR),配置和调用方式等非常混乱.

功能特点:

  • 可以在浏览器中发送 XMLHttpRequests 请求
  • 可以在 node.js 中发送 http请求
  • 支持 Promise API
  • 可以拦截请求和响应
  • 可以转换请求和响应数据

为什么要创建axios的实例呢?

当我们从axios模块中导入对象时, 使用的实例是默认的实例。当给该实例设置一些默认配置时, 这些配置就被固定下来了。但是后续开发中, 某些配置可能会不太一样。比如某些请求需要使用特定的baseURL或者timeout或者content-Type等。这个时候, 我们就可以创建新的实例, 并且传入属于该实例的配置信息.

vuex有哪几种属性?

img

VC派发(Dispatch)消息到Actions,Actions提交(Commit)到Mutation,Mutation转变(Mutate)state,然后重新渲染整个页面。

import Vuex from 'vuex'
import Vue from 'vue'
Vue.use(Vuex)
const state = {
    sum:1
};
const mutations={
    ADDSUM(state,value)
    {
         state.sum+=value
    }
};
const actions={
    addSum({commit},value)
    {
         commit('ADDSUM',value)
    }
};
const getters = {
    bigSum(state)
    {
        return state.sum*20
    }
}
export default new Vuex.Store({
    state,
    mutations,
    actions,
    getters
})

使用:

<template>
  <div>
      <h1>姓名:{{name}}</h1>
      <h1>学校:{{school}}</h1>
      <h1>爵位:{{Marquis}}</h1>
  </div>
</template>
 
<script>
export default {
    name:'Information',
    computed:{
        school()
        {
            return this.$store.state.school;
        },
        sum()
        {
            return this.$store.state.sum;
        },
        name()
        {
            return this.$store.state.name;
        },
        Marquis()
        {
            return this.$store.state.Marquis;
        }
    }
}
</script>

为什么需要一个Actions,求和案例之中,我把参数传给Actions,Actions原封不动的又传给了Mutations,为什么我不直接传给Mutations呢?
答:确实是这样子。如果参数确定的话,可以跳过Actions,直接commit到Mutations里面。但是如果参数不确定的话,比如我需要向服务器要数据,这时候就必须用到Actions发送Ajax。

mapState mapGetters

img

img

什么是webpack,webpack有哪些优点?

webpack是一个现在的javaScript应用的静态模块化打包工具

把很多文件打包整合到一起, 缩小项目体积, 提高加载速度

1、loader主要用于转化某些类型的模块,它是一个转化器
2、plugin是插件,它是对webpack本身的扩展,是一个扩展器

Loader 是webpack中提供了一种处理多种文件格式的机制,因为webpack只认识JS和JSON,所以Loader相当于翻译官,将其他类型资源进行预处理。
用于对模块的”源代码”进行转换。

Plugin功能更强大,主要目的就是解决loader 无法实现的事情,比如打包优化和代码压缩等。

你有写过自定义指令吗?自定义指令的应用场景有哪些?

// 注册一个全局自定义指令 `v-focus`
Vue.directive('focus', {
  // 当被绑定的元素插入到 DOM 中时……
  inserted: function (el) {
    // 聚焦元素
    el.focus()  // 页面加载完成之后自动让输入框获取到焦点的小功能
  }
})
//  <input v-focus />

vue 如何快速定位那个组件出现性能问题的

⽤ timeline ⼯具。 通过 timeline 来查看每个函数的调⽤时常,定位出哪个函数的问题,从⽽能判断哪个组件出了问题

说说vue的动态组件

动态组件就是几个组件放在一个挂载点下,然后根据父组件的某个变量来决定显示哪个,或者都不显示。
在挂载点使用 component 标签,然后使用 is =“组件名”,它会自动去找匹配的组件名,如果有,则显示;

<div id="app">
    <component is="one"></component>
</div>
 
new Vue({
    el: '#app',
    components: {
        one: {template: '<div>我是线路一</div>'},
        two: {template: '<div>我是线路二</div>'},
        thr: {template: '<div>我是线路三</div>'}
    }
})

slot插槽

slot插槽,可以理解为slot在组件模板中提前占据了位置,当复用组件时,使用相关的slot标签时,标签里的内容就会自动替换组件模板中对应slot标签的位置,作为承载分发内容的出口

主要作用是:复用和扩展组件,做一些定制化组件的处理

Vue父子组件的生命周期顺序

加载渲染过程: 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程:父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程:父beforeUpdate->父updated
销毁过程: 父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

对SSR有了解吗,它主要解决什么问题?

Server-Side Rendering 我们称其为SSR,意为服务端渲染指由服务侧完成页面的 HTML 结构拼接的页面处理技术,发送到浏览器,然后为其绑定状态与事件,成为完全可交互页面的过程;

解决了以下两个问题:

seo:搜索引擎优先爬取页面HTML结构,使用ssr时,服务端已经生成了和业务想关联的HTML,有利于seo
首屏呈现渲染:用户无需等待页面所有js加载完成就可以看到页面视图(压力来到了服务器,所以需要权衡哪些用服务端渲染,哪些交给客户端)

v-model 的原理?

v-model 本质上不过是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件

vue2.x中如何监测数组变化

使用了函数劫持的方式,重写了数组的方法,Vue将data中的数组进行了原型链重写,指向了自己定义的数组原型方法
这样当调用数组api时,可以通知依赖更新。如果数组中包含着引用类型,会对数组中的引用类型再次递归遍历进行监控。
这样就实现了监测数组变化。

谈谈单页面(SPA)的理解?

SPA( single page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。
一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转
而页面的变化是利用路由机制实现 HTML 内容的变换,避免页面的重新加载。

合并对象的方法

Object.assign()

!注意! Object.assign()实行的是浅拷贝,也就是说如果源对象的属性是一个对象,那么目标对象得到的是这个对象的引用

防抖和节流

用一句话总结防抖和节流的区别:防抖是将多次执行变为最后一次执行,节流是将多次执行变为每隔一段时间执行

<body>
搜索:<input type="text" id="input1">
    <script>
        // 防抖 
        // 默认值200ms
        function debounce(fn,dalay=200) {
         let  timer=0;
            return function(){
             if(timer)   clearTimeout(timer);
                timer=setTimeout(()=>{
                     fn.apply(this,arguments)//透传this和参数
                     timer=0
                },dalay)
            }           
        }
      
        const input=document.getElementById("input1");
        input.addEventListener("keyup",debounce(()=>{
            console.log("发起搜索"+input.value)
        },1000))
    </script>
</body>
// 节流 不管时间触发了多少次 在规定事件内只会执行一次 
        function throttle(fn,delay=200) {
            let timer=0;
            return function(){
                if(timer) return ;
                timer=setTimeout(()=>{
                     fn.apply(this,arguments)//透传this和参数
                     timer=0
                },delay)
            }
        }

总结防抖和节流函数: js代码区别就在于if这里是清除定时器还是直接return终止函数

function throttleOrDebounce(fn,delay=3000) {
           let timer=0;
           return function (){
               // 防抖
               // if(timer) clearTimeout(timer);
               // 节流
               if (timer) return;
               timer=setTimeout(()=>{
                      fn.apply(this,arguments)
                      timer=0
               },delay)
           }
       }

前端攻击手段有哪些?该如何预防?

XSS :跨站脚本攻击
DDoS :分布式的、大规模的流量访问,使服务器瘫痪
CSRF :跨站请求伪造
SQL 注入
点击劫持

1, xss

Cross Site Script跨站脚本攻击
手段∶黑客将JS代码插入到网页内容中,渲染时执行JS代码
预防∶特殊字符替换(前端或者后端)

2,CSRF
Cross Site Request Forgery跨站请求伪造
手段:黑客诱导用户去访问另一个网站的接口,伪造请求
预防︰严格的跨域限制+验证码机制

3,点击劫持

Click Jacking
手段:诱导界面上蒙一个透明的iframe
,诱导用户点击
预防:让iframe不能跨域加载

4,DDoS
Distribute denial-of-service分布式拒绝服务
手段:分布式的、大规模的流量访问,使服务器瘫痪。例如传播了几百万的木马病毒,然后控制这几百万台设备在某一时间点同时访问

5, sql注入

手段:黑客提交内容时写入SQL语句,破坏数据库
预防∶处理输入的内容,替换特殊字符

JS中的Array.splice()和Array.slice()方法有什么区别

splice:截取出 slice: 截取

var arr=[0,1,2,3,4,5,6,7,8,9];//设置一个数组
console.log(arr.slice(2,7));//2,3,4,5,6
console.log(arr.splice(2,7));//2,3,4,5,6,7,8
//由此我们简单推测数量两个函数参数的意义,
slice(start,end)第一个参数表示开始位置,第二个表示截取到的位置(不包含该位置)
splice(start,length)第一个参数开始位置,第二个参数截取长度

slice不会对原数组产生变化,而splice会直接剔除原数组中的截取数据!

同步和异步

img

列举Java和JavaScript之间的区别?

Java是一种面向对象编程(OOPS)或结构化编程语言,类似的如C ++或C,而JavaScript是客户端脚本语言,它被称为非结构化编程

a++和++a的区别

a++相当于给a加了1,返回值是a的初始值;
++a同样相当于给a加了1,返回值是a加了1之后的结果。

1、a++
let a = 1;
const b = a++;  // b = 1 ,a = 2
// b = a++的过程可分解为
const add = function (a) {
    const result = a;
    a = a + 1;
    return result;
}
b = add(a)  // b = 1, a = 2

2++a
let a = 1
const b = ++a;  // b = 2  ,a = 2
// b = ++a的过程可分解为
const add = function (a) {
    a = a + 1;
    return a;
}
b = add(a)  // b = 2, a = 2

举例:

let a = 1;
const b = a++ + a;  // b = 3,a = 2
// 计算过程: b = 1 + 2
var a = 888;
++ a; // a = 889
alert(a ++); // 889

js Math对象的round(),ceil(),floor()方法

Math.round()**:四舍五入*取整。返回与x最接近的整数。当出现两个最接近的整数,将返回最大的那个整数。Math.round(1.5);//2*

Math.floor():对一个数进行下取整

Math.ceil():对一个数进行上取整

对this的理解:

this表示当前对象的一个引用,单独使用的时候,表示全局对象,在方法中使用,表示该方法所属对象;

this的指向并不是一成不变的,会随着上下文的改变而改变;

this的绑定通常是在函数或者方法调用的时候绑定,而不是在定义函数的时候去绑定;

this的绑定方法:

默认绑定:不符合其他绑定规则的时候,就是默认绑定,一般指向全局对象;

隐式绑定:当函数有上下文或者该函数的引用地址被某一个对象调用并通过对象的属性直接运行的时候,this就会绑定该函数;

显示绑定:call apply bind

new修饰符绑定;

虚拟dom的理解;

虚拟dom其实就是js对象,用来描述真实的dom对象;

真实的dom运行很慢,操作真实dom的代价是昂贵的,就算一个div的属性都有很多;

虚拟dom算法步骤:

1,将dom树转化为js对象树,产生第一个Vdom;

2,在数据发生变化的时候,生成第二个Vdom树;

3,diff算法逐层比较两个Vdom树,并标记增删操作;

4,将标记出来的差异,应用到真实的dom树;

Vuex的五个属性以及基本用法:

state:基本数据,存储变量;

getter:从state派生的数据,相当于是state的计算属性;

mutation:提交数据更新的方法,必须是同步的;

action:和mutation功能大致相同,不同之处在于action提交的是mutation,而不是直接变更状态,且可以包含异步操作;

modules:模块化Vuex,然给一个模块拥有自己的state,mutation,action,getters,使得结构清晰,方便管理;

js数据类型有哪些;

基本数据类型:Number,String,Boolean,BigInt,Symbol,null,undefined;

引用数据类型:Object,Array,Function;

判断数据类型的方式:typeOf,instanceOf,construct,toString;

typeOf:判断基本数据类型;typeof 对对象类型的值的类型不能作出准确判断,能准确判断出基本数据类型的值

instanceOf:判断比较复杂的数据类型;instanceof 只能用于判断对象,基本数据类型值不能判断,所以也不能准确的判断出所有的类型!

construct:constructor能判断基本数据类型string、number、boolean和对象类型(array、function等等),但是它不能判断undefined和null。所以它判断类型值也不十分准确!

Object.prototype**.toString**.call():能够判断所有的数据类型;最准确的方法;

Vue组件和插件的区别:

组件:实现应用局部功能;

插件:添加全局功能;

computed的特点:

支持缓存;

只有依赖改变,属性才会发生改变;

ajax和axiaos的区别:

ajax是原生XHR封装,axiaos是通过Promise对ajax的封装

Vue.Set的方法是如何实现的:set(target, key|index, value)

背景:因为defineProperty无法监听对象的增删,所以需要Set方法来实现响应式;

如何实现:

1,target判断为数组的情况,且有索引index,当前数组的长度与index最大值作为数组的长度,最后通过splice方法来处理增加数据还是修改数据;

2,target判断为对象的情况,直接通过target[key] = value来添加属性或者修改属性的值,再调用对应方法重新定义响应式

3,最后调用**notify()**来触发更新操作

vue的缺点:不利于SEO;

常用状态码:401,403,404,503,200;

401:未授权,请求身份验证;

403:禁止,服务器拒绝访问

404:未找到,服务器找不到请求的页面;

503:服务不可用,超载或停机维护

200:成功

Es5,Es6的区别:

1,引入箭头函数;传统JS的this是在运行的时候确定的,而不是在定义的时候确定的;而箭头函数的this是在定义时就确定的,不能被改变,也不能被call,apply,bind这些方法修改

2,引入块级作用域;let (花括号 块级作用域)

在 ES6 中通常用 let 和 const 来声明,let 表示变量、const 表示常量

◼️ 特点

let 和 const 都是块级作用域。以{}代码块作为作用域范围 只能在代码块里面使用,不存在变量提升,只能先声明再使用,否则会报错。在代码块内,在声明变量之前,该变量 都是不可用的。这在语法上,称为“暂时性死区”(temporal dead zone,简称 TDZ),在同一个代码块内,不允许重复声明。

const 声明的是一个只读常量,在声明时就需要赋值。(如果 const 的是一个对象,

对象所包含的值是可以被修改的。抽象一点儿说,就是对象所指向的地址不能改变,而

变量成员 是可以修改的。)

3,引入class类;

4,引入Promise;

5,引入模板字符串;

6,对象的扩展;对象的解构赋值;展开运算符;等等。

for..of和for..in的区别:

  1. for...in 语句用于遍历数组或者对象的属性(对数组或者对象的属性进行循环操作)。
  2. for in得到对对象的key或数组,字符串的下标
  3. for offorEach一样,是直接得到值
  4. **for of不能用于对象 **只能遍历带有iterator接口的,例如Set,Map,String,Array

js闭包:

目的:为了在函数外部可以访问函数内部的变量;

背景:变量的作用域,**父对象的所有变量,对子对象都是可见的,反之则不成立**

Javascript语言的特殊之处,就在于函数内部可以直接读取全局变量。另一方面,在函数外部无法读取函数内的局部变量。

出于种种原因,我们有时候需要得到函数内的局部变量。但是,正常情况下,这是办不到的,只有通过变通方法才能实现。那就是在函数的内部,再定义一个函数。

例如:函数F1中再定义一个F2,这样的话,F2就可以拿到F1的变量,把F2作为F1的返回值,这样就可以在外部访问F1的变量了;

常见的盒子垂直居中的方法有哪些请举例3种?

利用子绝父相定位方式来实现:

<style>
    .container{
        width: 300px;
        height: 300px;
        position: relative;
    }
    .conter{
        width: 100px;
        height: 100px;
        position: absolute;
        top: 50%;
        left: 50%;
        margin-top: -50px;
        margin-left: -50px;
    }
</style>

利用Css3的transform,可以轻松的在未知元素的高宽的情况下实现元素的垂直居中。

<style>
     .container{
         position: relative;
     }
     .conter{
         position: absolute;
         top: 50%;
         left: 50%;
         transform: translate(-50%,-50%);
     }
 </style>

使用flex:

<style>
     .container{
      display: flex;
      justify-content: center;
      align-items: center;
     }
     .conter{
         
     }
 </style>
  • cookie 设置过期时间删除,即使窗口或浏览器关闭
  • localStorage 存储量大,存储持久数据,浏览器关闭后数据不会丢失除非手动删除
  • sessionStorage临时存储,关闭浏览器是存储内容自动清除

$route和$router的区别

router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。。。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样。

route相当于当前正在跳转的路由对象。。可以从里面获取name,path,params,query等

vue权限控制:

1.权限管理一般需求是页面权限和按钮权限的管理

2.具体实现的时候分后端和前端两种方案:

前端方案会把所有路由信息在前端配置,通过路由守卫要求用户登录,用户登录后根据角色过滤出路由表。比如我会配置一个asyncRoutes数组,需要认证的页面在其路由的meta中添加一个roles字段,等获取用户角色之后取两者的交集,若结果不为空则说明可以访问。此过滤过程结束,剩下的路由就是该用户能访问的页面,最后通过router.addRoutes(accessRoutes)方式动态添加路由即可。

后端方案会把所有页面路由信息存在数据库中,用户登录的时候根据其角色查询得到其能访问的所有页面路由信息返回给前端,前端再通过addRoutes动态添加路由信息

按钮权限的控制通常会实现一个指令,例如v-permission,将按钮要求角色通过值传给v-permission指令,在指令的moutned钩子中可以判断当前用户角色和按钮是否存在交集,有则保留按钮,无则移除按钮。

3.纯前端方案的优点是实现简单,不需要额外权限管理页面,但是维护起来问题比较大,有新的页面和角色需求就要修改前端代码重新打包部署;服务端方案就不存在这个问题,通过专门的角色和权限管理页面,配置页面和按钮权限信息到数据库,应用每次登陆时获取的都是最新的路由信息,可谓一劳永逸!

TCP三次握手:

TCP三次握手是浏览器和服务器建立连接的方式,目的是为了使二者能够建立连接,便于后续的数据交互传输。
第一次握手:浏览器向服务器发起建立连接的请求(求职者主动联系boss,并发送简历
第二次握手:服务器告诉浏览器,我同意你的连接请求,同时我也向你发起建立连接的请求(boss收到简历并发起面试邀约
第三次握手:浏览器也告诉服务器,我同意建立连接。(求职者同意面试邀约
至此,双方都知道对方同意建立连接,并准备好了进行数据传输,也知道对方知道自己的情况。接下来就可以传输数据了

http和https区别

HTTP协议以明文方式发送内容,不提供任何方式的数据加密。HTTP协议不适合传输一些敏感信息,比如:信用卡号、密码等支付信息。

https则是具有安全性的ssl加密传输协议。

http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。并且https协议需要到ca申请证书。HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。

DNS解析过程:

当用户在浏览器中输入www.baidu.com的时候,DNS解析大概会有以下过程:

  1. 首先浏览器会检查自身缓存是否解析过这个域名的IP地址,如果有即缓存命中,那么解析结束;
  2. 如果浏览器缓存中没有,那么浏览器会检查操作系统缓存中是否有相应的解析过的结果。而操作系统也有一个域名解析的过程。像我们熟悉的hosts文件,如果用户在这里定义了一个域名对应的IP地址,那么浏览器会首先使用这里定义的IP地址;
  3. 如果此时还没有命中域名,才会真正地去请求本地域名服务器(LDNS)来解析这个域名,这台服务器一般在你的城市的某个角落,距离你不是很远,并且这台服务器的性能很好,一般这里会缓存域名解析的结果。大约80%的域名解析到这里就完成了;
  4. 如果LDNS仍然没有命中,那么LDNS就会向根域名服务器(Root Server)发起域名请求解析;
  5. 根域名服务器返回给LDNS一个所查询域的主域名服务器(gTLD Server,国际顶尖域名服务器,如.com、.cn、.org等)地址;
  6. 此时LDNS再发送请求到上一步返回的gTLD的IP地址;
  7. 接受请求的gTLD查找并返回这个域名对应的Name Server的地址,这个Name Server就是网站注册的域名服务器;
  8. Name Server根据映射关系表找到目标IP地址,并将其返回给LDNS;
  9. LDNS缓存这个域名和对应的IP;
  10. LDNS把解析的结果返回给用户,用户根据TTL值缓存到本地系统缓存中,域名解析过程至此结束。

HTTP请求过程

简单来说,请求过程就是客户端向服务器进行request请求,服务器收到后进行处理然后response响应数据给浏览器,就完成了一次请求:

详细过程
详细过程能为工作中解决一些问题提供参考,面试时回答简单过程即可。详细过程不需要死记硬背,把它当成API类的存在即可。

当单击某个超链接或者输入访问地址访问时,HTTP的工作开始:

触发。如用户点击某个超链接,软件启动时发送的请求,用户在地址栏访问网址等等。
解析URL。浏览器解析URL,得到协议类型、域名或服务器地址、资源地址。
DNS查询。浏览器依次检查缓存与Hosts文件,如果没有,则向DNS服务器请求目标服务器的IP地址。
握手。浏览器向服务器发起TCP的连接请求,TCP经过3次握手以后建立连接。
请求。建立连接后,浏览器发送一个HTTP请求给服务器。
响应。服务器处理完后响应HTTP,返回数据给html。

策略模式

意图:定义一系列的算法,把它们一个个封装起来, 并且使它们可相互替换。

主要解决:在有多种算法相似的情况下,使用 if…else 所带来的复杂和难以维护。

何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。

如何解决:将这些算法封装成一个一个的类,任意地替换。

实际应用:表单的校验;替换if-else

function Validate () {}
Validate.prototype.rules = {
  // 是否手机号
  isMobile: function (str) {
    var rule = /^1[3,4,5,7,8,9][0-9]\d{8}$/;
    return rule.test(str);
  },
  // 是否必填
  isRequired: function (str) {
    // 除去首尾空格
    var value = str.replace(/(^\s*)|(\s*$)/g, "");
    return value !== "";
  },
  // 最小长度
  minLength: function (str, length) {
    var strLength = str.length;
    return strLength >= length;
  },
  // 是否相等
  isEqual: function () {
    // 可以接收多个参数比较
    var args = Array.prototype.slice.call(arguments);
    // 取首项与后面所有的项比较,如果每个都相等,就返回true
    var equal = args.every(function(value) {
      return value === args[0];
    })
    return equal;
  }
} 

单例模式

1.饿汉模式:在类加载的时候就对实例进行初始化 线程安全、非懒加载、效率高

img

2.懒汉模式 : 在第一次使用的时候才进行初始化,达到了懒加载的效果 线程安全、懒加载、效率低

img

装饰模式

定义:装饰模式可以在不改变一个对象本身的基础上给对象增加额外的新行为。

说起装饰,我们肯定不陌生。现实生活中有很多装饰,比如给相片加相框,给房子装修等等,其目的是美化外观或扩展功能。而软件工程的装饰模式通常用来扩展类的功能。在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)。

发布者-订阅者模式

vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,
在数据变动时发布消息给订阅者,触发相应的监听回调。

在这里插入图片描述

工厂模式

js特性:

es5实现异步编程的方式:回调函数

jS原型:object.prototype

class类属性:

编程:

  1. 如何消除一个数组里面重复的元素?

    1.使用 set

    function uniquearray(array) { 
     let unique_array= Array.from(set(array)) 
     return unique_array;
    }

    2.使用 filter

    function unque_array (arr) {
      let unique_array = arr.filter(function(elem, index, self) {
        return index == self.indexOf(elem);
      })
      return unique_array;
    }
    
     console.log(unique_array(array_with_duplicates));

    3.使用 for 循环

    Array dups_names = ['Ron', 'Pal', 'Fred', 'Rongo', 'Ron'];
    function dups_array(dups_names) {
     let unique = {};
     names.forEach(function(i) {
        If (!unique[i]) {
          unique[i] = true;    }
      });
    return Object.keys(unique);}   // Ron, Pal, Fred, Rongo
    Dups_array(names);
  2. 手写数组快速排序

    “快速排序”的思想很简单,整个排序过程只需要三步:

    (1)在数据集之中,选择一个元素作为”基准”(pivot)。

    (2)所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。

    (3)对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

  3. 统计字符串”aaaabbbccccddfgh”中字母个数或统计最多字母数。

    var str = "aaaabbbccccddfgh";
    var obj  = {};
    for(var i=0;i<str.length;i++){
        var v = str.charAt(i);
        if(obj[v] && obj[v].value == v){
            obj[v].count = ++ obj[v].count;
        }else{
            obj[v] = {};
            obj[v].count = 1;
            obj[v].value = v;
        }
    }
    for(key in obj){
        document.write(obj[key].value +'='+obj[key].count+' '); // a=4  b=3  c=4  d=2  f=1  g=1  h=1 
    }
  4. 写一个function,清除字符串前后的空格。(兼容所有浏览器)

    function trim(str) {
        if (str && typeof str === "string") {
            return str.replace(/(^\s*)|(\s*)$/g,""); //去除前后空白符
        }
    }
  5. 用纯JS编写一个程序来反转字符串

    str="jQuery";
    str = str.split("")
    str = str.reverse()
    str = str.join("")
    alert(str);
  6. 希望获取到页面中所有的checkbox怎么做?(不使用第三方框架)

    var inputs = document.getElementsByTagName("input"),
    	arr = [],
    	len = inputs.length;
    while (len--){
    	if(inputs[len].type == "checkbox"){
    		arr.push(inputs[i]);
    	}
    }
    
  7. 看下列代码输出为何?解释原因。

    var a;
    alert(typeof a); //undefined
    alert(b); //报错

    变量a是被声明的,只是没有赋值,所以值为undefined。而b未被声明,所以不存在。

  8. 看下列代码,输出什么?解释原因。

    var a = null;
    alert(typeof a); //object

    null是一个空指针对象,所以类型是object

  9. 看下列代码,输出什么?解释原因。

    var undefined;
    undefined == null; //true
    1 == true; //true
    2 == true; //false
    0 == false; //true
    0 == ''; // true
    NaN == NaN; //false
    [] == false; //true
    [] == ![]; //true

    undefined与null在if语句中会被自动转为false,相等运算符直接报告两者相等。(如果是全等的话结果为false)
    数字和布尔值进行比较会把布尔值变为数字,true为1,false为0。
    0为假即false,空值或者空格也为false。
    NaN和任何值都不相等。
    []被当作数组处理,空数组转换为0,所以等于false。
    ![]想做将数组转换为布尔值的运算,[]为一个数组对象,所以![]为false。

  10. 看下面的代码,输出什么,foo的值为什么?

    var foo = "11"+2-"1";
    console.log(foo); //111

    先做”11”+2运算,当一个为字符串一个为数字时,将数字转换为字符串,所以字符串拼接为”112”。当两个数据都是字符串时,+以外的运算会先把字符串转换为数字,即112-1=111,foo类型为Number。如果是+运算,则为”112”+“1”=“1121”,foo类型为String。

  11. 看代码给答案

    var a = new Object();
    a.value = 1;
    b = a;
    b.value = 2;
    alert(a.value); //2

    a,b都指向同一个对象,所以b修改了value值,a的value值也变了。

  12. 已知数组var stringArray = [“This”, “is”, “Baidu”, “Campus”],Alert出”This is Baidu Campus”。

    stringArray.join(" ");
  13. 已知有字符串foo=“get-element-by-id”,写一个function将其转化成驼峰表示法“getElementById”。

    var fooArr = foo.split("-");
    var newFoo = fooArr[0];
    for(var i=1;i<fooArr.length;i++){
    	newFoo += fooArr[i].charAt(0).toUpperCase()+fooArr[i].slice(1);
    }
    return newFoo;
  14. var numberArray = [3,6,2,4,1,5];

    实现对该数组的倒排,输出[5,1,4,2,6,3]

    numberArray.reverse();

    实现对该数组的降序排列,输出[6,5,4,3,2,1]

    numberArray.sort(function(a,b){
       	return b-a;
       });
  15. 输出今天的日期,以YYYY-MM-DD的方式

    var date = new Date();
    var year = date.getFullYear();
    var month = date.getMonth()+1;
    var nowDate = date.getDate();
    if(month<10){month = "0" + month;}
    if(nowDate<10){nowDate = "0" + nowDate;}
    var today = year + "-" + month + "-" + nowDate;
  16. 看下列代码,将会输出什么?(变量声明提升)

    var foo = 1;
    function(){
    	console.log(foo); //undefined
    	var foo = 2;
    	console.log(foo); //2
    }

    函数声明和变量声明会被隐式地提升到当前作用域的顶部,但是不会提升赋值部分。相当于:

    var foo = 1;
    function(){
    	var foo;
    	console.log(foo); //undefined
    	foo = 2;
    	console.log(foo); //2
    }
  17. 有这样一个URL:http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e,请写一段JS程序提取URL中的各个GET参数(参数名和参数个数不确定),将其按key-value形式返回到一个json结构中,如{a:’1′, b:’2′, c:”, d:’xxx’, e:undefined}。

    var url = "http://item.taobao.com/item.htm?a=1&b=2&c=&d=xxx&e";
    var gets = url.split("?")[1];
    var getsArr = gets.split("&");
    var obj = {};
    for(var i=0;i<getsArr.length;i++){
    	obj[getsArr[i].split("=")[0]] = getsArr[i].split("=")[1];
    }
    return obj;
  18. 看下面代码,给出输出结果。

    for(var i=1;i<=3;i++){
      setTimeout(function(){
      console.log(i); //4 //4 //4
      },0);  
    };

    Javascript事件处理器在线程空闲之前不会运行。

    如何让上述代码输出1 2 3?

    for(var i=1;i<=3;i++){
      setTimeout((function(i){
      console.log(i);
      })(i),0);  //立即执行函数
    };
  19. 解释什么是回调函数,并提供一个简单的例子。

    回调函数是可以作为参数传递给另一个函数的函数,并在某些操作完成后执行。下面是一个简单的回调函数示例,这个函数在某些操作完成后打印消息到控制台。

    function modifyArray(arr, callback) {
     // 对 arr 做一些操作
     arr.push(100);
     // 执行传进来的 callback 函数
     callback();
    }
    var arr = [1, 2, 3, 4, 5];
    modifyArray(arr, function() {
     console.log("array has been modified", arr);
    });
    
  20. 如何检查一个数字是否为整数?

    检查一个数字是小数还是整数,可以使用一种非常简单的方法,就是将它对 1 进行取模,看看是否有余数。

    function isInt(num) {
     return num % 1 === 0;
    }
    console.log(isInt(4)); // true
    console.log(isInt(12.2)); // false
    console.log(isInt(0.3)); // false
  21. 冒泡排序算法

    var array = [5, 4, 3, 2, 1];
    var temp = 0;
    for (var i = 0; i <array.length; i++){
    for (var j = 0; j <array.length - i; j++){
    if (array[j] > array[j + 1]){
    temp = array[j + 1];
    array[j + 1] = array[j];
    array[j] = temp;
     }
    }
    }
    
  22. 给定一个数组例如[1,3,4,6,7] ,再给定一个目标数,例如9。 写一个算法找出两个数他们相加等于目标数,返回他们在数组中的位置。

    function func(arr,target){
            var obj = {};
                for(var i = 0; i < arr.length; i++){
                    var item = arr[i];
                    if(obj[item] === undefined){
                        var x = target - item;
                        obj[x] = i;
                    }else{
                        return [obj[item],i];  
                    }
                }
                return null;
            }
             
            console.log(func([1,3,7,6,9,11],9))
    

文章作者: wsh
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 wsh !
  目录