1、js的数据类型
js 的数据类型分为两类,基本数据类型有Number、String、Boolean、null、undefined,复杂数据类型有Function、Object、Array
2、如何判断数据类型
判断数据类型有四种方法,typeof可以判断字符串、函数、Symbol;instanceof可以判断日期;Array.isArray可以判断数组;Object.prototype.toString.call可以判断其他类型;
3、js中的继承
JS 中的继承有七种方法,第一种原型链继承,也就是通过原型继承另一个引用类型的属性和方法;第二种是借用构造函数继承,主要是使用 apply() 和 call() 方法;第三种是组合继承,也就是第一种原型与第二种借用构造函数的结合;第四种是原型式继承,借助原型可以基于已有的对象创建新对象;第五种是寄生式继承,创建一个仅用于封装继承过程的函数,该函数在内部以某种方式来增强对象。寄生式继承是原型式继承的加强版;第六种是寄生组合式继承,通过借用函数来继承属性,通过原型链的混成形式来继承法方法;第七种是ES6 中的方法,使用 class 类继承,通过 extends 和 super 实现;
4、原型链
当访问一个对象的某个属性时,会先在这个对象本身属性上查找,如果没有找到,则会去它的构造函数的 prototype 上查找,如果还没有找到,就会再去构造函数的 prototype 的 __proto 中查找。这样一层一层往上查找,就会形成原型链。
5、闭包
一个作用域可以访问另一个函数内部的局部变量,或者一个函数访问另一个函数中的变量,就会形成闭包。闭包的优点是延伸了变量的作用范围;但是由于闭包会使得函数中的变量都被保存在内存中,内存消耗很大,会导致内存泄漏,用完后需要手动释放。
6、如何判断this的指向
一般在开发中,发现 this 指向不对时,会打断点进行调试。但也有一些规则可循。
- 以函数形式调用,this 指向 window,严格模式下指向 undeifned;
- 以方法的形式调用,谁调用,this 就指向谁;
- 构造函数中,this 指向实例;
- 使用 call ,apply ,bind 方法,指定谁,this 就指向谁;
- 箭头函数没有自己的 this,指向的是外层函数的 this ,如果没有,就指向 window;
7、call apply bind的使用
它们的共同点:都是用来改变函数 this 指向的,第一个参数都是 this 要指向的对象
- call 方法主要用于继承;
- apply 接受的是一个参数数组,主要给数组添加方法;
- bind 方法不会调用函数,会返回改变 this 指向之后的新函数,要赋值调用;
8、数组常用api4
- join(),用特殊字符连接数组,组成字符串;
- pop(),删除最后一个元素,并返回删除的元素;
- shift(),删除第一个元素,并返回删除的元素;
- push(),在末尾添加元素,返回新数组的长度;
- unshift(),在开头添加元素,返回新数组的长度;
- find(),查找数组中是否有满足条件的元素,有则返回满足条件的第一个元素的值;
- includes(),判断数组是否包含某个值,返回布尔值;
- findindex(),返回满足条件的第一个元素的索引;
- indexof(),返回满足条件的第一个元素的索引;
- splice(),添加或删除数组中的元素,返回被修改的内容;
- concat(),合并数组,返回合并后的数组;
- sort(),对数组进行排序,返回从小到大排序后的数组;
- reverse(),翻转数组;
- forEach(),遍历数组,无返回值;
- some(),判断数组中是否有满足条件的元素,有一个满足就返回 true,返回布尔值;
- every(),判断数组中是否有满足条件的元素,全部满足返回 true;
- filter(),将满足条件的元素过滤出来,形成新数组,返回新数组;
- map(),对数组的每一项进行操作,返回操作后的新数组;
9、reduce的使用格式
reduce 是数组的方法,可以进行累加的操作,第一个参数是总和 sum,第二个参数是数组的每一项 item,第三个参数是要进行操作的函数,第四个参数是初始值(一般是数字,不写默认是0,相当于从这个值开始进行操作),最后返回结果。
10、什么是回调地狱,如何解决
大量嵌套异步 JS 或者使用回调函数,导致代码很难直观地理解和调试,就会形成回调地狱。 可以改用 Promise 或者 async、await 解决,因为 Promise 可以把嵌套的解构改成串联的结构。
11、promise的使用
Promise 是异步编程的一种解决方案,比传统的解决方案(回调函数和事件)更合理和强大。
基本语法:通过 new Promise 同时传入一个固定格式的函数,得到一个 Promise 对象。固定格式的函数有两个参数,resolve,异步操作成功;reject,异步操作失败。
一般会使用 Promise 来改写一些需要回调的处理的异步操作,例如原生 ajax。还可以利用 Promise.then 是微任务的特点模拟一些异步操作。
12、new的背后做哪些事情
new 一个实例时,主要做了四件事,
- 创建一个空对象,并且 this 变量引入该对象,同时还继承了函数的原型;
- 设置原型链,空对象指向构造函数的原型对象;
- 执行函数体,修改构造函数 this 指针指向空对象,并执行函数体;
- 判断返回值,返回对象就用该对象,没有的话就创建一个对象
13、防抖和节流
本质:用来对函数的调用做降频(降低单位时间内被调用的次数)处理。性能优化
防抖:连续高频调用函数,函数只执行最后一次。
节流:连续高频调用函数,函数在指定时间内执行一次。
14、高阶函数
高阶函数:接收函数作为实参或将函数作为返回值。
实参是函数的:map、reduce、setTimeout
返回值是函数的:节流、防抖
15、函数柯里化
函数柯里化:把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
把事情搞复杂了,但是让函数更灵活了。
16、for in和for of的区别
相同点:都可以遍历元素
区别:
- for in 用来遍历 key,可以用在对象、字符串、数组中使用。推荐循环对象属性;
- for of 是 ES6 的新语法,遍历的是 value,可以用在数组上;
- 普通对象不能使用 for of,需要搭配 Object.keys() 使用;
17、递归及应用场景
递归:如果在一个函数内部可以调用其本身,那么这个函数就是递归函数。函数内部自己调用自己。
优点:结构清晰、可读性强
缺点:效率低。每一次函数的调用都会在内存栈中分配空间,而每个进程的栈容量都是有限的,当调用的层次太多时,就会导致栈溢出。
18、eventloop事件循环
JS 中把事件分为两类,宏任务与微任务,而任务又分为同步任务与异步任务。JS 在执行事件时,事件循环先执行宏任务,其中同步任务立即执行,异步任务会被放入特定的处理程序中,满足执行条件后,被放到事件队列中,微任务也加载到对应的微任务的事件队列中,所有的同步任务执行完毕之后,如果发现微任务的事件队列中还有未执行的任务,先执行他们,这样算是完成了一轮事件循环。
19、深拷贝和浅拷贝
浅拷贝的时候会创建一个新对象,如果属性是基本数据类型,拷贝的就是值,如果属性是复杂数据类型,拷贝的就是内存地址。新对象拷贝的是旧对象的地址, 如果修改其中一个,另一个的值就会发生改变。
深拷贝的时候会拷贝所有属性,并拷贝属性指向的动态分配的内存,深拷贝会拷贝多层,每一级的数据都会拷贝。新旧对象的内容虽然相同,但是是两个独立的地址,修改其中一个,另一个不会受影响。
深拷贝相比于浅拷贝,速度较慢,并且花销较大。
20、垃圾回收机制
JS 具有自动垃圾回收机制,执行环境会负责管理代码执行过程中使用的内存,开发人员不用再关心内存使用问题。
当我们在声明变量、函数、对象,并执行时,系统会自动进行内存分配;在读写内存,也就是使用变量、函数时,会使用内存;使用完毕之后,垃圾回收机制会进行内存回收,自动回收不再使用的内存。
垃圾回收机制有两种方法,标记清除算法和引用计数算法。
标记清除算法是最常用的, 当变量进入执行环境时,垃圾回收器将其标记为“进入环境”,当变量离开环境时,将其标记为“离开环境”。垃圾回收器在运行时会给内存中的所有变量加上标记,然后去掉环境中的变量以及被环境变量所引用的变量,其它仍然存在标记的变量就会被删除。
引入计数算法是最初级的,只在低版本IE 中会出现。当声明一个变量并将一个引用类型赋值给该变量时,这个值的引用次数就加1,当该变量的值改变时,引用次数就会减1。当引用次数变为0时,垃圾回收器就会在运行时清理掉这些变量。
21、await async的使用方式
async await相当于是 Promise 的语法糖,async 用于声明一个异步的函数,会返回一个 promise 对象。await 是 async wait 的缩写,只能出现在异步函数中,后面跟随的是一个 promise 对象,返回的是 promise 对象中的 then() 中的回调函数中的参数 res 。可以使用 try...catch 处理异步中的异常。
22、https和http的区别
HTTP 是互联网上应用最为广泛的一种网络协议,是一个客户端和服务器请求和应答的标准,用于从 WWW 服务器传输超文本到本地浏览器的传输协议,可以使浏览器更加高效,使网络传输减少。但 HTTP 协议传输的数据都是未加密的,传输隐私信息时非常不安全,很容易被截取。而 HTTPS 是以安全为目标的 HTTP 通道,简单讲是 HTTP 的安全版,加入了 SSL(Secure Sockets Layer)协议用于对 HTTP 协议传输的数据进行保密。HTTPS 的作用主要分为:建立一个信息安全通道,来保证数据传输的安全;确认网站的真实性。
23、常见http的状态码
100 :正在初始化;
101 :正在切换协议;
200 :请求已成功;
301 :永久重定向;
302 :临时重定向;
400 :请求参数错误;
401 :由于 token 过期需要认证;
403 :没有权限,服务器禁止访问;
404 :请求失败;
405 :请求方式错误;
500 :请求参数错误,或者是后端错误;
503 :服务器超负荷;
505 :服务器不支持请求的 http 协议的版本
24、js延迟加载的方式
JS 延迟加载有六种方法。
- 给 script 标签添加 defer 属性,告诉浏览器立即下载,但延迟执行;defer 属性只适用于外部脚本文件;
- 给 script 标签添加 async 属性,不让页面等待脚本下载和执行,从而异步加载页面其他内容,只适用于外部脚本文件,与 defer 类似;不能空控制加载的顺序;
- 动态创建 DOM 方式,将创建 DOM 的 script 脚本放置在标签前,接近页面底部;
- 使用 jQuery 的 getScript()方法;
- 使用 setTimeout 延迟方法,延迟加载 js 代码,给网页加载留出更多的时间;
- 把 js 外部引入的文件放到页面底部,来让 js 最后引入,从而加快页面加载速度
25、如何减少重绘和回流
重绘:当元素的一部分属性发生改变,但并没有引起布局变化,只需要浏览器根据元素的新属性重新绘制,使元素呈现新的外观
回流(重排):当 render 树中的一部分或者全部因为大小边距等问题发生改变而需要 DOM 树重新计算
重绘不一定引起回流,但回流一定引起重绘
减少回流、重绘就是减少对 DOM 的操作,方法:
- 对元素进行复杂操作时,可以先 display:none 隐藏,操作完后再显示;
- 需要创建多个 DOM 节点时,使用 DocumentFragment 创建完后一次性的加入 document;
- 尽量避免使用 table 布局,table 元素一旦触发回流,table 里的其他元素都会回流;
- 避免使用 css 表达式,因为每次调用都会重新计算值;
- 尽量使用 css 属性简写,比如 border 、padding、font;
- 批量修改元素样式,使用 className 和 style.cssTxt 代替 style
26、描述输入url地址到网页展示的过程
- 浏览器查找域名对应的 IP 地址(DNS 查询:浏览器缓存 -> 系统缓存 -> 路由器缓存 -> ISP DNS缓存 -> 根域名服务器);
- 浏览器向 Web 服务器发送一个 HTTP 请求(TCP 三次握手);
- 服务器 301 重定向(从 example.com 重定向到 www.example.com);
- 浏览器跟踪重定向地址,请求另一个带 www 的网址;
- 服务器处理请求(通过路由读取资源);
- 服务器返回一个 HTTP 响应;
- 浏览器进入 DOM 树构建;
- 浏览器发送请求获取嵌在 HTML 中的资源;
- 浏览器显示完成页面;
- 浏览器发送异步请求
27、跨域问题及解决方案
跨域:浏览器不能执行其他网站的脚本,它是由浏览器的同源策略造成的,是浏览器对 javascript 施加的安全限制,防止他人恶意攻击网站。
常见解决方案有四种:
- jsonp。动态创建一个 script 标签,利用 script 标签的 src 属性不受同源策略的限制。因为所有的 src 属性和 href 属性都不受同源策略的限制,可以请求第三方服务器数据内容;
- CORS:跨域资源共享。服务器设置 Access-Control-Allow-OriginHTTP 响应头之后,浏览器将会允许跨域请求。使用此方法需要浏览器支持 HTML5;
- 反向代理;
- window + iframe
28、本地持久化的方式和区别
主要有 localStorage、sessionStorage、cookie 三种方式,都是保存在浏览器端、且同源的。
主要区别分为四部分:
-
与服务器交互上:
- localStorage、sessionStorage 不会自动把数据发给服务器,仅在本地保存
- cookie 是网站为了表示用户身份而存储在用户本地终端上的数据(通常经过加密),始终会在同源 http 请求头中携带(即使不需要),在浏览器和服务器间来回传递
-
存储大小:
- cookie 存储数据根据不同浏览器限制,大小一般不能超过4k
- sessionStorage 存储数据约5M,localStorage 存储数据约20M
-
有期时间:
- localStorage 存储持久数据,生命周期永久生效,浏览器关闭后数据不丢失,除非手动删除数据
- sessionStorage 存储的数据,生命周期为关闭浏览器窗口,关闭后自动删除
- cookie 存储数据,根据设置的 cookie 过期时间决定,在设置的时间内一直有效,与浏览器是否关闭无关
-
作用域:
- sessionStorage 不在不同的浏览窗口中共享,即使是同一个页面
- localStorage、cookie 在所有同源窗口中都是共享的
29、get请求和post请求的区别
get 和 post 都是基于 http 协议进行请求的,get 是获取数据,post 是传递数据。get 使用 url 或 cookie 传参,而 post 将数据放在 body 中;get 的 URL 会在长度上有限制,post 的数据则可以非常大;post 比 get 更安全,因为数据在地址栏不可见。
30、http的协议的三个内容
请求行、请求体、请求头
31、请求头中的contentType有什么用处
请求头中的 contentType 用于向接收方说明传输资源的媒体类型。在浏览器中,浏览器会根据 contentType 判断响应体的资源类型,然后根据不同文件类型做出不同的展示。
32、事件冒泡和事件捕获
事件冒泡和事件捕获都是 DOM 事件模型。
事件捕获是由根 -> 目标的祖元素 -> 目标的父元素 -> 目标元素,由外到内触发,而事件冒泡正好相反,是从内到外依次触发的。
33、事件委托
事件委托是 JavaScript 的一种简单的技巧,把事件处理器添加到父节点上,通过事件冒泡影响每一个子节点,这样就避免了在多个子节点上添加事件。可以减少事件注册,节省内存。
缺点是对于不冒泡的事件不支持,当层级过多时,可能会被某层阻止掉。
34、如何添加和删除事件
添加事件:addEventLis,删除事件:removeEventListener
35、单个组件的生命周期钩子
-
初始化阶段
- beforeCreate,钩子函数被执行,此时无法访问 data 中的数据
- created,实例创建,可以访问 data 中的数据,不能获取真实DOM。常用,发送 AJAX 请求
-
挂载阶段
- beforeMount,挂载前执行,此时还是虚拟 DOM ,不能获取真实DOM
- mounted,在此之前真实 DOM 挂载完毕,获取的是真实 DOM。常用,操作真实 DOM
-
更新阶段
- beforeUpdate,虚拟 DOM 重新渲染,打补丁到真实 DOM,此时只有虚拟 DOM 中的数据更新了,真实 DOM 未更新
- updated,真实 DOM 挂载完毕,真实 DOM 中的数据已更新
-
销毁阶段
- beforeDestroy,实例被销毁前,一般使用这个,可以手动消除计时器、定时器、全局事件
- destroyed,实例被销毁后
36、hash路由和history路由的区别
hash 路由在地址栏显示 # 号,是默认值。history 路由无 # ,需要后端配合
37、hash路由和history路由的原理
hash 模式是一种把前端路由的路径用 # 号拼接在真实 URL 后面的模式,当 # 号后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发 haschange 事件,浏览器的进后退也能对其进行控制。
history 模式利用 HTML5 新增的 pushState() 和 replaceState() 两个 api,完成 URL 跳转不会重新加载页面。history 模式不仅可以在 URL 里传参,也可以将数据存放到一个特定的对象中。
38、父子组件的生命周期钩子
父组件 beforeCreate -> 父组件 create -> 子组件 beforeCreate -> 子组件 created -> 子组件 mounted -> 父组件 mounted
39、组件之间传参方式
父传子:在父组件中使用子组件,通过属性传递数据;子组件中定义 props 接收数据;
子传父:在父组件中给子组件绑定自定义事件;在子组件适当的时机,通过 this.$emit('') 调用自定义事件;
兄弟组件:在其中一个组件中,通过 on 进行数据接收
40、v-model和.sync的对比
v-model 语法糖是绑定 value 属性,监听 input 事件,完成双向绑定;
.sync 修饰符默认以 update:prop 模式触发事件;
一个组件中只能有一个 v-model ,但是可以有多个 .sync
41、vue路由钩子beforeEach的参数
boforeEach 是全局前置路由守卫,可以在路由跳转之前,进行拦截,一共有三个参数。
to:到哪里去;
from:从哪里来;
next:可不可以去。直接调用不传参表示允许跳转,调用时传入 false 表示不可跳转。next 如果不调用,所有路由导航全部失效,一定要调用 next 函数。
42、vuex的基本使用步骤
- 下载 vuex 依赖包
- 在 main.js 中导入 Vuex 模块
- Vue.use(Vuex)
- 创建 store 实例对象,const store = new Vuex.Store({ })
- 挂载到 Vue 身上,new Vue({ store })
43、vuex的getter的作用
Getter:本质是js函数,是 Vuex中的计算属性。State 数据源发生变化,getter 返回值自动更新
44、mutation和action的使用区别
mutation 和 action 都是函数。
mutation 专门用来修改 state 中的数据,所有数据和修改都必须使用 mutation;
action 专门用来处理 Vuex 中的异步操作
45、computed和watcher的使用区别
computed 计算属性用来监控自己定义的变量,改变量不在 data 里面声明,直接在 computed 里面定义,然后就可以在页面上进行双向数据绑定展示出结果或者用做其他处理。计算属性具有缓存特性。计算属性不能执行异步任务,必须同步执行。
watch 监听器主要用于监听 vue 实例的变化,它监听的变量必须在 data 中声明,可以监听变量或对象,不具有缓存性。
46、vue2中v-model是一个语法糖,那具体是怎么实现的?
v-model 是 :value(事件绑定) 和 @input(事件监听)的语法糖。当 value 绑定的值发生变化时,触发 input 事件并附带一个新的值,将新值覆盖给初始值。这样就可以达到变量与视图互相影响。
47、v-if和v-show的区别
- v-if 是真正的条件渲染,在切换过程中,被切换的对象会被直接从 DOM 上移除和添加,操作的实际上是 DOM 元素的创建或销毁
- v-show 操作元素时,元素一直都被渲染,只是将元素的 css 中的 display 属性设置为 none 或 block
- v-if 有更高的切换开销,v-show 有更高的初始渲染开销。如果需要频繁切换,就使用 v-show;如果运行条件很少改变,就使用 v-if。v-if 和 v-else 一起使用,可以形成 if...else... 语句,操作两个元素的显示与隐藏
48、key的作用
- 没有 key 时,会逐层对比 DOM 元素,尽可能多的复用 DOM 元素,就地复用;
- 当有 key,key 为索引时,会基于 key 来比较新旧虚拟 DOM,还是就地更新;
- 当有 key,key 为 id 时,基于key的来比较新旧虚拟DOM, 只更新有变化的部分;
在循环时,如果没有 key 作为唯一值,在页面上对一条标签进行操作时,就会不知道操作的是哪条数据。绑定 key 之后,标签就会自己的唯一值,这时候操作标签,就会按照对应的 key 值去找标签
49、vue2常用指令有哪些
- :属性名=‘变量名’,给标签属性设置 vue 变量的值;
- @事件名=’函数名‘,给标签绑定事件;
- v-model,数据双向绑定;
- v-html / v-text,设置标签显示的内容;
- v-show / v-if / v-else,控制元素的显示与隐藏;
- v-for,动态循环结构;
- :class=‘{类名:布尔值}’,根据布尔值来动态切换类名;
- :style=‘{css属性名:css属性值}’,设置行内样式;
50、vue2和vue3的区别
-
vue2:提供一个mvvm数据双向绑定的库,专注于ui层面,核心思想是:数据驱动、组件系统
-
对比vue2.0的区别
- 性能更比Vue2.0强
- 打包更科学不在打包没用到的模块
- Composition Api(组合api)
- 更友好的兼容TS
- 自定义渲染API
51、vue2中过滤器是怎么使用的
Vue.js 允许自定义过滤器,可被用于一些常见的文本格式化。过滤器可以用双花括号插值和 v-bind 表达式。过滤器接收两个参数:过滤器 ID 和过滤器函数。过滤器函数以值为参数,返回转换后的值。
52、vue2中如何自定义指令
注册自定义指令分为全局注册和局部注册
- 全局注册。在 main.js 中 ,Vue.directive('指令名‘,{inserted(el){ } })
- 局部注册。在组件中,directives:{指令名:{inserted(el){ } }}
53、vue2中vue.use是怎么用的
- 通过全局方法 Vue.use() 使用插件
- Vue.use 会自动阻止多次注册相同插件
- 需要在调用 new Vue() 启动应用之前完成
- Vue.use() 方法至少传入一个参数,必须是 Object 或 Function。如果是 Object,需要定义一个 install 方法;如果是 Function ,这个函数就会被当作 install 方法。
- 在 Vue.use() 执行时,install 会默认执行,执行时第一个参数就是 Vue,其他参数是 Vue.use() 执行时传入的其他参数
54、vue2中$nextTick
$nextTick 是一个函数,等 DOM 更新后,触发此方法里的函数体执行,返回的是一个 Promise 对象
55、vue2中响应式的原理
Vue是采用数据劫持和发布-订阅者功能来实现的。数据劫持是通过 Object.defineProperty() 来实现的,通过 mvvm 中的数据影响视图,视图影响数据实现。
- 将 observe 的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter 和 getter 。当数据对象发生改变时,就会触发 setter ,就监听到了数据变化。 observe 就是监听者
- compile 解析模板指令,将模板中的变量替换为数据,初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者 watcher。当数据发生变化时,收到通知,更新视图
- watcher 订阅者是 observe 和 compile 之间通信的桥梁。在自身实例化时往属性订阅器里添加自己,自身必须有一个 update()方法,待属性变动 dep.notice() 通知时,调用 update 方法,触发 compile 中绑定的回调
- mvvm 整合三者,搭建起三者的桥梁,最后达到数据影响视图,视图影响数据的响应式效果