中级前端必会基础面试题

848 阅读22分钟

1.说出cookie,sessionStorage和localStorage的区别

cookie:服务器端创建,浏览器端保存,请求携带对应的cookie,长度和数量有限制(4k)

localStorage:浏览器getItem持久化存储,关闭浏览器后还在

sessionStorage:会话存储,关闭浏览器后消失

方法:getItem(),setItem(),removeItem(),valueOf(),clear(),hasOwnProperty()

2.说出你所知道的http状态码

1xx(信息类):表示接收到请求并且继续处理

100:客户必须继续发出请求

2xx(相应成功):表示动作被成功接收处理

200:ok,正常返回信息
201:created,请求成功并且服务器创建新的资源
202:accepted,服务器已接受请求,但尚未处理

3xx(重定向类) :为了完成指定的动作,必须接收进一步处理

301:请求的网页已被永久移动到新位置
302:临时性重定向
303:临时性重定向,且总是使用GET请求新的URL
304:自从上次请求后,请求的网页未修改过

4xx(客户端错误类):请求包含错误语法或不能正确执行

400:服务器无法理解请求的格式,大概率时传参的问题
401:请求未授权
403:禁止访问
404:找不到与URL相匹配的资源

5xx(服务端错误类):服务器不能正确执行一个正确的请求

500:最常见的服务器端错误
503:服务气暂时无法处理请求(可能是过载或维护)

3.常见的数组的方法

Array.from():将一个类数组对象或者可便利对象转换成一个真正的数组

Array.prototype.copyWithin():浅复制数组的一部分到同一数组中的另一个位置,并返回它,不会改变原数组的长度

Array.prototype.some():测试数组中是不是至少有一个元素通过了被提供的函数测试,它返回的是一个boolean类型的值,true/false

Array.prototype.every():测试数组的所有元素

Array.prototype.flat():将层层嵌套的数组展开返回一个新的数组,嵌套数组扁平化处理

Array.prototype.includes():用来判断一个数组是否包含一个指定的值,根据情况,如果包含则返回true,否则返回false

Array.proyotype.lastIndexOf():返回指定元素在数组中的最后一个的索引,如果不存在则返回-1,从数组的后面向前查找
Array.prototype.reduce():对数组中的每个元素执行一个由您提供的reduce函数(升序执行),将其结果汇总为单个返回值

Array.prototype.entries():返回一个新的Array Iterator对象,该对象包含数组中的每个索引的键值对

filter():创建一个数组,包含函数测试通过的所有元素

find():返回一个数组中满足提供测试函数的第一个元素

arr.pop():从数组尾部弹出一个元素,并返回弹出的元素

arr.push():从数组的尾部压入一个元素,并返回数组的新长度

arr.shift():从数组的头部弹出一个元素,并返回此元素

arr.unshift():从数组的头部压入一个元素

arr.concat([arr]):连接原数组的元素和传递的参数形成一个新数组并返回,不影响原来的数组

arr.join('-'):可以把数组元素连接成字符串,接收一个参数为连接符串,返回的结果为字符串

arr.slice():复制数组的一部分,参数:获取数组起始索引和结束索引

arr.splice():在数组上进行插入或删除数组元素,会影响原来数组  参数一:删除数据的索引位置,到结束  参数二:要删除数组元素的个数  参数三:要插入到原数组中的元素,插入的位置从第一个参数所在的索引开始

4.简述CSS盒模型

分为标准盒模型与IE盒模型

标准:content+padding+border+margin

IE:content+margin 将padding+border合到了content中

5.为什么会有跨域问题,如何解决

原因是浏览器为了安全,而采用的同源策略

协议+域名+端口号相同就同源,一个不同就不同源

1.JSPON解决跨域

原理:由于script标签不受浏览器同源策略的影响,允许跨域使用资源,因此可以通过动态创建script标签,然后利用src属性进行跨域,这就是使用JSPON跨域的基本原理

2.利用CORS解决跨域

原理:后台需要设置响应头:'Acces-Control-Allow-Origin-’*‘

3.配置正反向代理

原理:正向代理主要代理的是客户端,反向代理一般用的是nginx

6.路由守卫(导航守卫)

路由守卫就是路由跳转过程中的一些钩子函数,路由跳转是一个大的过程,这个大的过程分为跳转前中后等等细小的过程,在每一个过程中都已函数,这个函数能让你操作一些其它的事,这就是路由守卫,类似于组件生命周期钩子函数。

全局前置守卫:router.beforeEach

全局解析守卫:router.beforeResolve

全局后置钩子:router.afterEach

路由独享的守卫:beforeEnter

组件内的守卫:beforeRouterEnter

                        beoreRouteUpdate

                        beforeRouteLeave

7.函数的节流防抖

节流:设定一个特定的时间,然函数在特定时间内只执行一次,不会频繁执行

举例:游戏中,鼠标按住 不松手,子弹并不会连城一条直线

需求:在鼠标滚动滚轮的时候,每隔一秒钟,打印一次

抖:延迟要执行的动作,若在延时的这段时间内再次触发了,则取消之前的动作,重新计时

需求:搜索时,等用户完整的输入内容后再发送查询请求

8.微信小程序

微信小程序没有DOM,一切基于组件化

它的配置方案是1rpx=0.5px

小程序的本地存储它需要注意的事单个key允许存储的最大数据长度为1M,所有数据存储上限为10MB,否则回内存溢出

小程序路由跳转不需要专门注册路由,会访问全局配置pages的列表,需要指定的API跳转

小程序的事件处理主要分为冒泡事件 bind+时间名 与非冒泡事件 catch+事件名

小程序发送请求用的语法事wx.request(),需要注意的是它的协议是http协议,对于每个接口(当前小程序),分别可以配置最多20个域名,最大并发限制是10个(同一时间发送请求的数量)

小程序获取openId流程(用户唯一标识)

小程序客户端拿到code,发送请求给开发者服务器,服务器端整合其它两条数据给微信的服务器,换取openId

自定义登录状态其实就是对当前数据进行加密,生成token,把token返给前端

9.HTML5新特性

语义化标签 :header    footer   nav

新表单类型:tel  date

视频和音频

canvas绘图

localStorage与sessionStorage

10.移动端适配

方案一:viewport

方案二:rem适配

rem适配的三种实现方式

1.借助media使用媒体查询设置根元素 的大小,元素大小需要根据设计稿来计算

2.js动态修改根元素的大小,根据设计稿自行计算

3.js动态修改配合css预处理器,即用less

11.图片的懒加载怎么实现

定义:当打开一个有很多图片的页面时,先只加载页面上看到的图片,等滚动到页面下面时,再加载所需的图片,这就是图片懒加载

作用:减少或延迟请求次数,缓解浏览器的压力,增强用户体验

实现方式:设置图片的src属性为同一张图片,同时自定义一个data-src属性来存储图片的真实地址

页面内初始化显示的时候或者浏览器发生滚动的时候判断图片是否在视野中

当图片在视野中时,通过js自动改变该区域的图片的src属性为真实地址

12.Vue中的数据代理

内部调用的是一个defineProperty()方法,先把vm实例对象中的data拿到,把里面的属性全部进行便利,每遍历一个的时候就会调用object.defineProperty方法,为vm实例对象上添加data里的每一个属性,并且会重新设置set和get方法

13.Vue如何实现双向数据绑定

vue实现数据绑定主要是采用数据劫持+消息订阅发布模式的方式

通过Object.defineProperty()来劫持监视data中的属性,在数据变动时发布消息给所有订阅者,每个订阅者去更新对应的DOM节点

双向数据绑定是单向数据绑定的基础上,给元素绑定input监听,一旦输入改变了,将最新的值保存到对应的属性上

14.闭包

定义:闭包是保存在内部函数的一个引用,该引用指向的是外部函数的变量对象,该引用能保证内部函数能够访问外部函数的变量对象,在外部函数执行完后不会被垃圾对象处理掉

作用:延长外部函数局部变量的生命周期,使函数外部可以多次间接操作到函数内部的数据

缺点:变量常驻内部,会增大内存使用量,使用不当很容易造成内存泄漏

15.在Vue项目开发过程中,更新状态数据,对应的界面不发生变化,如果在实例创建之后,添加新的属性到实例上,它为什么不会触发视图更新

原因:一般方法给一个已有绑定的对象中添加一个新的属性,这个属性没有数据绑定

向响应式对象中添加一个属性,并确保这个属性同样是响应式的,且触发视图更新,它必须用于向响应式对象上添加新属性,因为Vue无法探测普通的新增属性

解决方法:vue.set()

                 this.$set(this.data,'key',value)

16.说说原型与原型链

当从一个对象哪里调取属性或方法时,如果该对象自身不存在这样的属性或者方法,就会去自己关联的prototype对象哪里寻找,如果prototype没有,就会去prototype关联的前辈prototype哪里寻找,如果再没有则继续查找prototype.prototype引用的对象,依次类推,直到prototype......prototyoe为undefined(Object的prototype就是undefined),从而形成了所谓的‘原型链’

17.箭头函数与普通函数的区别

①.this指向的问题

箭头函数的this指向的是父级作用域的this,是通过查找作用域链来确定this的值,也就是说看的是上下文的this,指向的是定义它的对象,而不是使用时所在的对象

普通函数指向的是它的直接调用者

②.不可以当作构造函数

③.不可以使用arguments对象,该对象在函数体内不存在,如果要用就用rest参数代替

④.不可以使用yield命令,因此箭头函数不能用作Generator对象

18.说说你对Vuex的理解

vuex是vue的一个插件,是对vue应用中多个组件的共享状态进行集中式的管理(读/写)

state:包含了多个状态数据的对象,以后写在data里的数据都可以写在state中

mutations:包含了多个直接修改状态数据的方法的对象

actions:包含了多个间接修改状态数据的方法的对象

getters:包含了读个状态数据的计算属性的get方法的对象

19.混合(混入)

在vue中如果多个组件中有相同的配置选项,可以抽到一个js文件中,然后再该组件的配置选项中,引入这个文件暴露处理的对象,需要使用mixins:[]的方法引入,该组件就可以使用混合中的配置选项内容了

20.组件间的通信方式

①.props

多用于父传子,通过标签属性传递,在子组件通过props接收,也可用于跨组件通信,逐层传递,但无形中增大了复杂度,容易出问题

加分项:通过props传值是一个给props对象赋值的过程,如果传递的数据中包含引用数据类型的时候,会出现引用传递,即在子组件中修改数据会影响到父组件的状态值

②.自定义函数传递

多用于子传父,在父组件中定义函数并声明形参,将函数通过props传递给子组件,在子组件中调用该函数并传入实参

③.插槽

多用于向组件内部传递标签数据

场景:封装组件用于复用,将组件内不同的标签部分提取出来用插槽传递,提高组件的复用性

分类:普通插槽,具名插槽

当组件内只有一个插槽的时候可以使用普通插槽

当组件内有多个插槽的时候需要根据插槽的名字使用具名插槽

④.事件总线

多用于跨组件通信

vue.prototype-原型对象 把Vue的实例对象挂载到Vue的原型对象上

Vue.prototype.$Bus = new Vue() 

$on('事件名',回调函数)  绑定事件

$emit('事件名','参数数据')  分发事件

$off('事件名')  解绑事件

21.Vue的生命周期

共有11个,常用的有8个

beforeCreate

created

beforeMount

mounted

beforeUpdate

updated

beforeDestroy

destroyed

actived  组件缓存时使用  激活状态

deactivated 组件缓存时使用  未激活状态

errorCaptured  错误捕获,当捕获一个来自子孙组件的错误时被调用

22.浏览器渲染原理解析

①.首先渲染引擎下载HTML,解析生成DOM Tree

②.遇到css标签或js脚本标签就新起线程去下载他们,并继续构建DOM

③.通过CSS Rule Tree 匹配DMO Tree进行定位坐标和大小,这个过程称为Flow或Layout

④.最终通过调用Native GUI的API绘制网页画面的过程称为Paint

23.对象原生的方法

Object.isPrototypeOf() 一个对象是否是另一个对象的原型

Object.toString()定义一个对象的字符串表示

Object.valueOf() 指定对象的原始值

24.apply,call和bind的区别

都是改变this指向

call和apply会立即执行,call就是普通传参,apply传一个数组

bind返回了一个新的函数,不会立即执行

25.判断数据类型的方式

方法一:typeOf 运算符

返回结果包括:‘string’,'number','boolen','undefined','object','function','symbol'七种类型不能判断Null,NaN

typeOf null 返回的是object,但null 不是对象

方法二:instanceof运算符

通过原型链判断 A instaceof B ,在A的原型链中查找层层查找,是否有原型等于B.prototype

方法三:Object.prototype.toString.call() 方法

26.执行上下文

是什么:当前代码的运行环境

全局执行上下文:

在执行全局代码前将windows确定为全局执行上下文

对全局数据进行预处理(预解析):var定义的全局变量,提前定义(声明),值为undefined,是添加为windows的属性

function声明的全局函数,提前定义(声明),添加为windows的方法

this赋值为this

函数执行上下文:

在调用函数时,准备执行函数之前,会创建该函数所对应的执行上下文

对局部函数开始进行预处理

形参变量=>赋值为实参=>将形参定义在该函数对应的执行上下文区域内

arguments=>赋值为实参列表,定义在该函数对应的只能怪上下文区域内

var定义的局部变量=>赋值为undefined,定义在该函数对应的执行上下文区域内

function声明的函数=>赋值(函数体内容),定义在该函数对应的执行上下文区域内

this=>赋值(调用该函数的对象)

执行上下文栈

代码整体运行步骤:

①.在全局代码运行前 ,js引擎会创建一个栈结构来存储和管理所有的执行上下文

②.在全局执行上下文(undefined所对应的)确定后,将其添加到栈中(压栈),此时的栈底是全局执行上下文

③.在函数执行之前,创建函数的执行上下文,随后压栈

④.在当前函数执行完毕后,将该函数的执行上下文在栈中移除(出栈)

⑤.当所有的代码执行完后,栈中只剩下全局执行上下文

备注:执行上下文栈中,栈顶的永远是当前正在执行的函数执行上下文

27.字符串的方法

charAt(x):返回字符串中x位置的字符,下标从0开始

concat(v1,v2):用于连接两个或多个字符串,此方法不改变现有的字符串,返回拼接后的新的字符串

indexOf(substr,[start]):搜索并(如果找到)返回字符串中搜索到的字符或字符串的索引。如果没有找到。则返回-1,start是一个可选参数,指定字符串中开始的搜索位置,默认值为0

match(regexp):根据正则表达式在字符串中搜索匹配项。如果没有找到匹配项,则返回一个信息数组成null

replace:用于在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的字符串

28.Vue脚手架下载

npm install -g vue-cli 安装脚手架

vue init webpack vue-demo 初始化脚手架

29.npm常用命令

npm install 安装模块

npm uninstall 卸载模块

npm init 在项目中引导创建一个package.json文件

npm root 查看它的安装路径 输出node_modules的路径

npm ls 查看安装的模块

npm start 启动模块

npm stop 停止模块

npm update 更新模块

npm outdated 检查模块是否已经过时

npm restart 重新启动模块

npm help 查看某条命令的详细帮助

npm config 管理npm 的配置路径

npm cache 管理模块的缓存

30.Vue的常用配置及其作用

el:最外层元素选择器

props:声明接收那些属性

data:状态数据

computed:计算属性

methods:事件回调函数

watch:监视属性变化

directives:注册局部指令

filters:注册局部过滤器

components:配置组件

31.Vue常用指令及作用

v-text:设置标签体文本

v-html:设置标签体字标签

v-if/v-else/v-show:显示/隐藏

v-for:遍历显示列表

v-bind:强制绑定表达式,简写:

v-on:绑定事件监听,简写@

v-model:双向数据绑定

31.==和===的区别

前者会自动转换类型,后者不会

32.Vue中计算属性和watch的比较

一个数据属性在它所依赖的属性发生变化时,也要发生变化,这种情况最好使用计算属性

watch监听的是你定义的变量,当你定义的变量的值发生变化时,调用对应的方法,适用于当数据发生变化时,执行异步操作

33.如何确定this的值

①.对象调用,this时obj  obj.test()

②.直接调用,this是window test()

③new关键字调用,this是实例对象  var x = new fn()

④call和apply调用,test.call  apply(obj)  this是编码人员强制指定的

34.性能优化的方案

减少对DOM的操作,避免重绘重排

减少请求的个数,节省网络资源

封装功能函数实现复用

慎用闭包

函数节流,函数防抖

图片懒加载,路由懒加载

35.new的实现原理

①.创建一个新的对象,并且this变量引用该对象,同时继承了该函数的原型

②.属性和方法被加入到this引用的对象中

36.EGT和POST的区别

37.谈一谈let,var和const的区别

var

  • 使用var申明的变量,是全局变量。

    function textVar(){

        var a=30;
    
        if(true){
    
            var a=50;
    
            console.log(a);//50
        };
    
        console.log(a);//50 找离他最近的a
    
    };
    

let

  • let有作用域的概念,他只在let命令所在的代码块内有效。

    function textLet(){

        let a=30;
    
        if(true){
    
            let a=50;//有作用域的概念
    
            console.log(a);//50 
        };
    
        console.log(a);//30 
    
    };
    
    textLet();
    
  • let非常适合在for循环中使用,如果在外部读取,则会报错。

    for (let i = 0; i < 10; i++) { // ... }

    console.log(i);
    // ReferenceError: i is not defined
    

let 与var的区别

  • let不存在变量提升,var会出现变量提升的情况,也就是说在变量没有申明的情况下去使用,但是它的值为undefined ,let就不存在这种情况,let不允许在没有申明的情况下去使用,

    console.log(foo); //undefined var foo = 2;

    console.log(bar); //ReferenceError
    let bar = 2;
    
  • let不允许重复声明,不允许在相同作用域内,重复声明同一个变量。但var可以,只不过它的值会被覆盖。

    function letAndVar() { let a = 10; var a = 1; } // 报错

    function letAndVar() {
      let a = 10;
      let a = 1;
    }
     // 报错
    
    function letAndVar() {
       var a = 10;
       var a = 1;
    }
    // 正常,但是a的值会为1
    

const

  • 一但申明,不可修改,他是一个常量。

    const x=10;

    x=100;
    
    console.log(x);//Uncaught TypeError: Assignment to constant variable.
    

38.Vue实例的响应式属性 VS 非响应式属性

①.响应式属性

Vue实例初始化之前定义在data中的属性,修改响应式属性之后,会触发视图更新

②.非响应式属性

在Vue实例初始化之后添加的属性,添加或者修改非响应式属性不会触发视图更新

39.css样式显示省略号

.ellipsis{
    overflow:hidden;
    text-overflow:ellipsis;
    white-space:nowrap;
}

40.CSS隐藏元素的方法

①.display:none; 脱标,不占空间,不影响布局,无法响应事件

②.opacity:0;设置元素透明度,不脱标,占据空间可相应事件

③.visibility:hidden;不脱标,不想响应任何用户交互

④.position:absolute;脱标,通过定位将元素定到远离页面的位置

⑤.clip-path:polygon(0px,0px,0px,0px,0px,0px,0px,0px);通过剪裁盒子,不脱标

41.一个页面从输入URl到页面加载显示完成,这个过程发生了什么?

①.浏览器根据请求的URL交给DNS域名解析,找到真实IP,向服务器发起请求

②.服务器交给后台处理完成后返回数据,浏览器接收文件(html,css,js,图像等)

③.浏览器对加载到的资源(html,css,js等)进行语法解析,建立相应的内部数据结构(如html的DOM)

④.载入解析到的资源文件,渲染页面完成

42.为什么要初始化css样式

因为浏览器的兼容问题,不同浏览器对有些标签的默认值是不同的,如果没对css初始化往往会出现浏览器至今的页面显示差异

43.怎样解决页面中的间隙问题

display:inline-block

移除空格

使用margin负值

使用font-size:0

letter-spacing:word-spacing

44.怎样使一个浮动的元素垂直居中

使一个浮动的元素垂直居中用定位就可以,分为已知高度跟未知高度,已知高度用负的margin拉。未知用transion拉

45.v-for中key的作用

key主要就是用来提高渲染性能的

key属性可以避免数据混乱的情况出现(如果元素中包含了有临时数据的元素,如果不用key就会产生数据混乱)

46.position的属性值

absolute 绝对定位

fixde 固定定位

relative 相对定位

static 默认值

inherit 规定应该从父元素继承position属性的值

47.清除浮动的方法

①.利用clear样式

②.利用伪元素

clearfix:after{
    contant:'';
    height:0;
    display:block;
    clear:both;
}

③.overflow清除浮动

48.jQuery的编程三大特点

链式编程

隐式迭代:可以不用循环遍历对dom操作,对数组或者类数组操作

读写二合一

49.jQuery常用的方法

$.each():遍历数组或对象中的数据

$.trim():去除字符串两边的空格

$.type(obj):得到数据的类型

$.isArray(obj):判断是否是数组

$.isFunction(obj):判断是否是函数

50.Vue跟jQuery的区别

①.Vue比jQuery减少了DOM操作

为什么要减少DOM操作?

答:当DOM操作影响到布局的时候,浏览器的渲染引擎就要重新计算然后渲染,越多的DOM操作就会导致越多的计算,自然会影响页面性能,所以DOM操作减少是最好的

Vue是怎样减少DOM操作的呢?

答:Vue通过虚拟DOM技术减少DOM操作,什么是虚拟DOM?使用js对象模拟DOM,在操作过程中不会直接操作DOM,等待虚拟DOM操作完成,仅仅比较开始和结束状态虚拟DOM有哪些变换,最终根据结束状态虚拟DOM去操作DOM,至于虚拟DOM怎么比较则是用diff算法

diff算法的处理方式

优先处理特殊场景

①.头部的同类型节点,尾部的同类型节点

这类节点更新前后位置没有发生变化,所以不用移动他们对应的DOM

②.头尾/尾头同类型节点

这类的节点位置很明显,不需要再花心思查找直接移动DOM就好

原地复用

"原地复用"是指Vue会尽可能复用DOM,尽可能不发生DOM移动,Vue在判断更新前后指针是否指向同一节点,其实不要求它们真实引用同一个DOM节点,实际上它仅判断指向的是否是同类系欸但,如果不是同类节点,那么Vue会直接复用DOM,例如通过对接文本内容的方式,这样的好处是不需要移动DOM。

②.Vue支持双向数据绑定

数据有单向数据绑定和双向数据绑定

什么是单向数据绑定?

指数据影响页面,而页面不影响数据

什么是双向数据绑定?

双向的意思即两个方面相互影响,前端来说,即数据影响页面,页面同时影响数据。例如:在MVVM框架中,View(视图)和Model(数据)是不可以直接通讯的,在它们之间存在着ViewModel这个充当着观察者的角色,当用户操作View(视图),ViewModel感知到变化,然后通知Model发生相应改变,反之当Model(数据)发生变化,ViewModel也能感知到变化,是View做出响应的更新。

其实v-model只是语法糖,双向绑定其实就等于单向绑定+UI事件监听,只不过Vue将过程采用黑箱封装起来了

双向数据绑定有什么好处?

方便,数据自动更新,而缺点就是无法得知哪里更改了数据

③.Vue支持组件化

web中的组件其实就是页面组成的一部分,好比是电脑中的每一个元件(如硬盘,键盘,鼠标),它是一个具有独立的逻辑和功能或页面,同时又能根据规定的接口规则进行相互融合,变成一个完整的应用,页面就是有一个个类似这样的部分组成,比如导航,列表,弹窗,下拉菜单等。页面只不过是这些组件的容器,组件自由组合形成功能完善的界面,当不需要某个组件,或者想要替换某个组件时,可以随时进行替换和删除,而不影响整个应用的运行。

组件化的特性

高内聚性:组件功能必须是完整的,如我要实现下拉菜单功能,那在下来菜单这个组件中,就把下拉菜单所需要的所有功能全部实现

低耦合性:通俗点说,代码独立不会和项目中的其它代码发生冲突。在实际工程中,我们经常会涉及到团队协作,传统按照业务线去编写代码的方式,就很容易相互冲突,所以运用组件化方式就可以大大避免这种冲突的存在

每一个组件都有子集清晰的职责,完整的功能,较低的耦合性,便于单元测试和重复利用

组件化的有点

提高开发效率

方便重复使用

简化调试步骤

提高整个项目的可维护性

便于协同开发

51.this.routethis.route和this.router的区别

this.$router相当于是一个全局的路由对象,包含了很多属性和对象(比如history对象),任何页面都可以调用其push(),replace(),go()等方法

this.$route表示当前路由对象,每个路由都会有一个route对象,是一个局部的对象,可以获取对应的name,path,params,query等属性

52.路由跳转相对于a标签的好处

真正的实现了前后端分离,后端专注在数据上,前端专注在交互和可视化上

53.的作用是什么

就是一个声明,告诉浏览器用那种HTML的版本规范来解读HTML文档

54.手写一个原生ajax请求

实例化一个XML HTTP Request 对象,名为xhr
let xhr = new XML Http Request();
给上一步实例化出来的对象绑定监听,名为onreadystatechange
xhr.onreadystatechange=function() {
    if(xhr.readyState === 4 && xhr.states === 200){
        console.log(xhr.response)
    }
}
指定发送请求的方式,地址,参数
xhr.open('get','http://localhost:3000/test?name=zhansan')
发送请求xhr.open()

55.数组的去重

 // 循环去重
var array = [1,1,2,2,3,3,4,5,6,5]function unique(array) {  var res = []  for(var i=0;i<array.length;i++){    for(var j=0;j<res.length;j++){      if(array[i]===res[j]){        break;    }  }    if(j===res.length){      res.push(array[i])    }  }console.log(res)return res;}unique(array)
// 在这个方法中,我们使用循环嵌套,最外层循环array,里面循环res,如果array[i]的值跟res[j]的值相等,
就跳出循环,如果都不等于,说明元素是唯一的,这时候j的值就会等于res的长度,根据这个特点进行判断,
将值添加进res// 数组的indexOf方法function unique1() {var res = []for(var i = 0; i<array.length; i++){  var current = array[i]  if(res.indexOf(current) ===-1){      res.push(current)    }  }  console.log(res)  return res}unique1(array)

//排序后去重function unique2() {var res = []var sortedArray = array.concat().sort()var seenfor(var i=0;i<sortedArray.length;i++){  if(!i || seen !== sortedArray[i]){    res.push(sortedArray[i])  }    seen = sortedArray[i]}  console.log(res)  return res}unique2(array)// 我们先将要去重的数组使用sort方法排序后,相同的值就会被排在一起,然后我们就可以只判断当前元素与上一个元素是否相同相同就说明重复,不相同就添加进res// filterfunction unique3() {  var res = array.filter(function(item,index,array){    return array.indexOf(item)===index})console.log(res)return res}unique3(array)


//ES6// ES6提供了新的数据结构set,它类似于数组,但是成员的值都是唯一的,没有重复的值function unique4(array) {  console.log(new Set(array))}unique4(array)

56.冒泡排序

function test(arr) {
    for(var i=0; i<arr.length-1; i++){
        for(var j=0; j<arr.length-1-i; j++){
            if(arr[j]<arr[j+1]){
                var temp = arr[j]
                arr[j] = arr[j+1]
                arr[j+1] = temp
            }
        }
    }
    console.log(arr)
}

57.数组的深浅拷贝

浅拷贝:直接使两个数组相等就可以

深拷贝:

①.使用数组遍历赋值

原理:最原始的方法,就是把每个值取出来到另一个数组中

②.使用数组map方法

使用map方法遍历数组然后返回新的数组,里面的值不变

③.使用concat方法

连接数组,如果连接的是一个空,那么也是返回了新的本身的数值

④.使用ES6语法实现深拷贝

ES6三点运算符实现数组的深拷贝,目前是最简单的

⑤.for-in连原型链也一并复制的方法

这种方法,不仅复制的值,还会把属性也进行拷贝

⑥.多维数组的复制

function deepClone(target) {
    let result = null
    if(target instanceOf Array){
        result = []
    }else if (target instanceOf Object){
        result = {}
    }else{
        return target
    }
    for(let key in target){
        let item = target[key]
        if(item instanceOf Array || item instanceOf Object){
            result[key] = deepClone(item)
        }else{
            result[key] = item
        }
    }
    return result
}

58.Vue父子组件生命周期执行顺序

加载渲染过程

->父beforeCreate -> 父created -> 父beforeMount****->子beforeCreate -> 子created ->子beforeMount -> 子mounted-> 父mounted

子组件更新过程

->父beforeUpdate**-> 子beforeUpdate -> 子updated****-> 父updated**

父组件更新过程

父beforeUpdate -> 父updated

销毁过程

-> 父beforeDestroy**-> 子beforeDestroy** -> 子destroyed**-> 父destroyed**

59.伸缩盒模型(弹性盒模型)

①.flex容器

display:flex;
desplay:-webkit-flex; chome内核

②.主轴的布局方向

flex-direction:row; 横向,主轴默认值
flex-direction:column; 主轴与侧轴发生对调

③.主轴的排列方向

flex-direction:row-reverse; 主轴从左到右,startend对调
flex-direction:column-reverse; 主轴与侧轴发生对调,主轴startend对调

④.富裕空间的管理(主轴,内容的对齐方式)

justify-content:flex-start;富裕空间在右侧
justify-content:flex-end;富余空间在左侧
justify-content:center;富裕空间在两边
justify-content:space-around;富裕空间围绕
justify-content:space-between;富裕空间在...之间
justify-content:space-evenly;富裕空间均匀分布

⑤.富裕空间的管理(侧轴)

align-items:flex-start;富裕空间在下边
align-items:flex-end;富裕空间在上边
align-items:center;富裕空间在两边
align-items:baseline;富裕空间被基线分开
align-items:stretch;拉伸,默认值

⑥.弹性空间(伸缩项目)

flex-grow:1;将富余空间分配到项目上(子元素上)

新版本特有属性

①.项目实现换行(flex容器)

flex-wrap:nowrap;默认值,父元素宽度不够,子元素自身宽度会被压缩
flex-wrap:wrap;父元素宽度不够,子元素进行换行
flex--wrap:wrap-reverse;子元素换行的同时,侧轴的start与end发生对调

②.控制整体侧轴的富余空间(flex容器)换行后生效

align-content:flex-start;项目整体进行打包,放在整体侧轴start处
align-content:flex-end;项目整体进行打包,放在整体侧轴end处
align-content:center;项目整体进行打包,放在整体侧轴的center处
注意:align-itemsalign-content发生冲突时,看元素是否换行,如果没有换行align-items生效,如果有换行align-content生效
align-content生效条件
在伸缩容器中产生换行flex-wrap:wrap
同时设置足够高的容器高度(因为需要整体打包才能看见效果,所以需要高度)

③.项目的排列顺序(flex项目)子元素

order:1;order排序,往后排,看编号,编号大的在前
order排序,把排序元素先单独拿出来,让剩余元素先正常排列,拍完之后,order元素在其后面再进行顺序排列
沿着主轴方向进行排序

④.项目自身侧轴的富余空间(flex项目)

align-self:flex-start;
align-self:flex-end;
align-self:center;

60.ES6新特性

61.Vue3新特性

62.触发Vue的生命周期的条件是什么

①.浏览器刷新的时候

②.路由跳转的时候

63.数组扁平化处理

①.使用递归

function flatten(arr) {
    var result = [];
    for (var i = 0, len = arr.length; i < len; i++) {
        if (Array.isArray(arr[i])) {
            result = result.concat(flatten(arr[i]))
        } else {
            result.push(arr[i])
        }
    }
    return result;
}

②.[1, [2, [3]]].flat(2)

64.斐波那契数列

1,1,2,3,5,8,13......斐波那契数列的原理就是前两位之和等于第三位

解决方法:循环和递归

function fibonacci(n) {
    if (n == 1 || n == 2) {
        return 1
    };
    return fibonacci(n - 2) + fibonacci(n - 1);
}
fibonacci(30)

function fibonacci(n) {
    var n1 = 1, n2 = 1, sum;
    for (let i = 2; i < n; i++) {
        sum = n1 + n2
        n1 = n2
        n2 = sum
    }
    return sum
}
fibonacci(30

65.宏任务与微任务

宏任务:整体代段script,settimeout,setInterval

微任务:promise,process.nextTick

事件循环的顺序,决定js代码的执行顺序,进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕,再执行所有的微任务。

66.设置小于12px的字体大小

css3属性 :transform:scale(0.5)

67.px、rem、em的区别

①.px是像素单位,是相对于显示器分辨率而言的

②.rem相对元素单位,相对于的是浏览器根元素的大小,html标签

③.em相对元素单位,相对于的是父级元素的大小

68.一像素边框

产生原因:主要是跟一个东西有关,DPR(devicePixelRatio) 设备像素比,它是默认缩放为100%的情况下,设备像素和CSS像素的比值。

window.devicePixelRatio=物理像素 /CSS像素

目前主流的屏幕DPR=2 (iPhone 8),或者3 (iPhone 8 Plus)。拿2倍屏来说,设备的物理像素要实现1像素,而DPR=2,所以css 像素只能是 0.5。一般设计稿是按照750来设计的,它上面的1px是以750来参照的,而我们写css样式是以设备375为参照的,所以我们应该写的0.5px就好了啊! 试过了就知道,iOS 8+系统支持,安卓系统不支持。

解决方案:

①:

border:0.5px solid #fff;

可能你会问为什么在3倍屏下,不是0.3333px 这样的?经过我测试,在Chrome上模拟iPhone 8Plus,发现小于0.46px的时候是显示不出来。

  • 优点:简单,没有副作用

  • 缺点:支持iOS 8+,不支持安卓。后期安卓follow就好了。

②:使用边框图片

 border: 1px solid transparent;
 border-image: url('./../../image/96.jpg') 2 repeat;
  • 优点:没有副作用

  • 缺点:border颜色变了就得重新制作图片;圆角会比较模糊。

③:使用box-shadow实现

box-shadow: 0  -1px 1px -1px #e5e5e5,   //上边线
            1px  0  1px -1px #e5e5e5,   //右边线
            0  1px  1px -1px #e5e5e5,   //下边线
            -1px 0  1px -1px #e5e5e5;   //左边线
  • 优点:使用简单,圆角也可以实现

  • 缺点:模拟的实现方法,仔细看谁看不出来这是阴影不是边框。

④:使用伪元素

1 条border

.setOnePx{
  position: relative;
  &::after{
    position: absolute;
    content: '';
    background-color: #e5e5e5;
    display: block;
    width: 100%;
    height: 1px; /*no*/
    transform: scale(1, 0.5);
    top: 0;
    left: 0;
  }
}
  • 可以看到,将伪元素设置绝对定位,并且和父元素的左上角对齐,将width 设置100%,height设置为1px,然后进行在Y方向缩小0.5倍

    4 条border

    .setBorderAll{
         position: relative;
           &:after{
               content:" ";
               position:absolute;
               top: 0;
               left: 0;
               width: 200%;
               height: 200%;
               transform: scale(0.5);
               transform-origin: left top;
               box-sizing: border-box;
               border: 1px solid #E5E5E5;
               border-radius: 4px;
          }
        }
    复制代码
    

    同样为伪元素设置绝对定位,并且和父元素左上角对其。将伪元素的长和宽先放大2倍,然后再设置一个边框,以左上角为中心,缩放到原来的0.5倍 

  • 总结:

  • 优点:全机型兼容,实现了真正的1px,而且可以圆角。

  • 缺点:暂用了after 伪元素,可能影响清除浮动。

69.构造函数与普通函数的区别

1.构造函数其实也是一个普通函数,通常构造函数的首字母大写

2.调用方式不一样,普通函数直接方法名加小括号的形式来调用,构造函数通常要用new关键字来调用

3.作用不一样,构造函数用来新建实例对象

4.内部用this来构建属性和方法

5.普通函数没有返回值,所以值为undefined,构造函数会马上创建一个新的对象,并将该对象作为返回值返回

70.v-if跟v-show为什么不能一起使用

原因:v-for比v-if优先级高,所以使用的话,每次v-for都会执行v-if,造成不必要的计算,影响性能,尤其是当之需要渲染很小一部分的时候。

71.vue3新特性

1.Vue3中设计了一套强大的组合API代替了Vue2中的optiom API,复用性更强了

2.更好的支持TS

3.Vue3中使用了Proxy配合Reflect代替了Vue2中Object.defineProperty()方法实现数据的响应式(数据代理)

4.重写了虚拟DOM,速度更快了

5.新的组件:Fragment(片段)/Teleport(瞬移)/Suspense(不确定)

6.设计了一个新的脚手架工具,vite

72.箭头函数中的this是不能通过call(),apply(),bind()方法来改变的

73.vue中的data为什么是一个函数而不是一个对象

多个组件复用时,每次调用data函数的时候都会return一个新的对象,它们的内存地址都是不一样的,这样就不会相互影响

74.vue中怎样监视一个对象中的属性

加上deep:true属性

75.query传参跟params传参的区别

params只能通过name传参二query既可以通过name同样可以通过path

76.this.$nextTick的作用

作用:在下一次DOM更新结束后执行其指定的回调

什么时候用:当数据改变后,要基于更新后的DOM进行某些操作时,要在nextTick所指定的回调函数中执行

77.hash跟history的区别

最直观的表现一个有#一个没有#

hash模式的兼容性更好history的兼容性更差

history需要后端配合

hash模式#后面的内容称为hash值

hash值不会包含在http请求中 即hash值不会带给服务器

解决方法:需要后端配合

在node.js中可以使用connect-history-api-fallback

78.数组中常用的方法

map():经常用来遍历数据 ,返回一个新的数组,由原数组中的每个元素调用一个指定方法后的返回值组成的新数组

from():将一个伪数组转化成一个真数组

find():返回数组中的第一个符合条件的元素

includes():判断一个数组中是否包含某个元素,包含了的话就返回true,否则返回false

79.for...in与for...of的区别

for...in与for...of都可以用来遍历数组对象  但是for...of不能用来遍历对象因为for...of不能用来遍历对象  因为对象没有iterbale接口

for...in遍历的是key for...of遍历的是值

79.什么是MVVM

M:模型(Model):对应data中的数据

V:视图(View):模板

VM:视图模型(ViewModel):Vue实例对象

80.keep-alive的作用

keep-alive:``主要用于保留组件状态或避免重新渲染。

**

  1. include:字符串或正则表达式。只有匹配的组件会被缓存。
  2. exclude:字符串或正则表达式。任何匹配的组件都不会被缓存。

**

81.Vue3修改rective整个对象

Object.assign(car,{brand:'奥拓',price: 1})

82.ref的作用

给节点打标识

83.Hooks的作用

84.Vue2跟Vue3的区别

一. 根节点不同

  1. vue2中必须要有根标签
  2. vue3中可以没有根标签,会默认将多个根标签包裹在一个fragement虚拟标签中,有利于减少内存。

二. 组合式API和选项式API

  1. 在vue2中采用选项式API,将数据和函数集中起来处理,将功能点切割了当逻辑复杂的时候不利于代码阅读。
  2. 在vue3中采用组合式API,将同一个功能的代码集中起来处理,使得代码更加有序,有利于代码的书写和维护。

三. 生命周期的变化

  1. 创建前:beforeCreate -> 使用setup()
  2. 创建后:created -> 使用setup()
  3. 挂载前:beforeMount -> onBeforeMount
  4. 挂载后:mounted -> onMounted
  5. 更新前:beforeUpdate -> onBeforeUpdate
  6. 更新后:updated -> onUpdated
  7. 销毁前:beforeDestroy -> onBeforeUnmount
  8. 销毁后:destroyed -> onUnmounted
  9. 异常捕获:errorCaptured -> onErrorCaptured
  10. 被激活:onActivated 被包含在<keep-alive>中的组件,会多出两个生命周期钩子函数。被激活时执行。
  11. 切换:onDeactivated 比如从 A 组件,切换到 B 组件,A 组件消失时执行

四. v-if和v-for的优先级

  1. 在vue2中v-for的优先级高于v-if,可以放在一起使用,但是不建议这么做,会带来性能上的浪费
  2. 在vue3中v-if的优先级高于v-for,一起使用会报错。可以通过在外部添加一个标签,将v-for移到外层

五. diff算法不同

  1. vue2中的diff算法

    • 遍历每一个虚拟节点,进行虚拟节点对比,并返回一个patch对象,用来存储两个节点不同的地方。
    • 用patch记录的消息去更新dom
    • 缺点:比较每一个节点,而对于一些不参与更新的元素,进行比较是有点消耗性能的。
    • 特点:特别要提一下Vue的patch是即时的,并不是打包所有修改最后一起操作DOM,也就是在vue中边记录变更新。(React则是将更新放入队列后集中处理)。
  2. vue3中的diff算法

    • 在初始化的时候会给每一个虚拟节点添加一个patchFlags,是一种优化的标识。
    • 只会比较patchFlags发生变化的节点,进行识图更新。而对于patchFlags没有变化的元素作静态标记,在渲染的时候直接复用。

六. 响应式原理不同

  1. vue2通过Object.definedProperty()的get()和set()来做数据劫持、结合和发布订阅者模式来实现,Object.definedProperty()会遍历每一个属性。
  2. vue3通过proxy代理的方式实现。
  3. proxy的优势:不需要像Object.definedProperty()的那样遍历每一个属性,有一定的性能提升proxy可以理解为在目标对象之前架设一层“拦截”,外界对该对象的访问都必须通过这一层拦截。这个拦截可以对外界的访问进行过滤和改写。
  4. 当属性过多的时候利用Object.definedProperty()要通过遍历的方式监听每一个属性。利用proxy则不需要遍历,会自动监听所有属性,有利于性能的提升

85.Vue2跟Vue3中变量的关系

Vue2中可以读取到Vue3中setup中定义的值,Vue3中的setup执行的时间比Vue2中的data还要早,所以Vue3中的setup中读不到Vue2中的值

86.ref与reactive

reactive只能定义对象类型的数据

ref可以定义对象类型的数据也可以定义基本数据类型的数据

87.在Vue3中接一个对象

Object.assign()

88.toRef与toRefs

toRef与toRefs将reactive定义的对象解构出来并且具备响应式

React是什么?

用于构建用户界面的JavaScript库

React的特点?
1.采用组件化模式、声明式编码,提高开发效率及组件复用率

2.在React Native中可以使用React语法进行移动端开发

3.使用虚拟DOM+优秀的diffing算法,尽量减少与真实DOM的交互 

89.js基本数据类型

undefined  null string number boolean symbol bigint

90.ts基本数据类型

  1. Boolean

    :布尔类型,值为truefalse,用于逻辑判断。示例:let isDone: boolean = false;。‌

  2. Number

    :数字类型,包含整数、浮点数及特殊值(InfinityNaN)。支持二进制、八进制等进制表示。示例:let hex: number = 0xf00d;。‌

  3. String

    :字符串类型,支持单引号、双引号和模板字符串。示例:let color: string = 'blue';。‌

  4. Array

    :数组类型,可通过类型或泛型Array<类型>定义。示例:let list: number = ;。‌

  5. Tuple

    :元组类型,固定长度和类型的数组。示例:let x: [string, number] = ['hello', 10];。‌12

  6. Enum

    :枚举类型,为一组数值赋予友好名称。示例:enum Color {Red, Green}; let c: Color = Color.Green;。‌

  7. Any

    :任意类型,绕过类型检查。示例:let notSure: any = 4;。‌

  8. Void

    :表示无返回值,常用于函数。示例:function warn(): void { console.log(); }。‌

  9. Null/Undefined

    :分别表示空值和未定义。默认情况下是其他类型的子类型。‌

  10. Never

:表示永不存在的值,如抛出错误的函数。示例:`function error(): never { throw new Error(); }`。
  1. Object
:非原始类型,表示对象。示例:`let obj: object = { name: 'Alice' };`。
  1. Symbol
(ES6)和
‌**BigInt**‌

(ES10):唯一标识符和大整数类型,需注意环境兼容性。‌