2021前端面试题

文章目录

VUE篇

v-show和v-if有什么区别??

v-show是css切换,v-if是完整的销毁和重新创建,如果频繁切换时用v-show,运行时较少改变用v-if


slot 插槽

很多时候,我们封装了一个子组件之后,在父组件使用的时候,想添加一些 dom 元素,这个时候就可以使用 slot 插槽了,但是这些 dom 是否显示以及在哪里显示,则是看子组件中 slot 组件的位置了。

Vue 中操作 data 中数组的方法中哪些可以触发视图更新,哪些不可以,不可以的话有什么解决办法?

push ()、pop ()、shift ()、unshift ()、splice ()、sort ()、reverse () 这些方法会改变被操作的数组; filter ()、concat ()、slice () 这些方法不会改变被操作的数组,返回一个新的数组;
以上方法都可以触发视图更新。

利用索引直接设置一个数组项,例:this.array[index] = newValue
直接修改数组的长度,例:this.array.length = newLength
以上两种方法不可以触发视图更新;

可以用 this.$set(this.array,index,newValue) 或 this.array.splice(index,1,newValue) 解决方法 1
可以用 this.array.splice(newLength) 解决方法 2


v-if和v-for的优先级

答:当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。所以,不推荐v-if和v-for同时使用。

如果v-if和v-for一起用的话,vue中的的会自动提示v-if应该放到外层去。


怎么强制刷新组件?

this.$forceUpdate()。
组件上加上 key,然后变化 key 的值。


watch 的属性和 methods 方法能用箭头函数定义吗?

不可以。this 会是 undefind, 因为箭头函数中的 this 指向的是定义时的 this,而不是执行时的 this,所以不会指向 Vue 实例的上下文。


给组件绑定自定义事件无效怎么解决?

加上修饰词.native。


SPA首屏加载慢如何解决

安装动态懒加载所需插件;使用CDN资源。


在使用计算属性的时,函数名和data数据源中的数据可以同名吗?

不能同名 因为不管是计算属性还是data还是props 都会被挂载在vm实例上,因此 这三个都不能同名。同名时会报错:The computed property “xxxx” is already defined in data


怎么给vue定义全局的方法?

通过prototype,这个非常方便。Vue.prototype[method]=method;
通过mixin,Vue.mixin(mixins);


你怎么理解vue中的diff算法?

diff算法是虚拟DOM技术的必然产物:通过新旧虚拟DOM作对比(即diff),将变化的地方更新在真实DOM上;
另外,也需要diff高效的执行对比过程,从而降低时间复杂度为0(N).

vue 2.x中为了降低Watcher粒度,每个组件必须有一个Watcher与之对应,只有引入diff才能精确找到发生变化的地方。
vue中的diff执行的时刻是组件实例执行其更新函数时,它会比对上一次渲染结果oldVnode和新的渲染结果newVnode,此过程成为patch.
diff过程整体遵循深度优先、同层比较的策略;两个节点之间比较会更具它们是否拥有子节点或者文本节点做不同操作;
比较两组子节点是算法的重点,首先假设头尾节点可能相同做4次比对尝试;

如果没有找到相同节点才按照通用方式遍历查找,查找结束再按情况处理剩下的节点;

借助key通常可以非常准确的找到相同节点,因此整个patch过程非常高效。


你对Vue3.0的新特性有没有了解?

更快
(1).虚拟DOM重写

(2).优化slots的生成

(3).静态树提升

(4).静态属性提升

(5).基于Proxy的响应式系统

更小
(1).通过摇树优化核心库体积

更容易维护
(1).TypeScript + 模块化

更加友好
(1).跨平台:编译器核心和运行时核心与平台无关,使得Vue更容易与任何平台一起使用

更容易使用
(1).改进的TypeScript支持,编辑器能提供强有力的类型检查和错误及肩高

更好的调试支持
独立的响应化模块
Composition API

params和query的区别

答:用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是this. r o u t e . q u e r y . n a m e 和 t h i s . route.query.name和this. route.query.namethis.route.params.name。

url地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示

注意点:query刷新不会丢失query里面的数据

params刷新 会 丢失 params里面的数据。


Vue里面router-link在电脑上有用,在安卓上没反应怎么解决?

Vue路由在Android机上有问题,babel问题,安装babel polypill插件解决。


分别简述computed和watch的使用场景

computed:

当一个属性受多个属性影响的时候就需要用到computed

最典型的例子: 购物车商品结算的时候

watch:

当一条数据影响多条数据的时候就需要用watch

例子:搜索数据


assets和static的区别

相同点:assets和static两个都是存放静态资源文件。项目中所需要的资源文件图片,字体图标,样式文件等都可以放在这两个文件下,这是相同点

不相同点:assets中存放的静态资源文件在项目打包时,也就是运行npm run build时会将assets中放置的静态资源文件进行打包上传,所谓打包简单点可以理解为压缩体积,代码格式化。而压缩后的静态资源文件最终也都会放置在static文件中跟着index.html一同上传至服务器。static中放置的静态资源文件就不会要走打包压缩格式化等流程,而是直接进入打包好的目录,直接上传至服务器。因为避免了压缩直接进行上传,在打包时会提高一定的效率,但是static中的资源文件由于没有进行压缩等操作,所以文件的体积也就相对于assets中打包后的文件提交较大点。在服务器中就会占据更大的空间。

建议:将项目中template需要的样式文件js文件等都可以放置在assets中,走打包这一流程。减少体积。而项目中引入的第三方的资源文件如iconfoont.css等文件可以放置在static中,因为这些引入的第三方文件已经经过处理,我们不再需要处理,直接上传。


vue常用的修饰符

答:.stop:等同于JavaScript中的event.stopPropagation(),防止事件冒泡;

.prevent:等同于JavaScript中的event.preventDefault(),防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);

.capture:与事件冒泡的方向相反,事件捕获由外到内;

.self:只会触发自己范围内的事件,不包含子元素;

.once:只会触发一次。

v-model的修饰符:

v-model.lazy,懒加载,失去焦点或按回车键时生效

v-model.number,v-model默认的是字符格式,转数字。

v-model.trim,去除首尾两边的空格

Vue在created和mounted这两个生命周期中请求数据有什么区别呢?

在created中,页面视图未出现,如果请求信息过多,页面会长时间处于白屏状态,DOM节点没出来,无法操作DOM节点。在mounted不会这样,比较好。


使用key要什么要注意的吗?

不要使用对象或数组之类的非基本类型值作为key,请用字符串或数值类型的值;

不要使用数组的index作为key值,因为在删除数组某一项,index也会随之变化,导致key变化,渲染会出错。

例:在渲染[a,b,c]用 index 作为 key,那么在删除第二项的时候,index 就会从 0 1 2 变成 0 1(而不是 0 2),随之第三项的key变成1了,就会误把第三项删除

Vue中的常见指令有那些??

v-text/v-html/v-for/v-show/v-if/v-else/v-cloak/v-bind/v-on/v-model/v-slot…


请说出vue.cli项目中src目录每个文件夹和文件的用法?

assets文件夹是放静态资源;components是放组件;router是定义路由相关的配置; app.vue是一个应用主组件;main.js是入口文件。


NextTick 是做什么的

$nextTick的使用
当你修改了data的值然后马上获取这个dom元素的值,是不能获取到更新后的值,
你需要使用$nextTick这个回调,让修改后的data值渲染更新到dom元素之后在获取,才能成功。

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


Vue 的双向绑定数据的原理

vue 实现数据双向绑定主要是:采用数据劫持结合“发布者 - 订阅者”模式的方式,通过 Object.defineProperty() 来劫持各个属性的 setter、 getter,在数据变动时发布消息给订阅者,触发相应监听回调。

首先我们为每个vue属性用Object.defineProperty()实现数据劫持,
为每个属性分配一个订阅者集合的管理数组dep;
然后在编译的时候在该属性的数组dep中添加订阅者,
v-model会添加一个订阅者,{{}}也会,v-bind也会,只要用到该属性的指令理论上都会;
接着为input会添加监听事件,修改值就等于为该属性赋值,
则会触发该属性的set方法,在set方法内通知订阅者数组dep,
订阅者数组循环调用各订阅者的update方法更新视图。

缺陷

  1. 监听数组的方法不能触发Object.defineProperty方法中的set操作(如果要监听的到话,需要重新编写数组的方法)。
  2. 必须遍历每个对象的每个属性,如果对象嵌套很深的话,需要使用递归调用。

为什么使用key?

答:需要使用key来给每个节点做一个唯一标识,Diff算法就可以正确的识别此节点。

作用主要是为了高效的更新虚拟DOM。


watch怎么深度监听对象变化?

当设置deep:true时,就可以深度监听到对象到内部值的变化。


Vue 组件 data 为什么必须是函数

因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。

组件中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。


keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

主要是有include、exclude、max三个属性;前两个属性允许keep-alive有条件的进行缓存;max可以定义组件最大的缓存个数,如果超过了这个个数的话,在下一个新实例创建之前,就会将以缓存组件中最久没有被访问到的实例销毁掉。

两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态。

keep-alive中还运用了LRU(Least Recently Used)算法。


vue-router有哪几种导航钩子( 导航守卫 )?

1、全局守卫: router.beforeEach

2、全局解析守卫: router.beforeResolve

3、全局后置钩子: router.afterEach

4、路由独享的守卫: beforeEnter

5、组件内的守卫: beforeRouteEnter、beforeRouteUpdate (2.2 新增)、beforeRouteLeave

参数:有to(去的那个路由)、from(离开的路由)、next(一定要用这个函数才能去到下一个路由,如果不用就拦截)最常用就这几种


说说vue-router的两种模式

最明显的是在显示上,hash模式的URL中会夹杂着#号,而history没有。
Vue底层对它们的实现方式不同。hash模式是依靠onhashchange事件(监听location.hash的改变),而history模式是主要是依靠的HTML5 history中新增的两个方法,pushState()可以改变url地址且不会发送请求,replaceState()可以读取历史记录栈,还可以对浏览器记录进行修改。

当真正需要通过URL向后端发送HTTP请求的时候,比如常见的用户手动输入URL后回车,
或者是刷新(重启)浏览器,这时候history模式需要后端的支持。因为history模式下,
前端的URL必须和实际向后端发送请求的URL一致,例如有一个URL是带有路径path的(例如www.lindaidai.wang/blogs/id),
如果后端没有对这个路径做处理的话,就会返回404错误。所以需要后端增加一个覆盖所有情况的候选资源,一般会配合前端给出的一个404页面。

vuex有哪几种属性?

有五种,分别是 State、 Getter、Mutation 、Action、 Module

vuex的State特性
A、Vuex就是一个仓库,仓库里面放了很多对象。其中state就是数据源存放地,对应于一般Vue对象里面的data
B、state里面存放的数据是响应式的,Vue组件从store中读取数据,若是store中的数据发生改变,依赖这个数据的组件也会发生更新
C、它通过mapState把全局的 state 和 getters 映射到当前组件的 computed 计算属性中

vuex的Getter特性

A、getters 可以对State进行计算操作,它就是Store的计算属性
B、 虽然在组件内也可以做计算属性,但是getters 可以在多组件之间复用
C、 如果一个状态只在一个组件内使用,是可以不用getters

vuex的Mutation特性
Action 类似于 mutation,不同在于:Action 提交的是 mutation,而不是直接变更状态;Action 可以包含任意异步操作。


v-bind和v-model的区别, v-model原理知道吗?

v-model用于表单数据的双向绑定,其实它就是一个语法糖,这个背后就做了两个操作:
v-bind绑定一个value属性;v-on指令给当前元素绑定input事件。

v-bind用来绑定数据和属性以及表达式
v-model使用在表单中,实现双向数据绑定的,在表单元素外不起使用。
v-model原理:我们在vue项目中主要使用v-model指令在表单 input、textarea、select、等表单元素上创建双向数据绑定, v-model本质上就是vue的语法糖,v-model在内部为不同的输入元素使用不同的属性并抛出不同的事件:

text和 textarea元素使用value属性和input事件
checkbox和 radio使用checked属性和change事件
slect字段将 value作为prop并将change作用事件

<input v-model="something">
本质上相当于这样
<input v-bind:value="something" v-on:input="something = $event.target.value">

其实就是通过绑定一个something属性,通过监听input事件,当用户改变输入框数据的时候,
通过事件传递过来的事件对象中的target找到事件源,value属性表示事件源的值,从而实现双向数据绑定的效果


Vue中的的通信方式有几种?隔代组件的通信你用那种方式解决?

	6种
	props/$emit (帕死和乙米特)                  适用父子组件通信  
	ref与parent/children(撇轮吃和秋准)          适用父子组件通信    
	EventBus(一万八十)                            适用于父子、隔代、兄弟组件通信    
	attrs/listeners(一丝特内斯)                   适用于隔代组件通信     
	provide/inject (破外的/英杰克特)              适用于隔代组件通信
	vuex                                          适用于父子、隔代、兄弟组件通信

router和route

$router对象是全局路由的实例,是router构造方法的实例。

router为VueRouter的实例,是一个全局路由对象,包含了路由跳转的方法、钩子函数等。
route 是路由信息对象||跳转的路由对象,每一个路由都会有一个route对象,是一个局部对象,包含path,params,hash,query,fullPath,matched,name等路由信息参数。

1.    $route.path      字符串,对应当前路由的路径,总是解析为绝对路径,如"/foo/bar"。

2.    $route.params      一个 key/value 对象,包含了 动态片段 和 全匹配片段,      如果没有路由参数,就是一个空对象。

3.    $route.query      一个 key/value 对象,表示 URL 查询参数。      例如,对于路径 /foo?user=1,则有$route.query.user == 1,      如果没有查询参数,则是个空对象。

4.    $route.hash      当前路由的hash值 (不带#) ,如果没有 hash 值,则为空字符串。锚点*

5.    $route.fullPath      完成解析后的 URL,包含查询参数和hash的完整路径。

6.    $route.matched      数组,包含当前匹配的路径中所包含的所有片段所对应的配置参数对象。

7.    $route.name    当前路径名字

8.    $route.meta  路由元信息

导航钩子的参数:

router.beforeEach((to,from, next)=>{//to 和from都是 路由信息对象,后面使用路由的钩子函数就容易理解了})

$router对象是全局路由的实例,是router构造方法的实例。

路由实例方法:

1、push

1. 字符串this.$router.push('home')

2. 对象this.$router.push({path:'home'})

3. 命名的路由this.$router.push({name:'user',params:{userId:123}})

4. 带查询参数,变成 /register?plan=123this.$router.push({path:'register',query:{plan:'123'}})

push方法其实和<router-link :to="...">是等同的。

注意:push方法的跳转会向 history 栈添加一个新的记录,当我们点击浏览器的返回按钮时可以看到之前的页面。

2、go
页面路由跳转

 前进或者后退this.$router.go(-1)  // 后退

3、replace
push方法会向 history 栈添加一个新的记录,而replace方法是替换当前的页面,

不会向 history 栈添加一个新的记录

4.一般使用replace来做404页面
this.$router.replace(’/’)

配置路由时path有时候会加 '/' 有时候不加,以'/'开头的会被当作根路径,就不会一直嵌套之前的路径。

谈谈你对vuex的理解?

vuex是一个专门为vue.js开发的状态管理模式,每一个vuex应用核心就是store(仓库)。store基本上就是一个容器,它包含着你的应用中大部分的state(状态)

	vuex的状态存储是响应式的,当 vue组件中store中读取状态时候,若store中的状态发生变化,
那么相应的组件也会相应地得到高效更新。
改变store中的状态的唯一途径就是显示 commit(提交)mutation,这样使得我们可以方便地跟踪每一个状态的变化。
主要有以下几个模块:

State: 定义了应用状态的数据结构,可以在这里设置默认的初始状态
Getter: 允许组件从Stroe中获取数据, mapGetters辅助函数仅仅是将store中的getter映射到计算属性。
Mutation: 唯一更改store中状态的方法,且必须是同步函数。
Action: 用于提交muatation, 而不是直接变更状态,可以包含任意异步操作。
Module: 允许将单一的store拆分为多个 sotre且同时保存在单一的状态树中

Vuex刷新页面数据丢失,怎么处理

放在localStorage 或者就是sessionStorage ,或者借用辅助插vuex-persistedstate

基础篇

什么是Typescript?

TypeScript是一种由微软开发和维护的免费开源编程语言。它是一个强类型的JavaScript超集,可编译为纯JavaScript。它是一种用于应用级JavaScript开发的语言。对于熟悉c#、Java和所有强类型语言的开发人员来说,TypeScript非常容易学习和使用。

TypeScript可以在任何浏览器、主机和操作系统上执行。TypeScript不是直接在浏览器上运行的。它需要一个编译器来编译和生成JavaScript文件。TypeScript是带有一些附加特性的ES6 JavaScript版本。

DOM和BOM

BOM是浏览器对象模型,DOM是文档对象模型,前者是对浏览器本身进行操作,而后者是对浏览器(可看成容器)内的内容进行操作
DOM 对象 有 documet event element attlibute

BOM 对象有window history location screan

ajax请求步骤

1.创建一个XMLHttpRequest异步对象
2.设置请求方式和请求地址
3.接着,用send发送请求
4.监听状态变化
5.最后,接收返回的数据

移动端1px问题

  1. 在ios8+中当devicePixelRatio=2的时候使用0.5px,利用媒体查询
  2. 使用box-shadow模拟边框,利用css 对阴影处理的方式实现0.5px的效果
  3. viewport + rem 实现,这种兼容方案相对比较完美,适合新的项目,老的项目修改成本过大。 在devicePixelRatio
    = 2 时,输出viewport:
  4. 伪元素 + transform 实现, 对于老项目伪元素+transform是比较完美的方法了。

设计模式

单例模式
在执行当前 Single 只获得唯一一个对象
单例模式,是一种常用的软件设计模式。在它的核心结构中只包含一个被称为单例的特殊类。
通过单例模式可以保证系统中,应用该模式的一个类只有一个实例。即一个类只有一个对象实例。


工厂模式
工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。
因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,
如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,
是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。

订阅/发布模式(subscribe & publish)
  text属性变化了,set方法触发了,但是文本节点的内容没有变化。
   如何才能让同样绑定到text的文本节点也同步变化呢? 这里又有一个知识点: 订阅发布模式。
  订阅发布模式又称为观察者模式,定义了一种一对多的关系,让多个观察者同时监听某一个主题对象,
  这个主题对象的状态发生改变时就会通知所有的观察者对象。
	发布者发出通知 =>主题对象收到通知并推送给订阅者 => 订阅者执行相应的操作。

构造函数模式
  ECMAScript中的构造函数可用来创建特定类型的对象,像Array和Object这样的原生构造函数,
  在运行时会自动出现在执行环境中。此外,也可以创建自定义的构造函数,从而定义自定义对象的属性和方法。
  使用构造函数的方法,既解决了重复实例化的问题,又解决了对象识别的问题。

h5的新特性

语义标签:header footer nav aside
表单
音频 audio 视频video
canvas绘画
geolocation 定位
localstorage:长期存储数据,浏览器关闭后数据不丢失;
sessionStorage 数据在浏览器关闭后自动删除
websockt 消息推送
Drag 与Drop 拖放

浏览器的内核分别是什么?

IE: trident内核 (踹滴)
Firefox:gecko内核 (给狗)
Safari:webkit内核
Opera:以前是presto内核,Opera现已改用Google Chrome的Blink内核
Chrome:Blink(基于webkit,Google与Opera Software共同开发) (布灵克)

一次完整的HTTP事务是怎样的一个过程?

a. 域名解析
b. 发起TCP的3次握手
c. 建立TCP连接后发起http请求
d. 服务器端响应http请求,浏览器得到html代码
e. 浏览器解析html代码,并请求html代码中的资源
f. 浏览器对页面进行渲染呈现给用户

行内元素有哪些?块级元素有哪些? 空(void)元素有那些?

行内元素:a、b、span、img、input、strong、select、label、em、button、textarea
块级元素:div、ul、li、dl、dt、dd、p、h1-h6、blockquote
空元素:即系没有内容的HTML元素,例如:br、meta、hr、link、input、img

简述一下src与href的区别

href 是指向网络资源所在位置,建立和当前元素(锚点)或当前文档(链接)之间的链接,用于超链接。
src是指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在位置;
在请求src资源时会将其指向的资源下载并应用到文档内,
例如js脚本,img图片和frame等元素。当浏览器解析到该元素时,
会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕,图片和框架等元素也如此,
类似于将所指向资源嵌入当前标签内。这也是为什么将js脚本放在底部而不是头部。

es6的新特性

新增变量声明方式:let 块级作用域 const常量声明
promise
箭头函数:不需要function关键字来创建函数,可以省略return关键字,继承当前上下文的this关键字
Object.assign 浅拷贝
...扩展符号  浅拷贝  let arr = [2,3,4]; let result = [...arr];
函数参数可以直接设置默认值:function(name="xiao"){}
``反斜号模板拼接,变量用${}
结构赋值:let [a,b,c] = [1,2,3]
 Set 的成员具有唯一性: let set2 = new Set([4,5,6,5])
 console.log('array to set 1:', set2) =>{4, 5, 6}
Array.from([1,2,3]) // 返回和原数组一致

四种常见的内存泄漏:全局变量,未清除的定时器,闭包,以及 dom 的引用

全局变量 不用 var 声明的变量,相当于挂载到 window 对象上。如:b=1; 解决:使用严格模式
被遗忘的定时器和回调函数
闭包
没有清理的 DOM 元素引用

在Javascript中什么是伪数组?如何将伪数组转化为标准数组?

伪数组(类数组):无法直接调用数组方法或期望length属性有什么特殊的行为,
但仍可以对真正数组遍历方法来遍历它们。典型的是函数的argument参数,
还有像调用getElementsByTagName,document.childNodes之类的,
它们都返回NodeList对象都属于伪数组。

原型链

每个构造函数都有原型对象,每个构造函数实例都包含一个指向原型对象的内部指针(proto),如果我们让第一个构造函数的原型对象等于第二个构造函数的实例,结果第一个构造函数的原型对象将包含一个指向第二个原型对象的指针,再然第三个原型对象等于第一个构造函数的实例,这样第三个原型对象也将包含指向第一个原型对象的指针,以此类推,就够成了实例于原型的链条,这就是原型链的基本概念


闭包

闭包的概念:闭包就是能读取其他函数内部变量的函数。
优点:
避免全局变量的污染
希望一个变量长期存储在内存中(缓存变量)
缺点:
内存泄露(消耗)
常驻内存,增加内存使用量
删除闭包 直接 funtion= null; 就可以了。


懒加载的三种方式

1.第一种是纯粹的延迟加载,使用setTimeOut或setInterval进行加载延迟
2.第二种是条件加载,符合某些条件,或触发了某些事件才开始异步下载。
3.第三种是可视区加载,即仅加载用户可以看到的区域,这个主要由监控滚动条来实现,一般会在距用户看到某图片前一定距离遍开始加载,这样能保证用户拉下时正好能看到图片。

null 与 undefined 的不同点是什么呢?

共同点:都是原始类型,保存在栈中变量本地。
不同点:
(1)undefined——表示变量声明过但并未赋过值。
它是所有未赋值变量默认值,例如:
var a; // a 自动被赋值为 undefined
(2)null——表示一个变量将来可能指向一个对象。
一般用于主动释放指向对象的引用,例如:
var emps = [‘ss’,‘nn’];
emps = null; // 释放指向数组的引用
<hr style=" border:solid; width:100px; height:1px;" color=#000000 size=1">

数组操作的方法

shift:删除第一位 并返回删除的元素

unshift:数组最前面添加数据 

pop:删除最后一位 并返回删除的元素

splice:第一位起始值 第二位删除的数量 第三到N是添加到数组中

join:将数组转化为字符串

push:向数组末尾添加元素并返回新的数组长度

reverse:翻转数组

slice:(start,end)截取数组

indexOf:查找数组中数据是否存在并返回其索引值

concat:将数组连接到数组末尾

sort:数组排序

判断是否是数组的四种方法

1.通过Array.isArray()判断

Array.isArray() 用于确定传递的值是否是一个数组,返回一个布尔值。<font color="red">推荐使用

2. instanceof运算符检测Array.prototype属性是否存在于变量a的原型链上,显然a是一个数组,拥有Array.prototype属性,所以为true。
a  instanceof  Array;//true

3. 实例的构造函数属性constructor指向构造函数,那么通过constructor属性也可以判断是否为一个数组。
let a = [1,3,4];
a.constructor === Array;//true

4. Object.prototype.toString().call()可以获取到对象的不同类型,它强大的地方在于不仅仅可以检验是否为数组,
比如是否是一个函数,是否是数字等等
//检验是否是数字
let b = 1;
Object.prototype.toString.call(a) === '[object Number]';//true

let a = [1,2,3]
Object.prototype.toString.call(a) === '[object Array]';//true

this的5种绑定方式

默认绑定(非严格模式下this指向全局对象, 严格模式下this会绑定到undefined)
隐式绑定(当函数引用有上下文对象时, 如 obj.foo()的调用方式, foo内的this指向obj)
显示绑定(通过call()或者apply()方法直接指定this的绑定对象, 如foo.call(obj))
new绑定
箭头函数绑定(this的指向由外层作用域决定的)

JS数据类型:JS 的数据类型有几种?

 8种。Number、String、Boolean、Null、undefined、object、symbol、bigInt。

JS数据类型:Object 中包含了哪几种类型?

  其中包含了Data、function、Array等。这三种是常规用的。

JS数据类型:JS的基本类型和引用类型有哪些呢?

基本类型(单类型):除Object。 String、Number、boolean、null、undefined。

引用类型:object。里面包含的 function、Array、Date。

事件冒泡 ,事件捕获 ,事件代理

冒泡
p -> div -> body -> html -> document

捕获
document -> html -> body -> div -> p

代理
每个li需要点击事件的时候,将方法写在ul上,通过事件冒泡完成代理

阻止事件冒泡
1.给子级加 event.stopPropagation( )
2. 在事件处理函数中返回 false


get请求和post请求有什么区别??

「GET」

一般用于获取数据
基于URL地址传参,所以有个长度限制(一般在8KB左右),如果超过就会被截掉
因为GET请求基于问号传参容易被劫持,所以相对不安全。
会产生不可控制的缓存,POST不会
「POST」

一般用于新增数据
基于请求传参,理论上没有任何限制(真实项目中会自己做大小限制,防止上传过在信息导致请求迟迟完不成)
PSOT请求基于请求主体传参,相对来说不好被劫持,比较安全

对于http请求有了解过嘛?常见的状态码都有那些?405是什么?

HTTP网络状态码(STATUS) 根据状态码能够清楚的反映出当前交互的结果及原因

200 OK 成功(最理想的状态)
301 Moved Permanently 永久转移(永久重定向)
302 Move temporarily 临时转移
304 Not Modified 设置缓存
400 Bad Request 请求参数错误
401 Unauthorized 无权限访问
404 Not Found 找不到资源(最不理想的状态)
405 Method Not Allowed 请求行中指定的请求方法不能被用于请求相应的资源,但是该响应必须返回一个Allow头信息来表示出当前资源能够接受请求方法的列表。
500 Internal Server Error 未知的服务器错误
503 Service Unavailable 服务器超负荷

cookie、SessionStroage、LocalStroage这三者的区别。

回答这个问题的时候我没答好,讲到最后自己都没听明白,之间自己还做过笔记(可见复习的重要性,做过的笔记一定要多看,不然也就没有意义了)

存储大小
Cookie4K, Stroage5M

存储有效期
Cookie有有效期的限制,而Storage没有,sessionStorage只在窗口关闭会消失
 LocalStorage始终有效即使浏览器关闭也有,是存储在硬盘中的。
 存储位置:C:\Users\你的计算机名\AppData\Local\Google\Chrome\User Data\Default\Local Storage\leveldb

作用域不同
sessionStorage不在不同的浏览器窗口共享,
即使是同一个页面,LocalStorage在所有同源窗口中都是共享的,
cookie也是在所以同源窗口共享。

简述同步和异步的区别

同步是阻塞模式,异步是非阻塞模式。
同步就是指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息
,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;

异步是指进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。
当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

Event Loop 执行过程如下

  1. 一开始整个脚本 script 作为一个宏任务执行

  2. 执行过程中,同步代码 直接执行,宏任务 进入宏任务队列,微任务 进入微任务队列。

  3. 当前宏任务执行完出队,检查微任务列表,有则依次执行,直到全部执行完毕。

  4. 执行浏览器 UI 线程的渲染工作。

  5. 检查是否有 Web Worker 任务,有则执行。

  6. 执行完本轮的宏任务,回到步骤 2,依次循环,直到宏任务和微任务队列为空。

    事件循环中的异步队列有两种:宏任务队列(MacroTask)和 微任务队列(MicroTask)。
    宏任务队列可以有多个,微任务队列只有一个。
    宏任务 包括:script setTimeout setInterval setImmediate
    微任务 包括:Promise.then()/catch() 以 Promise 为基础开发的其他技术,例如 fetch API


浏览器缓存知道吗?

浏览器缓存也就是HTTP缓存机制,其机制是根据HTTP报文的缓存标识进行的,缓存分为两种:强制缓存 协商缓存
「强制缓存」
当浏览器向服务器发送请求的时候,服务器会将缓存规则放入HTTP响应的报文的HTTP头中和请求结果一起返回给浏览器,控制强制缓存的字段分别是Expires和Cache-Control,其中Cache-Conctrol的优先级比Expires高。

「协商缓存」
协商缓存就是强制缓存失效后,浏览器携带缓存标识向服务器发起请求,由服务器根据缓存标识决定是否使用缓存的过程

强制缓存优先于协商缓存进行,若强制缓存生效则直接使用缓存,若不生效则进行协商缓存,协商缓存由服务器决定是否使用缓存,若协商缓存失效,那么代表该请求的缓存失效,重新获取请求结果,再存入浏览器缓存中;生效则返回304,继续使用缓存


前端如何优化网站性能?

1、减少 HTTP 请求数量
在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信。浏览器与服务器需要经过三次握手,每次握手需要花费大量时间。而且不同浏览器对资源文件并发请求数量有限(不同浏览器允许并发数),一旦 HTTP 请求数量达到一定数量,资源请求就存在等待状态,这是很致命的,因此减少 HTTP 的请求数量可以很大程度上对网站性能进行优化。
CSS Sprites
国内俗称CSS精灵,这是将多张图片合并成一张图片达到减少HTTP请求的一种解决方案,可以通过CSS的background属性来访问图片内容。这种方案同时还可以减少图片总字节数。
合并 CSS 和 JS 文件
现在前端有很多工程化打包工具,如:grunt、gulp、webpack等。为了减少 HTTP 请求数量,可以通过这些工具再发布前将多个CSS或者多个JS合并成一个文件。
采用 lazyLoad
俗称懒加载,可以控制网页上的内容在一开始无需加载,不需要发请求,等到用户操作真正需要的时候立即加载出内容。这样就控制了网页资源一次性请求数量。

2、控制资源文件加载优先级
浏览器在加载HTML内容时,是将HTML内容从上至下依次解析,解析到link或者script标签就会加载href或者src对应链接内容,为了第一时间展示页面给用户,就需要将CSS提前加载,不要受 JS 加载影响。
一般情况下都是CSS在头部,JS在底部。

3、利用浏览器缓存
浏览器缓存是将网络资源存储在本地,等待下次请求该资源时,如果资源已经存在就不需要到服务器重新请求该资源,直接在本地读取该资源。

4、减少重排(Reflow)
基本原理:重排是DOM的变化影响到了元素的几何属性(宽和高),浏览器会重新计算元素的几何属性,会使渲染树中受到影响的部分失效,浏览器会验证 DOM 树上的所有其它结点的visibility属性,这也是Reflow低效的原因。如果Reflow的过于频繁,CPU使用率就会急剧上升。
减少Reflow,如果需要在DOM操作时添加样式,尽量使用 增加class属性,而不是通过style操作样式。
5、减少 DOM 操作
6、图标使用 IconFont 替换


前端安全

什么是CSRF攻击

CSRF即Cross-site request forgery(跨站请求伪造),是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法。

假如黑客在自己的站点上放置了其他网站的外链,例如"www.weibo.com/api,默认情况下,浏览器会带着weibo.com的cookie访问这个网址,如果用户已登录过该网站且网站没有对CSRF攻击进行防御,那么服务器就会认为是用户本人在调用此接口并执行相关操作,致使账号被劫持。

如何防御CSRF攻击

验证Token:浏览器请求服务器时,服务器返回一个token,每个请求都需要同时带上token和cookie才会被认为是合法请求
验证Referer:通过验证请求头的Referer来验证来源站点,但请求头很容易伪造
设置SameSite:设置cookie的SameSite,可以让cookie不随跨域请求发出,但浏览器兼容不一

什么是XSS攻击

XSS即Cross Site Scripting(跨站脚本),指的是通过利用网页开发时留下的漏洞,注入恶意指令代码到网页,使用户加载并执行攻击者恶意制造的网页程序。常见的例如在评论区植入JS代码,用户进入评论页时代码被执行,造成页面被植入广告、账号信息被窃取

XSS攻击有哪些类型

存储型:即攻击被存储在服务端,常见的是在评论区插入攻击脚本,如果脚本被储存到服务端,那么所有看见对应评论的用户都会受到攻击。
反射型:攻击者将脚本混在URL里,服务端接收到URL将恶意代码当做参数取出并拼接在HTML里返回,浏览器解析此HTML后即执行恶意代码
DOM型:将攻击脚本写在URL中,诱导用户点击该URL,如果URL被解析,那么攻击脚本就会被运行。和前两者的差别主要在于DOM型攻击不经过服务端

如何防御XSS攻击

输入检查:对输入内容中的script iframe 等标签进行转义或者过滤
设置httpOnly:很多XSS攻击目标都是窃取用户cookie伪造身份认证,设置此属性可防止JS获取cookie
开启CSP,即开启白名单,可阻止白名单以外的资源加载和运行


手写call

Function.prototype.myCall = function(context, ...args) {
  context = context || window
  let fn = Symbol()
  context[fn] = this
  let result = context[fn](...args)
  delete context[fn]
  return result
}

手写apply

Function.prototype.myApply = function(context) {
  context = context || window
  let fn = Symbol()
  context[fn] = this
  let result
  if (arguments[1]) {
    result = context[fn](...arguments[1])
  } else {
    result = context[fn]()
  }
  delete context[fn]
  return result
}

手写bind

Function.prototype.myBind = function (context) {
  var _this = this
  var args = [...arguments].slice(1)
  // 返回一个函数
  return function F() {
    // 因为返回了一个函数,我们可以 new F(),所以需要判断
    if (this instanceof F) {
      return new _this(...args, ...arguments)
    }
    return _this.apply(context, args.concat(...arguments))
  }
}

防抖

防抖和节流的作用都是防止函数多次调用。区别在于,假设一个用户一直触发这个函数,且每次触发函数的间隔小于阈值,防抖的情况下只会调用一次,而节流会每隔一定时间调用函数。

    function debounce(fn, time) {
            let timer = null
            return function () {
                let args = arguments
                let context = this
                if (timer) {
                    clearTimeout(timer) //清除这个
                    timer = null
                }
                timer = setTimeout(function () {
                    fn.apply(context, args)
                }, time)


            }

        }
		
   function test(name) {
         this.name = name
         console.log(this.name)
         console.log(this)
  }
   let newFn = debounce(test, 3000)
   window.onscroll = function () {
       newFn("333")
   }

节流

 function throttle (fn,time){
	   let canRun=true
       return function(){
           if(canRun){
               fn.apply(this,arguments)
               canRun=false
               setTimeout(function(){
                   canRun=true
               },time)
           }
       }

   }

   function test(name){
       this.name=name 
       console.log(this.name )
       console.log(this)
   }
   let obj={
       age:18
   }
   let newFn=throttle(test,1000)
   obj.newFn=newFn
   window.onscroll=function(){
       obj.newFn("333")
   } 

new

  // new的实现,因为new是语言层面的操作符,所以用一个函数模仿一下
        function newFacCat(constructor){
            // 原型对象的方法继承到obj上
            let obj= Object.create(constructor.prototype)  //等同于 obj.__proto__=constructor.prototype
            
            //切割掉传进来的对象,只留参数
            let args=Array.from(arguments).slice(1)
            let result= constructor.apply(obj,args)
            console.log(result)
            // instanceof可以对不同的对象实例进行判断,判断方法是根据对象的原型链依次向下查询,如果obj2的原型属性存在obj1的原型链上,(obj1 instanceof obj2)值为true。
            //如果result返回的是对象则返回rusult  否则返回obj
            return result instanceof Object?result:obj

        }

            // 构造函数
          function Cat (name,color){
            this.name=name 
            this.color=color
           
        }

        Cat.prototype.miao=function(){
            console.log("喵~!")
        }
        let cat =newFacCat( Cat,"大猫","橙色")
        console.log(cat.__proto__===Cat.prototype)
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值