0
点赞
收藏
分享

微信扫一扫

2022前端面试高频题目

梦幻之云 2022-04-13 阅读 86
vue.js

这里写自定义目录标题

HTML&CSS

  • H5C3新增特性
  • 如何使一个盒子水平垂直居中?
  • 纯css手写大于号
  • 什么是BFC,如何创建BFC?

JavaScript

Vue:

网络

性能相关

HTML&CSS:

H5新增特性

1.语义化标签:header,nav,footer ,aside, article, section,audio, video

2.阴影:文字阴影(text-shadow),盒子阴影 (box-shadow)

3.表单控件:calendar , date , time , email , url , search , tel , file , number

4.画布: Canvas,svg

5.浏览器存储:localstory,sessionstory

6.拖拽释放(Drap and drop) API ondrop

CSS3新特性

1、弹性布局 flex

2、阴影 :文字阴影(text-shadow)盒子阴影 : box-shadow

3、边框: 圆角(border-radius)

4、盒子模型: box-sizing

5、背景:background-size background-origin background-clip

6、渐变: linear-gradient , radial-gradient

7、过渡 : transition 可实现动画

8、自定义动画 animate @keyfrom

9、媒体查询 多栏布局 @media screen and (width:800px) { …}

10、2D3D 转换;transform: translate(x,y) rotate(x,y) skew(x,y) scale(x,y)

11、新增 RGBA , HSLA 模式

纯css手写大于号

如何使一个盒子水平垂直居中?

1.利用flex布局(设置在父元素)

display:flex;justify-content:center;align-items:center;

2.利用定位 + margin:auto

position: absolute;margin: auto;top: 0;left: 0;right: 0;bottom: 0;

3.利用定位 + 转换

position: absolute;top:50%;left:50%;transform:translate(-50%,-50%)

什么是BFC,如何创建BFC?

BFC:格式化上下文(formatting context) ,是有一定规则的环境,不同BFC区域下的盒子有不同的表现,BFC是一个完全独立的空间(布局环境),让空间里的子元素不会影响到外面的布局。那么怎么使用BFC呢,BFC可以看做是一个CSS元素属性。

BFC规则:

BFC就是一个块级元素,块级元素会在垂直方向一个接一个的排列

BFC就是页面中的一个隔离的独立容器,容器里的标签不会影响到外部标签

垂直方向的距离由margin决定, 属于同一个BFC的两个相邻的标签外边距会发生重叠

计算BFC的高度时,浮动元素也参与计算

触发BFC:

float值为left、right

overflow值不为 visible,为 auto、scroll、hidden

display值为 inline-block、table-cell、table-caption、table、inline-table、flex、inline-flex

position值为 absolute、fixed`

css动画js动画区别?

CSS 动画大多数都是补间动画(原因是只需要添加关键帧的位置,其他的未定义的帧会被自动生成),而 JS 动画是逐帧动画,CSS动画的渲染成本小,并且它的执行效率高于 JavaScript 动画。

display: none; visibility: hidden;opacity: 0;区别?

display: none,dom树中存在节点,不占位置

visibility: hidden,dom树中存在节点,占位置

opacity: 0,dom树中存在节点,占位置

JavaScript:

什么是闭包?

一个作用域可以访问另外一个函数内部的局部变量 ,或者说一个函数 (子函数)访问另一 个函数 (父函数)中的变量。此时就会有闭包产生 ,那么这个变量所在的函数我们就称之为闭包函数。

闭包的主要作用: 延伸了变量的作用范围, 因为闭包函数中的局部变量不会等着闭包函数 执行完就销毁, 因为还有别的函数要调用它 , 只有等着所有的函数都调用完了他才会销毁 闭包会造成内存泄漏, 如何解决: 用完之后手动释放。

说说你对原型(prototype)理解

在JavaScript 中, 原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript 的对象中都包含了一个” prototype” 内部属性,这个属性所对应的就是该对象的原型。

当访问一个对象的某个属性时, 会先在这个对象本身属性上查找, 如果没有找到, 则会去 它的__proto__隐式原型上查找, 即它的构造函数的 prototype, 如果还没有找到就会再 在构造函数的 prototype 的__proto__中查找,这样一层一层向上查找就会形成一个链式结构, 我们称为原型链。

es6

1.变量

2.箭头函数

3.模板字符串

4.解构赋值

5.展开运算符

6.class

7.Promise 对象


8.async、 await

9.Set 数据结构

10.对象扩展:Object.keys()方法,Object.assign ()

11.for…of 循环

12.import 和 export

vue:

vue双向数据绑定原理

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

Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。

cli刚创建后的基础目录(8,7)

node_modules 依赖目录

public:(该文件夹可以用来存放静态资源,存放在该文件夹的东西不会被打包影响,而是会原封不动的输出到dist文件夹中,和vue cli2中的static文件夹一样的。)

favicon.ioc(页面标签图标)

index.html(入口页面)

src:(源代码目录)

aseets(资源目录,这里的资源会被webpack构建),

components(公共组件目录),

router(路由配置),

store(状态管理),

views(页面目录),

APP.vue(根组件),

main.js(入口文件)

.gitignore (git提交忽略文件)

babel.config.js(babel配置)

package.json(npm包配置文件,里面定义了项目的npm脚本,依赖包等信息)

前端路由实现原理

简单来说路由就是用来跟后端服务器进行交互的一种方式,通过不同的路径,来请求不同的资源。
hash模式url里面永远带着#号,我们在开发当中默认使用这个模式。那么什么时候要用history模式呢?如果用户考虑url的规范那么就需要使用history模式,因为history模式没有#号,是个正常的url适合推广宣传。

当然其功能也有区别,比如我们在开发app的时候有分享页面,那么这个分享出去的页面就是用vue或是react做的,咱们把这个页面分享到第三方的app里,有的app里面url是不允许带有#号的,所以要将#号去除那么就要使用history模式,
但是使用history模式还有一个问题就是,在访问二级页面的时候,做刷新操作,会出现404错误,那么就需要和后端人配合让他配置一下apache或是nginx的url重定向,重定向到你的首页路由上就ok啦

history模式利用history API(pushstate,并不会触发popstate事件,不会刷新页面)实现url地址改变,网页内容改变。

hash 模式是一种把前端路由的路径用井号 #拼接在真实 url 后面的模式。当井号 # 后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发 onhashchange 事件,通过这个事件我们就可以知道 hash 值发生了哪些变化。然后我们便可以监听hashchange来实现更新页面部分内容的操作。

vue-router守卫:

vue-router全局有三个守卫:

router.beforeEach 全局前置守卫 进入路由之前

router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用

router.afterEach 全局后置钩子 进入路由之后

    // main.js 入口文件
    import router from './router'; // 引入路由
    router.beforeEach((to, from, next) => { 
      next();
    });
    router.beforeResolve((to, from, next) => {
      next();
    });
    router.afterEach((to, from) => {
      console.log('afterEach 全局后置钩子');
    });

路由独享守卫:

    const router = new VueRouter({
      routes: [
        {
          path: '/foo',
          component: Foo,
          beforeEnter: (to, from, next) => { 
            // 参数用法什么的都一样,调用顺序在全局前置守卫后面,所以不会被全局守卫覆盖
            // ...
          }
        }
      ]
    })

路由组件内的守卫:

beforeRouteEnter 进入路由前

beforeRouteUpdate (2.2) 路由复用同一个组件时

beforeRouteLeave 离开当前路由时

  beforeRouteEnter (to, from, next) {
    // 在路由独享守卫后调用 不!能!获取组件实例 `this`,组件实例还没被创建
  },
  beforeRouteUpdate (to, from, next) {
    // 在当前路由改变,但是该组件被复用时调用 可以访问组件实例 `this`
    // 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
    // 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
  },
  beforeRouteLeave (to, from, next) {
    // 导航离开该组件的对应路由时调用,可以访问组件实例 `this`
  }

组件的使用方法

定义组件名称–>创建组件结构–>其他vue文件引入该组件–>注册组件–>模板中使用组件(驼峰转横线)

在使用 vue-cli 创建的项目中,组件的创建非常方便,只需要新建一个 .vue 文件,然后在 template 中写好 HTML 代码,一个简单的组件就完成了 一个完整的组件,除了 template 以外,还有 script和 style,然后在其他vue文件里面引入并注册,就能直接使用这个组件了。一个通用组件,往往不能够完美的适应所有应用场景 所以在封装组件的时候,只需要完成组件 80% 的功能,剩下的 20% 让父组件通过 solt 解决。

插件的使用流程(方法)

npm下载包–>配置包–>入口文件中引入包–>使用包(1.挂在到prototye原型全局使用,2.在需要的地方引入)

CSS动画我们只设置了几个关键帧的位置,所以在进行动画控制的时候比较困难,不能再半路暂停动画,或者在动画过程中添加一些其他操作,都不大容易,但是 CSS 动画也有很多的好处,浏览器可以对动画进行优化,帧速不好的浏览器,CSS3 可以自然降级兼容,代码简单,调优方向固定

require和import的区别

  1. 导入require 导出 exports/module.exportsCommonJS 的标准,通常适用范围如 Node.js
  2. import/exportES6 的标准,通常适用范围如 React
  3. require赋值过程并且是运行时才执行,也就是同步加载
  4. require 可以理解为一个全局方法,因为它是一个方法所以意味着可以在任何地方执行。
  5. import解构过程并且是编译时执行,理解为异步加载
  6. import 会提升到整个模块的头部,具有置顶性,但是建议写在文件的顶部。

require 的性能相对于 import 稍低。
因为 require 是在运行时才引入模块并且还赋值给某个变量,而 import 只需要依据 import 中的接口在编译时引入指定模块所以性能稍高

JS 动画是逐帧动画,在时间帧上绘制内容,一帧一帧的,所以他的可再造性很高,几乎可以完成任何你想要的动画形式。但是由于逐帧动画的内容不一样,会增加制作的负担,占用比较大的资源空间。细腻的动画,可控性高,炫酷高级的动画。

keep-alive的作用

组件缓存,用于那些频繁切换的页面,减少因页面频繁切换导致页面频繁的创建和销毁等损耗性能的情况。里面有两个生命周期钩子,创建actived和销毁deactived,你可以在这两个钩子里面做一些事情

v-if与v-show的区别

v-if通过创建删除节点来显示隐藏元素,v-show通过display:none来显示隐藏元素

路由传参方式

this.$router.push({
    path:`/home/${id}`,
})

路由配置
{
    path:"/home/:id",
    name:"Home",
    component:Home
}
在Home组件中获取参数值
this.$route.params.id


name----params:
通过name来匹配路由,通过param来传递参数
this.$router.push({
    name:'Home',
    params:{
        id:id
    }
})
用params传递参数,不使用:/id
{
    path:'/home',
    name:Home,
    component:Home
}
Home组件中获取参数
this.$route.params.id


path----query
this.$router.push({
    path:'/home',
    query:{
        id:id
    }
})
路由配置
{
    path:'/home',
    name:Home,
    component:Home
}
获取参数的方法
this.$route.query.id


取url参数

  let url = window.location.href
  function parseQuery(url) {
    url = url || '';
    const queryObj = {};
    const reg = /[?&]([^=&#]+)=([^&#]*)/g;
    const queryArr = url.match(reg) || [];
    for (const i in queryArr) {
        if (Object.hasOwnProperty.call(queryArr, i)) {
            const query = queryArr[i].split('=');
            const key = query[0].substr(1);
            const value = decodeURIComponent(query[1]);
            queryObj[key] ? queryObj[key] = [].concat(queryObj[key], value) : queryObj[key] = value;
        }
    }
    return queryObj;
  }
  console.log(parseQuery(url));

网络:

http和https区别

http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。

http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。

https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。

https相比于http更有利于SEO

HTTP使用TCP三次握手建立连接,客户端和服务器需要交换3个包,HTTPS除了TCP的三个包,还要加上ssl握手需要的9个包,所以一共是12个包,更加占用服务器资源。

tcp三次握手四次挥手

三次握手其实就是指建立一个TCP连接时,需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实质上其实就是连接服务器指定端口,建立TCP连接,并同步连接双方的序列号和确认号,交换TCP窗口大小信息。

三次握手:客户端发第一个包服务端接收,服务端可以判断客户端发送能力。

服务端接收后发第二个包给客户端,这时客户端可以判断服务端的接收和发送能力。

这时还服务端还不能判断客户端的接收能力,所以还需要客户端再发一个包服务端接收来确定。

四次挥手TCP 协议是全双工通信, 这意味着客户端和服务器端都可以向彼此发送数据,所以关闭连接是双方都需要确认的共同行为, 假设是三次挥手时, 首先释放了客户到服务器方向的连接,此时 TCP 连接处于半关闭状态, 这时客户不能向服务器发送数据, 而服务器还是可以向客户发送数据。 如果此时客户收到了服务器的确认报文段后, 就立即发送一个确认报文段,这会导致服务器向客户还在发送数据时连接就被关闭。 这样会导致客户没有完整收到服务器所发的报文段

简单介绍localStorage,sessionStorage,cookie,session以及它们之间的区别:

localStorage,sessionStorage,cookie三者都是浏览器端储存方式,由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份,所以使用cookie来保存用户登录状态区分不同用户。localStorage,sessionStorage主要用来存储数据。

不同点

cookie 数据始终在同源的 http 请求中携带(即使不需要),localStorage,sessionStorage仅本地储存

cookie能存大约4k的数据,localStorage,sessionStorage大约5M
cookie默认有效期20分钟(后端可修改),localStorage默认永久有效,sessionStorage窗口关闭即失效

//手动封装设置localStorage有效时间方法
// 存值函数
        // 接收三个参数:键、值、有效天数
        Storage.prototype.setCanExpireLocal = (key, value, expire) => {
            // 判断传入的有效期是否为数值或有效
            // isNaN是js的内置函数,用于判断一个值是否为NaN(非数值),
            // 非数值返回true,数值返回false
            // 还可以限制一下有效期为整数,这里就不做了
            if (isNaN(expire) || expire < 1) {
                throw new Error('有效期应为一个有效数值')
            }
            // 86_400_000一天时间的毫秒数,_是数值分隔符
            let time = expire * 86_400_000
            let obj = {
                data: value, //存储值
                time: Date.now(), //存值时间戳
                expire: time, //过期时间
            }
            // 注意,localStorage不能直接存储对象类型,sessionStorage也一样
            // 需要先用JSON.stringify()将其转换成字符串,取值时再通过JSON.parse()转换回来
            localStorage.setItem(key, JSON.stringify(obj))
        }

        // 取值函数
        // 接收一个参数,存值的键          
        Storage.prototype.getCanExpireLocal = key => {
            let val = localStorage.getItem(key)
            // 如果没有值就直接返回null
            if (!val) return val
            // 存的时候转换成了字符串,现在转回来
            val = JSON.parse(val)
            // 存值时间戳 +  有效时间 = 过期时间戳
            // 如果当前时间戳大于过期时间戳说明过期了,删除值并返回提示
            if (Date.now() > val.time + val.expire) {
                localStorage.removeItem(key)
                return '值已失效'
            }
            return val.data
        }
        // 存值
        Storage.prototype.setCanExpireLocal('测试', '一天后过期', 1)
        // 取值
        Storage.prototype.getCanExpireLocal('测试')
        console.log(Storage.prototype.getCanExpireLocal('测试'));
        

cookie,session,token

cookie:由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份,Cookie实际上是一小段的文本信息。客户端浏览器会把Cookie保存起来。当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。

session:session保存在服务器,session需要使用Cookie作为识别标志,由于HTTP协议是无状态的,session不能依据HTTP连接来判断是否为同一客户,因此服务器向客户端浏览器发送一个名为JSESSIONID的Cookie,它的值为该session的id(也就是HttpSession.getId()的返回值)。session依据该Cookie来识别是否为同一用户。

token:token是目前多用户下处理认证的最佳方式,token=用户数据 + 签名(算法加密后的用户数据 + 秘钥),服务端生成token,客户端请求时携带token,之后服务端再对用户数据进行算法加密并且与签名中的数据对比,达到验证目的。

json理解

JSON(JavaScript Object Notation)它是一种轻量级纯文本数据格式,不是一种编程语言,可以简化表示复杂数据结构的工作量。虽然和JavaScript具有类似的语法形式,但 JSON 并不从属于 JavaScript。而且,并不是只有 JavaScript 才使用 JSON。

JSON 是存储和交换文本信息的语法,类似 XML,比 XML 更小、更快,更易解析。JSON 使用 JavaScript 语法的子集表示对象、数组、字符串、数值、布尔值和 null 。即使 XML 也能表示同样复杂的数据结果,但JSON 没有那么烦琐,而且在 JavaScript 中使用更便利。ECMAScript 5 定义了一个原生的 JSON 对象,JSON.parse(),JSON.stringify()。

跨域处理

协议、子域名、主域名、端口号中任意一个不相同时,都算作不同域。跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。

JSONP

是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。

// index.html 原生封装jsonp方法
function jsonp({ url, params, callback }) {
  return new Promise((resolve, reject) => {
    let script = document.createElement('script')
    window[callback] = function(data) {
      resolve(data)
      document.body.removeChild(script)
    }
    params = { ...params, callback } // wd=b&callback=show
    let arrs = []
    for (let key in params) {
      arrs.push(`${key}=${params[key]}`)
    }
    script.src = `${url}?${arrs.join('&')}`
    document.body.appendChild(script)
  })
}
jsonp({
  url: 'http://localhost:3000/say',
  params: { wd: 'Iloveyou' },
  callback: 'show'
}).then(data => {
  console.log(data)
})

Vue axios实现
this.$http = axios;
this.$http.jsonp('http://www.domain2.com:8080/login', {
    params: {},
    jsonp: 'handleCallback'
}).then((res) => {
    console.log(res); 
})


CORS

是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。 CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

node中间件实现跨域代理

原理大致与nginx相同,都是通过启一个代理服务器,实现数据的转发,也可以通过设置cookieDomainRewrite参数修改响应头中cookie中域名,实现当前域的cookie写入,方便接口登录认证。

nginx反向代理跨域

通过Nginx配置一个代理服务器(域名与domain1相同,端口不同)做跳板机,反向代理访问domain2接口,并且可以顺便修改cookie中domain信息,方便当前域cookie写入,实现跨域访问。

兼容:

click 在 ios 上有 300ms 延迟,原因及如何解决?

原因:早期苹果为了判断移动端上的双击缩放事件而加的,在touchendclick事件之间加300ms的延迟来判断用户到底是点击还是双击。
解决方法:fastclick是专门为解决移动端浏览器300毫秒点击延迟问题所开发的一个轻量级的库,fastclick的原理是在检测到touchend事件的时候,会通过DOM自定义事件立即触发模拟一个click事件,并把浏览器在300ms之后的click事件阻止调。还有禁用缩放也可以解决。

算法:

手写数组去重:

 双重for循环
        let arr = [1, 2, 3, 4, 5, 5, 4, 6, 1]
        let newarr = [arr[0]]
        for (let i = 1; i < arr.length; i++) {
            let flag = true
            for (let j = 0; j < newarr.length; j++) {
                if (arr[i] === newarr[j]) {
                    flag = false;
                    break
                }
            }
            if (flag) {
                newarr.push(arr[i])
            }
        }
        console.log(newarr);

indexOf
        let arr = [1, 2, 3, 4, 5, 5, 4, 6, 1]
        let newarr = Array.prototype.filter.call(arr, function (item, index) {
            return arr.indexOf(item) === index;
        });

        console.log(newarr);


        let list = [1, 2, 3, 4, 5, 5, 4, 6, 1]
        let newlist = []
        for (let i = 0; i < list.length; i++) {
            if(newlist.indexOf(list[i]) === -1){
                newlist.push(list[i])
            }
        }
        console.log(newlist);

set
        let list = [1, 2, 3, 4, 5, 5, 4, 6, 1]
        let newlist =[...new Set(list)]
        console.log(newlist);
       
        let list = [1, 2, 3, 4, 5, 5, 4, 6, 1]
        let newlist = Array.from(new Set(list))
        console.log(newlist);

手写tab组件

性能相关前端模块化:

前端模块化

CommonJS模块的加载机制是,输入的是被输出的值的拷贝。也就是说,一旦输出一个值,模块内部的变化就影响不到这个值,ES6 模块输出的是值的引用。

AMD规范采用异步方式加载模块,模块的加载不影响它后面语句的运行。所有依赖这个模块的语句,都定义在一个回调函数中,等到加载完成之后,这个回调函数才会运行。

CMD是另一种js模块化方案,它与AMD很类似,不同点在于:AMD 推崇依赖前置、提前执行,CMD推崇依赖就近、延迟执行。

举报

相关推荐

0 条评论