前端面试题总结 数据类型 基本类型
string ‘字符串’
number ‘64位双精度浮点型数字’(包含NaN)
boolean ‘布尔’,
undefined ‘没有任何值’
null ‘没有任何对象’
bigint ‘任意精度格式的整数’
symbol ‘标记值’
引用类型
对象’object’(Function也是一个特殊的对象)
类型判断
如何判断一个数据是NaN
用全等判断 x === NaN;
用isNaN(x) 来判断;
null与undefined区别
null 表示一个值被定义了,定义为“空值”;
undefined 表示根本不存在定义;
typeof和istanceof区别?
typeof 会返回一个运算数的基本类型
instanceof 判断一个对象是否是某个构造函数的实例1 2 3 class Person {}const p = new Person ();console .log (p instanceof Person );
如何判断一个对象是对象
Object.prototype.toString.call({}) // “[object Object]”
如何判断一个对象时数组
Object.prototype.toString.call([]) // “[object Array]”
Array.isArray([])
[] instanceof Array // true
Map & Set
概念
Map:主要用于存储和管理键值对数据,适合在需要快速查找、插入和删除键值对的场景中使用.常见应用包括缓存、配置管理和数据关联.
Set:主要用于存储唯一值集合,适合在需要确保元素不重复的场景中使用.常见应用包括去重、集合操作和存在性检查.
用途
Map:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const map = new Map ();map.set ('a' , 1 ); map.set ('b' , 2 ); map.set ('c' , 3 ); console .log (map.get ('a' )); console .log (map.has ('b' )); console .log (map.size ); map.delete ('c' ); for (let [key, value] of map) { console .log (`${key} : ${value} ` ); } map.clear ()
Set:1 2 3 4 5 6 7 8 9 10 11 12 const set = new Set ();set.add (1 ); set.add (2 ); set.add (3 ); set.add (1 ); set.delete (3 ); console .log (set.has (1 )); console .log (set.size ); for (let value of set) { console .log (value); } set.clear ()
数组/字符串 数组操作方法
arr.push() 从后添,返回值为添加完后的数组的长度
arr.pop() 从后删一个,返回值是删除的元素
arr.unshift() 从前添,返回值是添加后数组的长度
arr.shift() 从前删一个,返回值是删除的元素
arr.splice(i,n)从数组中添加/删除/修改值,返回值被改动的值
arr.concat() 连接两个数组 返回值为连接后的新数组
arr.sort() 将数组进行排序,返回值是排好的数组,默认是按照最左边的数字进行排序,不是按照数字大小排序的
arr.reverse() 将数组反转,返回值是反转后的数组
arr.slice(start,end) 切一段从索引值start到end(不包含)的数组,返回值是切出来的数组
arr.join(separator) 把数组的所有元素放入一个字符串,方法内的参数作为分隔符,省略该参数,则使用逗号作为分隔符
arr.forEach(callback) 遍历数组,无return 即使有return,也不会返回任何值,并且会影响原来的数组
arr.map(callback) 映射数组(遍历数组),有return 返回一个新数组
arr.filter(callback) 过滤数组,返回一个满足要求的数组
arr.indxOf() : 返回数组中满足提供的测试函数的第一个元素的下标
arr.lastIndexOf() : 从后往前返回数组中满足提供的测试函数的第一个元素的下标
arr.find() : 返回数组中满足提供的测试函数的第一个元素的值
arr.some() : 测试数组中是否至少有一个元素通过了由提供的函数实现的测试( 一个直则真 )
arr.every() : 测试一个数组内的所有元素是否都能通过指定函数的测试( 全真才真 )
map,forEach和for循环区别:
forEach只是进行简单的数组遍历,无返回值,且break和return语句不能跳出循环,for可以适用于更复杂的循环且效率更高
map代表是映射它有返回值,返回值是一个处理过后的新数组且不改变原数组
字符串操作方法
str.charAt(index) 返回在指定位置的字符
str.concat(stringA,stringB,…,stringZ) 连接两个或多个字符串,返回连接后的字符串
str.indexOf(检索的字符串,开始检索的位置【可省略】)检索字符串返回某个指定的字符串值在字符串中首次出现的位置,如果没有返回+1
str.lastIndexOf(检索的字符串,开始检索的位置【可省略】) 从后向前搜索字符串,返回一个指定的字符串值最后出现的位置,如果没有返+1
str.replace(正则表达式/检索的字符串,替换成的字符串)在字符串中用一些字符替换另一些字符,或替换一个与正则表达式匹配的子串.
str.slice(起始下标【slice独有:可为负数,+1指字符串的最后一个字符】,结尾的下标【可省略,如果省略则代表一直到字符串结尾】) 提取字符串的片断,返回被提取的部分.从start开始到end结束(不包括结尾的下标所代表的值)
str.substr(起始下标,长度【可选】) 返回从起始索引号提取字符串中指定数目的字符.
str.substring(起始下标,结束的下标【可选】) 返回提取字符串中两个指定的索引号之间的字符.
str.split(字符串或正则表达式,从该参数指定的地方分割,多少个【可选】) 把字符串分割为字符串数组.
数组字符串操作题
正则 正则中的特殊字符:
单个字符:
^ :正则开始
$ :正则结束
. :元字符, 表示任意一个字符
\ :表示转义字符 如:.表示.
- :表示其前面紧挨着的字符至少出现 1 次 等价{1,}
* :表示其前面出现的字符至少出现过 0 次 等价{0,}
? :表示其前面出现的字符至少出现过 0 次,至多 1 次 等价{0,1}
| :表示或者
组合字符:
\d :0-9 之间的任意一个数字 \d 只占一个位置
\D :除了\d
\w :数字,字母 ,下划线 0-9 a-z A-Z _
\W :除了\w
\s :空格或者空白等
\S :除了\s
函数 普通函数
回调函数:是一个作为参数传递给另一个函数的函数1 2 3 4 5 6 7 8 9 10 11 12 13 function getData (callBack ){ let status = 404 ; setTimeout (()=> { status = 200 callBack (status) },1000 ) } getData (dealData); function dealData (num ){ console .log ('i get the number:' + num) }
arguments 用法:是 JavaScript 函数内部的一个 类数组对象(array-like object),用于存储所有传入函数的参数。它只可以在 非箭头函数 中使用1 2 3 4 5 6 7 8 9 10 11 function test ( ) { console .log (arguments ); console .log (arguments [0 ]); console .log (arguments [1 ]); console .log (arguments .length ); const args = [...arguments ]; console .log (args); } test (1 , 2 , 3 );
function构造函数 1 2 3 4 5 6 7 function People (name,sex){ this .name = name this .sex = sex } People .prototype .sayName = function ( ){ console .log (this .name ) }
class构造函数(本质仍然是function的语法糖) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Person { constructor (name,sex ){ this .name = name this .sex = sex } sayName ( ){ console .log (this .name ) } } class Superman extends Person { constructor (name,sex,skill ){ super (name,sex) this .skill = skill } useSkill ( ){ console .log (this .skill ) } }
bind()和call()与apply()区别:
call 和 apply 主要用于 改变 this 指向,它们可以让一个对象借用另一个对象的方法。它们的主要区别在于 参数传递的方式不同。
bind 也是改变 this 的方法,但它不会立即执行函数,而是返回一个新的函数:1 2 3 4 5 6 7 8 9 10 11 const person1 = { name : "Alice" };function sayHello (age ) { console .log (`Hello, my name is ${this .name} and I am ${age} years old.` ); } sayHello.call (person1, 25 ); sayHello.apply (person1, [25 ]); const boundFunc = sayHello.bind (person1, 25 );boundFunc ();
浏览器API ajax如何创建和使用
实例化XMLHttpRequest对象:
open()准备发送求:
send()执行发送动作:
onreadystatechange指定回调函数接收来自服务器端的请求,readyState即为回调状态 responseText返回内容
1 2 3 4 5 6 7 8 9 let http = new XMLHttpRequest ();http.open (post,"https://www.baidu.com" ,false ) http.send (); http.onreadystatechange = function ( ){ if (http.status === 200 && http.readyState === 4 ) { console .log (http.responseText ); } }
本地存储与Cookie的区别
Cookie:它有4kb的大小限制,数据的生命周期比较灵活,不设置失效时间默认关闭浏览器后失效,原生Cokkie接口不好需要二次封装,可以通过它设置记住密码功能,存储的内容会保留在HTTP请求的Header中,并且会随每次请求发送到浏览器
本地储存:是HTML5新增技术,有localStorage和sessionStorage两种,他们可存储的大小为5mb,localStorage的生命周期是永久存储,sessionStorage的生命周期是当页面关闭后销毁
Json如何新增/删除键值对
新增:
使用数组下标形式添加 Object[“属性名”] =’xxx’;
使用对象参数的形式添加 Object.属性名 = ‘xxx’;
删除:
使用delete删除 delete Object.属性名
ES6新特性
const和let
Let与var与const的区别
var声明的变量会挂载在window上,而let和const声明的变量不会
var声明变量存在变量提升,let和const不存在变量提升
let和const声明形成块级作用域
同一作用域下let和const不能声明同名变量,而var可以
let 有暂存死区
模板字符串
箭头函数
函数的参数默认值
对象和数组解构
for…of 和 for…in
ES6中的类
Promise对象
async函数
核心概念 闭包
概念: 写一段自调用函数,函数体内声明变量后return出一个方法,在方法内引用数据并处理,之后随着函数的调用结束定义的数据不会被而释放,第一次调用后的值被保存了下来,所以形成了”闭包”.
原因:因为当声明一段函数时,它的作用域和变量就已经在内存中被声明了,因为js的垃圾处理机制是被引用的堆内存不会被释放.所以当变量被函数内部引用,函数执行完毕后作用域被销毁,但被引用的值不会被销毁,所以这些变量在闭包执行期间是永久性存在的
特性:
函数内变量以私有成员的存在,避免了全局变量的污染
函数内部可以引用外部的参数和变量
这些变量的值始终保持在内存中,不会在外层函数调用后被自动清除
参数和变量不会被垃圾回收机制回收
影响:
用途:
保存状态:1 2 3 4 5 6 7 8 9 10 const countNum = (() => { let a = 0 ; return () => { a += 1 ; return a } })() countNum (); countNum ();
模块化:1 2 3 4 5 6 7 8 9 10 11 12 13 export default moduleA = (()=> { let data = "this is my data" ; return { getData :()=> { return data } } })() import moduleA from moduleA.js const data = moduleA.getData () + "deal" ;...
什么是内存泄露?
内存因为某些原因没有被垃圾回收装置回收成为常驻内存,造成系统内存的浪费,可能会导致程序运行速度减慢甚至崩溃
原型/原型链/继承
概念:
原型: 在JS中每个构造函数有一个原型对象,构造函数可以通过prototype去访问原型对象,而原型对象有一个constructor指回构造函数,构造函数可以生成一个实例,生成的实例有一个__proto__属性指向原型对象.
原型链:当访问JS中一个实例的方法和属性时,首先会查找自身;如果并未查找到,那么就会寻找实例的原型对象中是否存在,如果仍不存在,就会访问原型对象的原型对象.这个搜索链条就叫原型链1 2 3 4 5 function People (name,sex ){ this .name = name this .sex = sex } People .prototype
用途:
用于继承1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function Animal (){ this .step = 0 this .category = "animal" } Animal .prototype .run = function ( ){ this .step += 1 ; } function Dog (name ){ Animal .call (this ); this .name = name } Dog .prototype = Object .create (Animal .prototype )Dog .prototype .construtor = Dog ;Dog .prototype .say = function ( ){ console .log ("woof" ) } const xiaobai = new Dog ("xiaobai" )
继承:是面向对象编程中的一个重要概念,通过继承可以使子类的实例使用在父类中定义的属性和方法.[每当代码读取某个对象的某个属性时,都会执行一次搜索,目标是具有给定名字的属性.搜索首先从对象实例本身开始.如果在实例中找到了具有给定名字的属性,则返回该属性的值;如果没有找到,则继续搜索_proto_指针指向的原型对象,在原型对象中查找具有给定名字的属性.如果在原型对象中找到了这个属性,则返回该属性的值.]
同步与异步的区别/阻塞与非阻塞区别
(https://blog.csdn.net/qq_22855325/article/details/72958345 )
同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行下一个任务;
异步任务指的是,不进入主线程、而进入”任务队列”,只有等主线程任务执行完毕,”任务队列”才开始通知主线程,请求执行任务,该任务才会进入主线程执行 [javascript是单线程,所有任务需要排队,前一个任务结束,才会执行后一个任务]
阻塞:调用时,如果被调用者状态未就绪,会导致调用线程被挂起.
非阻塞:调用时,如果被调用者就绪则立即返回结果,如果未就绪也会返回一个错误值,告诉调用者当前的状态
请简述async的用法
(https://segmentfault.com/a/1190000007535316 )
async用于申明一个函数是异步的并且它会返回一个Promise对象,函数的返回值就是.then()里的数值 [await只能出现在async函数中,await在等待一个async函数完成,因为 async 函数返回一个 Promise 对象,所以 await 可以用于等待一个 async 函数的返回值——这也可以说是 await 在等 async 函数,但要清楚,它等的实际是一个返回值]
什么是JSONP工作原理是什么?
工作原理: 通过 script 标签绕过同源策略 前端动态生成一个script标签向后端发送get请求,然后准备函数接收数据,并用callback为键将函数名发送给后端,后端接收函数名后将数据作为实参拼接一段执行调用函数的js代码返回给前端,前端接收到执行函数的代码后 script标签 会自动调用声明的函数,函数的形参就是后端返回的数据.1 2 3 4 5 6 7 8 9 dealData ({ name : "Alice" , age : 25 });function dealData (data ){ console .log (data) }
事件委托是什么?如何确定事件源
事件委托就是利用事件冒泡机制,只给一个元素绑定事件,就可以代理管理某一类型的所有事件.这样可以避免绑定一大堆事件,优化性能
事件源通过事件对象的target属性来确定
This指向
在一般函数内或全局作用域下,指向的window对象
在对象的方法中,指向的该对象
在事件处理函数中,指向触发事件的元素(Node节点)
在箭头函数中: 继承上一级的指向位置(无视当前函数)
在构造函数中,指向的是实例化对象.(需要new的对象) 1 2 3 4 5 6 function People (name,age ){ this .sayMyName = alert (name); this .age = age; } let student = new People ("二狗" ,18 );student.sayMyName
在新增原型对象属性中,this指的就是这个原型的主人(实例化的对象)
箭头函数与普通函数的区别
箭头函数都是匿名函数,没有自己this,arguments,原型对象
普通函数和构造函数的区别
写法不同构造函数习惯上首字母大写
调用方式不一样,普通函数可以用 函数名() 的形式直接调用,构造函数需要用new关键字来调用创建实例对象
返回值不一样,普通函数返回值由return决定,构造函数返回值是实例化的对象
什么是面向对象请简述
面向对象的三大特征 继承、封装、多态
继承:通过继承使子类可以使用在父类中定义的属性和方法
封装:就是指把内部的实现封装起来,然后暴露必要的方法让外部调用.
多态:多态指的是同一类事物有多种形态,如文件有:文本文件,可执行文件,视频文件等…
重绘以及回流是什么
重绘(repaint):当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要UI层面的重新像素绘制,因此损耗较少,常见的重绘操作有:改变元素颜色
回流(reflow):当元素的尺寸、结构或者触发某些属性时,浏览器会重新渲染页面,称为回流.此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作.常见的回流操作有:浏览器窗口大小改变,添加或者删除可见的DOM元素
回流必定会触发重绘,重绘不一定会触发回流.重绘的开销较小,回流的代价较高.
事件循环
解释: JS是单线程的语言,为了避免阻塞主线,它引入了事件循环机制来处理异步任务,JS会先执行同步任务,遇到异步任务的时候会交给Web API,当异步任务执行完成的时候,会将回调函数放入 任务队列 Task Queue / Callback Queue 然后 Event Loop 事件循环 负责一直监听任务队列 执行队列中的任务
宏任务微任务:遇到同步任务直接执行,遇到异步任务分类为宏任务(macro-task)和微任务(micro-task).有微则微,无微则宏:
宏任务: 整体代码 定时器 ajax DOM事件
微任务: promise async/await
微任务 > DOM渲染 > 宏任务
深浅拷贝
是什么如何实现?
js有两种类型基本类型和引用类型,基本类型它的名和值会储存在栈内存中,当我们复制它时会开一条新内存再创建一个同样的值,但是引用类型在我们新建的时候它会在栈内存中储存它的名和一个指向它堆内存的地址,当我们复制的时候其实只是复制了它的引用地址并非堆里面的值,如果要深拷贝我们就需要新建一个和它一样的堆内存的值
什么时候用深拷贝/浅拷贝
当我们创建了一个对象并复制,如果我们想修改复制的对象,但却不想让原对象也随之改变的时候使用深拷贝,但是如果我们只是想复制它的基本类型的数据或者指向它的堆内存的指针的时候使用浅拷贝
深拷贝的代码实现
简单深拷贝(一层拷贝) 1 2 3 4 5 6 7 function deepCopy (obj ){ let copyObj = Array .isArray (obj) ? [] : {}; for (let key in obj){ copyObj[key] = obj[key]; } return copyObj; }
复杂深拷贝(递归实现多层拷贝) 1 2 3 4 5 6 7 8 9 function deepCopy (obj ){ let copyObj = Array .isArray (obj) ? [] : {}; for (let key in obj){ if ( obj.hasOwnProperty (key) ){ copyObj[key] = typeof obj[key] === 'object' ? deepCopy (obj[key]) : obj[key] ; } } return copyObj; }
Promise
理解: promise是为解决异步处理回调地狱问题而产生的;它是一个构造函数,可以通过new得到一个Promise的实例对象,Promise里有两个函数分别叫做resolve(成功之后的回调函数)和reject(失败之后的回调函数)在Promise构造函数的Prototype属性上,有一个.then()和.catch()方法,只要是Promise的实例化对象都可以使用
Promise在哪里使用过
在使用ajax,axios等一类的数据请求的时候用过,只要是一些需要解决回调函数问题的都可以用(在函数中return一个promise实例,成功后干嘛失败后干嘛,则该函数就可以使用.then和catch方法)
函数节流和防抖
函数节流:
(https://www.cnblogs.com/fightjianxian/p/12077570.html )
作用: 在 n 秒中只执行一次函数(指定时间间隔内只会执行一次任务)
实现:1 2 3 4 5 6 7 8 9 10 11 12 13 var pass = true ;document .getElementById ("throttle" ).onscroll = function ( ){ if (!pass){ return ; } pass = false ; setTimeout (function ( ){ console .log ("函数节流" ); pass = true ; }, 300 ); };
应用场景: 高频触发的事件,多数在监听页面元素滚动事件
函数防抖:
(https://www.cnblogs.com/fightjianxian/p/12077451.html )
作用: 在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间(任务频繁触发的情况下,只有任务触发的间隔超过指定间隔,任务才会执行)
实现:1 2 3 4 5 6 7 var timer = false ;document .getElementById ("debounce" ).onscroll = function ( ){ clearTimeout (timer); timer = setTimeout (function ( ){ console .log ("函数防抖" ); }, 300 ); };
应用场景:如邮箱验证和手机号验证.只有等用户输入完毕后,前端才需要检查格式是否正确,如果不正确,再弹出提示语
VUE VUE2
Vue的核心是什么
数据驱动和组件化
数据驱动:视图的内容随着数据的改变而改变
组件化:把页面封装成为若干个组件进行拼装,让页面的复用性达到最高
请简述你对vue的理解
一套渐进式的自底向上增量开发的前端MVVM框架
渐进式:可以只使用部分功能,也可以整个用vue开发,不做职责之外的事
自底向上增量开发:先编写出基础页面,再逐步扩大规模,补充和升级某些功能和效果
M代表模型层也是数据层V代表视图层,VM是用来沟通的桥梁,负责监听模型层或者视图层的修改
mvvm框架是什么?
M代表数据层 V代表视图层,VM是用来沟通的桥梁,负责监听模型层或者视图层的修改
区别:vue数据驱动,通过数据来显示视图层而不是节点操作.
场景:数据操作比较多的场景,更加便捷.
MVVM与MVC的区别
MVC中Model和View还有Controller是完全独立的,由Controller作为中间人来负责二者的交互
MVVM中VM是V与M沟通的桥梁,开发者只需关注业务逻辑,不需要手动操作DOM,不需要关注数据状态的同步问题,复杂的数据状态维护完全由MVVM来管理
请简述vue的单向数据流
组件之间一旦传值完毕,接收数据的这个组件无论怎么修改,传递数据的那个组件的数据都不会改变;我们经常会采用父子组件通过正向/逆向传值来对数据进行传递.以上的这些模式非常脆弱,通常会导致无法维护的代码.
Vue常用的修饰符有哪些
事件修饰符:
prevent(阻止事件的默认行为)
stop(阻止事件冒泡)
capture(让事件传递成为捕获)
self(只会触发自己范围内的事件,不包含子元素)
once(只会触发一次)
按键修饰符(按下某个键):up down ctrl enter space
什么是计算属性
它是一种属性,有“计算”这个特殊性质.每次取得它的值得时候,它并不像普通属性那样直接返回结果,而是经过一系列的计算之后再返回结果.
计算属性与watch区别
计算属性是依赖于缓存的,当依赖的值发生改变才会触发.而watch是当watch监听的值发生改变就会被调用相应方法
计算属性适合在数据展示时做一些处理
Vue如何定义一个过滤器
`全局过滤器使用Vue.filter(‘过滤器名字’,function(val){return 返回的内容})在app.vue中
局部过滤器使用filters(‘’,function(val){})在data同级
通过 { { 要过滤的数据|过滤器名 } }来调用
Vue循环的key作用
key的作用主要是为了高效的更新虚拟DOM,是遍历数组或元素中的唯一标识,增加或删减元素时,通过key判断是否是之前的元素,如果是则直接会复用该标签,不会将所有标签重新删除和创建,只会重新渲染数据,然后再创建新的元素直到数据渲染完为止
v-for与v-if优先级
v-for比v-if具有更高的优先级,但是不能把v-if与v-for用在同一个元素上,因为如果两者同时出现的话,那每次循环都会执行v-if,会很浪费性能
Vue单页面的优缺点
优点:用户体验好,速度快,内容的改变不需要再加载整个页面,前后端分离,组件化便于修改和调整
缺点:初次加载耗时高,页面复杂度提高,导航需要自行实现前进后退,不利于seo搜索引擎优化
Vue的生命周期请简述
beforeCreate:创建vue实例前
created:创建实例完成后,开始监听data对象数据变化情况,初始化VUE内部事件
beforeMount:编译模板,把data里面的数据和模板生成html
mounted:用编译好的html替换掉el属性所指向的DOM对象
beforeUpate:数据更新前
updated:数据更新后
beforedestroy:销毁实例前
destroyed:销毁所有事件监听器和子实例,完成销毁vue实例
Vue生命周期的作用:
DOM渲染在那个生命周期阶段内完成
Vue中路由跳转方式(声明式/编程式)
声明式:
编程式: this.$router.push(“/路由名”)
跨域的解决方式
在vue.config.js中进行proxy配置
在后台用cors跨域
Vue路由的实现
通过hash和history两种模式来实现,它们分别基于location和history对象
Vue路由模式hash和history,简单讲一下
hash模式:基于location对象,地址栏会出现#(hash)符,只有#前的内容会被包含在请求中,前端路由修改的是#后的信息,所以刷新是不会向服务端请求添加#后面的参数,所以刷新不会出问题
history模式:基于History对象,前端的URL必须和实际向后端发起请求的URL一致,不然会出现404错误(比如刷新的时候),需要后端配置一下apache或是nginx的url重定向,重定向到我的首页路由上.
Vue路由懒加载(按需加载路由)
因为vue的路由技术是为了完成单页面应用的,在第一次页面初始化的时候路由会把所有的路由页面都渲染好可能会造成用户的页面白屏相应慢: component:()=>import(‘路由组件路径’)
Route与router区别
route对象表示当前的路由信息,是一个局部对象,包含了当前URL解析得到的信息.包含当前的路径,参数,query对象等.
router对象是全局路由的实例,他包含所有的路由拥有的对应的对象,属性和方法.比如history对象
Vue路由传参的两种方式,prams和query方式与区别
params:需要在路由规则中绑定接收的参数名,通过路由规则的name值来绑定发送的参数,传递的参数不会暴露在地址栏相对安全
query:不需要在路由规则中绑定参数名,通过路由规则的path路径来绑定发送的参数,传递的参数会暴露在地址栏不安全
Vue数据绑定的几种方式
普通文本绑定v-text
解释HTML标签的绑定v-html
数据特殊属性v-bind
双向绑定 v-model
Vue注册一个全局组件
在main.js通过import引入封装的组件
使用vue.component(“设置使用时的组件名”,引入的组件)
Vue的路由钩子函数/路由守卫有哪些
全局钩子:
路由前置:router.beforeEach((to,from,next)=>{})
路由后置:router.afterEach((to,from,next)=>{})
路由独享钩子:在路由规则中写入 只有前置beforeEnter:(to,from,next)=>{}
组件内钩子:beforeRouteEnter(to,from,next){} beforeRouteLeave(to,from,next){}
Vue中如何进行动态路由设置?有哪些方式?怎么获取传递过来的数据?
前端列表页点击之后通过params或query的声明式( )或编程式发送参数(this.$router.push(name/路径,params/query:{}))如果使用params传参需要在路由规则中配置接收参数的参数名
最后详情页再通过this.$route.params/query.接收的参数名后 发送不同参数的请求接收不同的数据渲染页面
Vue中指令有哪些
v-text 将普通数据显示在页面上
v-html 输出html内容
v-show 控制元素的显示和隐藏
v-if 判断是否加载内容 v-else-if:满足一项先执行它 v-else:不然就执行它
v-model 用于表单的双向绑定
v-for 遍历数据
v-bind 绑定特殊属性
v-once 只渲染一次 数据改变不会影响该值的变化
v-on 绑定事件
v-on可以绑定多个方法吗
可以 使用v-on”{ click:dbclick,mouseomve:mouseclick }”
Vue-cli中如何自定义指令
自定义指令有5个钩子;
bind代表绑定指令到元素上,只执行一次
inserted代表绑定指令的元素插入到页面时就调用(常用)
componentUpdated:指令所在组件的节点及其子节点全部更新完成后调用
update:所有组件节点更新时调用
unbind:解除指令和元素的绑定,只执行一次
如果时局部指令使用directives:{ 自定义指令的名字:{ 钩子函数(el){ 操作逻辑 } } }写在data同级
如果时全局使用Vue.directive(‘自定义的名字’,{钩子函数(el){ 操作逻辑 } })
Watch请简述
监听data模型数据 当模型数据改变的时候就会触发;watch初始化的时候不会运行,只有数据被改变之后才会运行
v-text与区别{ { } }
{ { } }是模板插值,v-text是指令,模板插值 { { } } 如果数据过多可能会把大括号显示出来(屏幕闪动)需要使用v-cloak指令
对vue中keep-alive的理解
切换过程中将状态保留在内存中,防止重复渲染DOM,减少加载时间及性能消耗,提高用户体验性
用元素将其路由出口包裹起来;它有两个钩子函数 activated(激活后)和deactivated(停用后)
如何让组件中的css在当前组件生效
Vue组件中的data为什么是函数
data数据会以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,相当于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据.如果是对象形式,就使得所有组件实例共用了一份data,就会造成数据的公用的结果.
Vue双数据绑定过程中,这边儿数据改变了怎么通知另一边改变
当我们读取或者设置对象属性的时候,都会触发Object.defineProperty()函数的get和set方法,在这两个方法中添加操作从而劫持数据,当属性发生变化的时候,会执行一系列的渲染视图操作
Vue双向绑定的原理
数据劫持:当我们读取或者设置对象属性的时候,都会触发Object.defineProperty()函数的get和set方法,在这两个方法中添加操作从而劫持数据,当属性发生变化的时候,会执行一系列的渲染视图操作
发布者订阅模式:对象间一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都将得到通知.
Vue中组件怎么传值
正向传值:
在子组件用props新建一个数据名并使用,来接收父组件传过来的值
在父组件中使用子组件,并以特殊属性的方式,把需要传递的数据通过props数据名传递给子组件
逆向传值:可以使用自定义事件传值 或者ref获取节点传值或vuex传值
需通过事件函数来触发一个自定义事件: this.$emit(“自定义事件名”,传递的数据)
在使用子组件的父组件中,使用事件绑定指令绑定抛出的自定义事件名并让其等于一个函数,函数的形参就是传递的数据
Vue兄弟组件传值
可以使用传统的子传父 父再传子的办法或vuex或者eventBus
在父组件中使用两个子组件让其成为兄弟
在兄弟a引入事件总线,并通过事件函数来触发一个自定义事件 eventBus.$emit(“自定义事件名”,”要传递的数据”)
在兄弟b引入事件总线,在钩子函数中使用eventBus.$on(“自定义事件名”,(val)=>{})接收传递的数据,回调函数中的形参就是传递的数据
请简述插槽
父组件中子组件中数量不同内容也不相同的时候使用的技术; 子组件中插入 则可在父组件的子组件开标签内部写入标签和内容
Vue首屏加载慢的原因,怎么解决的,白屏时间怎么检测,怎么解决白屏问题
使用路由懒加载(还有如将第三方依赖打包进入CDN服务器,按需引入ui,压缩代码,精灵图等等)
Vuex是什么?怎么使用?在那种场景下使用?
状态(数据)管理工具,就是一个数据的仓库,将数据全部存入仓库,组件就可以自由使用数据
将数据保存在state中,通过(this.$store.state.数据名)来调用数据,修改数据在Mutations中,在Actions调用mutations中的方法异步操作数据,在需要使用的组件通过this.$store.dispatch()来调用和传递实参
用于开发中大型web单页应用中对应用的状态进行管理或解决组件间数据通信麻烦的问题
vuex的优势
能够集中管理和共享数据,易于开发和维护
能够高效地实现组件之间的数据传递,提高开发效率
数据都是响应式的,能够实时保持数据与页面的同步
Vuex怎么请求异步数据
在action使用封装的axios发送请求,接收到数据后使用commit调用mutation给state数据赋值
Vuex中action如何提交给mutation的
在组件内通过this.$store.dispatch()调用action的方法并传递实参,在action中使用commit调用mutation方法,通过mutation修改state中的数据
vuex有哪几种状态和属性
数据保存的地方:State
对数据过滤的:Getter
修改数据的:Mutation
处理异步操作的:Action
让数据模块化的:Module
vuex的State特性是?
state就是存放数据的仓库,特性就是若store中的state数据发生改变,依赖这个数据的组件也会相应更新(当mutation修改了state的数据的时候,他会动态的去修改所有的调用这个变量的组件里的值)
vuex的Getter特性是?
vuex的Mutation特性是?
同步执行,修改state数据的唯一途径,直接变更state数据.
vuex的actions特性是?
用于异步请求数据,不能直接操作state,需要通过提交给mutation来修改state数据
$set:解决data数据改变和视图不改变(vue3.0以上已解决,面试常问)
vue中的拖拽+js原生拖拽说思路?
需要三个事件 鼠标 按下\移动\抬起
当按下时获取鼠标点击元素的内部鼠标的位置 移动时获取鼠标在页面的位置并减去元素内部鼠标的位置,同时判断边界条件,当减去的位置的x轴小于零代表出屏幕的左边,当减去的位置的y轴小于零代表出屏幕的右边,当大于时则需要算出页面的宽度高度(window.innnerXXX)减去元素的宽高度,当大于这个值就等于这个值, 当抬起时把移动的事件归位为null
vue中assets和public里的静态区别?
public放不会变动的文件(相当于vue-cli2.x中的static)public/ 目录下的文件并不会被Webpack处理:它们会直接被复制到最终的打包目录(默认是dist/static)下.必须使用绝对路径引用这些文件,这个取决于你vue.config.js中publicPath的配置,默认的是/.
assets放可能会变动的文件assets目录中的文件会被webpack处理解析为模块依赖,只支持相对路径形式.简单来说就是就是public放别人家js文件(也就是不会变动),assets放自己写的js文件(需要改动的文件)
怎么提升页面性能?性能优化有哪些?
不用将所有的数据都在data中注册,不需要响应式的数据可以定义在实例上
v-for循环生产的代码,要操作dom可以用事件委托
使用keep-alive缓存组件,防止切换路由时来回创建组件浪费性能
如果没有安全性考虑使用v-show代替v-if指令
使用路由懒加载
VUE3
TypeScript Typescript是什么 请简述?
Typescript 与javascript 的优势?
Typescript优势
能帮助开发人员检测出错误并修改
TypeScript工具使重构更变的容易、快捷
类型安全能在编码期间检测错误,可以更好的协作,对于大型项目更友好
便于开发人员做注释
javascript优势
不需要编译,直接由浏览器执行
社区成熟,可以很方便地找到大量成熟的开发项目和可用资源
比较灵活
工程化工具 Webpack
Webpack与gulp区别
Webpack和另外两个并没有太多的可比性,Gulp/Grunt是一种能够优化前端的开发流程的工具,而WebPack是一种模块化的解决方案,不过Webpack的优点使得Webpack在很多场景下可以替代Gulp/Grunt类的工具.
请简述webpack中的loaders与plugin的区别
loader:模块转换器(翻译器),如 less –> css, 如识别 js 结尾的,css 结尾的,图片格式结尾的,通过 loader 转换成相应的文件格式
plugin:扩展插件,如 HtmlWebpackPlugin
说一下webpack的打包原理
把所有依赖打包成一个bundle.js文件,通过代码分割成单元片段并按需加载.
说一下对websocket的理解
WebSocket是html5出的一个持久化的协议,它是HTTP协议上的一种补充,因为HTTP协议通信只能由客户端发起,如果要获取一些实时性较高的信息,只能通过“轮询”一类的方式,但是要不停连接所以轮询的效率低,非常浪费资源.所以通过websocket协议可以让服务器主动向客户端推送消息解决了这种问题,做到双向平等对话
Vite
rollup babelrc eslint 网络 Get和post有什么区别?
get安全性低,post有加密所有安全性高
get发送的数据会暴露在地址栏并且会被保存在历史记录里,而post不会
get参数通过URL传递,post放在Request body中.
传输的数据量不同,get传输的量小,不能大于2kb,post理论上没有限制
get一般用于获取数据,post一般用于发送数据
常见的HTTP状态码:
1##:信息响应类,表示接收到请求并且继续处理
2##:处理成功响应类,表示动作被成功接收、理解和接受
3##:重定向响应类,为了完成指定的动作,必须接受进一步处理
301 Moved Permanently 永久性转移/重定向
302 Move Temporarily 临时转移
307 Temporary Redirect 临时重定向,一般应用于服务器的负载均衡
304 Not Modified ——客户端已经执行了GET,但文件未变化
4##:客户端错误,客户请求包含语法错误或者是不能正确执行
400 Bad Request 请求参数错误
401 Unauthorized 无权限访问
404 Not Found 地址错误
405 Method Not Allowed 当前请求的方式服务器不支持
5##:服务端错误,服务器不能正确执行一个正确的请求
500 Internal Server Error 未知服务器错误
503 Service Unavailable 服务器超负荷
http是什么?有什么特点
http是客户端浏览器或其他程序与Web服务器之间的应用层通信协议
特点:
简单快速灵活:客户向服务器请求服务时,只需传送请求方法和路径且HTTP允许传输任意类型的数据对象
无连接:每次连接只处理一个请求,收到用户应答后,就断开连接
无状态:协议对于事务处理没有记忆能力,如果后续处理需要前面的信息,则它必须重传
HTTP协议和HTTPS区别
传输信息安全性不同;前者是超文本传输协议,信息是明文传输,后者是具有安全性的ssl加密传输协议
连接方式不同:前者很简单是无状态的,后者是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议
端口不同:前者端口是80,后者是443
什么是csrf攻击
csrf(cross-site request forgery)是跨站请求伪造;攻击者盗用了用户的身份,以用户的名义发送恶意请求,它可以做的事情包括 以用户的名义发邮件,发消息,购买物品和盗取用户账户
为什么会造成跨域/请简述同源策略
不符合同源协议(不同协议;不同域名/IP;不同端口号),
解决方法:
JSONP请求:JSONP的原理是利用 script 标签的跨域特性,可以不受限制地从其他域中加载资源
CORS跨域:就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功还是应该失败.
Web sockets跨域:是HTML5一种新的协议.它实现了浏览器与服务器全双工通信,同时允许跨域通讯,在js中创建WebSockets后,会有一个HTTP请求发送到浏览器以发起连接.在取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为WebSocket协议,所以只能支持此协议的专门服务器才能正常工作
proxy代理:请求不会直接发给目标主机,而是先发给代理机再向目标主机发送,接收目标机数据后再由代理服务器返还给用户
什么是CORS
CORS是一个W3C标准,全称是”跨域资源共享”(Cross-Origin Resource Sharing).它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了ajax只能同源使用的限制.
后台传递过来的数据格式有哪些
json:一段用数组或对象表示得键值对
arraybuffer: 通用的、固定长度的原始二进制数据缓冲区,它是一个字节数组
blob : 一个不可变、原始数据的类文件对象.它的数据可以按文本或二进制的格式进行读取
document : 如xml一类的文件格式
text : 文本格式
stream : 数据流
算法题 数组去重的方式
双层for循环 1 2 3 4 5 6 7 8 9 10 function unique (arr ){ for (let i=0 ; i<arr.length ; i++){ for (let j = i+ 1 ; j < arr.length ; j++){ if (arr[i]==arr[j]){ arr.splice (j,1 ); j--; } } } return arr; }
利用indexOf去重 1 2 3 4 5 6 7 8 9 function unique (arr ) { let array = []; for (let i = 0 ; i < arr.length ; i++) { if (array.indexOf (arr[i]) === -1 ) { array.push (arr[i]) } } return array; }
利用filter过滤 1 2 3 4 5 6 function unique (arr ) { return arr.filter (function (item, index, arr ) { return arr.indexOf (item,0 ) === index; }); }
利用ES6 Set去重 1 2 3 function unique (arr ) { return Array .from (new Set (arr)) }
数组排序的方式
冒泡排序1 2 3 4 5 6 7 8 9 10 11 12 13 function sort (arr ) { let temp = null ; for (let i = 0 ;i < arr.length -1 ; i++){ for (let j = 0 ;j < arr.length -i-1 ;j++){ if (arr[j] > arr[j+1 ]){ temp = arr[j]; arr[j] = arr[j+1 ]; arr[j+1 ] = temp; } } } return arr; }
- - https://www.yuque.com/kanding/ktech/bmy2w1i1s4fo6k9w
擂台排序1 2 3 4 5 6 7 8 9 10 11 12 13 function sort (arr ){ let temp = null ; for (let i =0 ;i < arr.length - 1 ; i++ ){ for (let j = i+ 1 ;j < arr.length ; j++ ){ if (arr[i] > arr[j]){ temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } } } return arr; }
sort排序 1 2 3 4 5 6 function sort (arr ){ arr.sort ((small,big )=> { return small-big; }) return arr; }
遍历一个多维数组 1 2 3 4 5 function each (obj ){ for (let key in obj){ typeof (obj[key]) == "object" ? each (obj[key]) : console .log (key+'--' +obj[key]) } }
深拷贝的代码实现
简单深拷贝(一层拷贝)1 2 3 4 5 6 7 function deepCopy (obj ){ let copyObj = Array .isArray (obj) ? [] : {}; for (let key in obj){ copyObj[key] = obj[key]; } return copyObj; }
复杂深拷贝(递归实现多层拷贝)1 2 3 4 5 6 7 8 9 function deepCopy (obj ){ let copyObj = Array .isArray (obj) ? [] : {}; for (let key in obj){ if ( obj.hasOwnProperty (key) ){ copyObj[key] = typeof obj[key] === 'object' ? deepCopy (obj[key]) : obj[key] ; } } return copyObj; }
合并两个有序数组
给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m 和 n ,分别表示 nums1 和 nums2 中的元素数目。 请你 合并 nums2 到 nums1 中,使合并后的数组同样按 非递减顺序 排列。 注意:最终,合并后数组不应由函数返回,而是存储在数组 nums1 中。为了应对这种情况,nums1 的初始长度为 m + n,其中前 m 个元素表示应合并的元素,后 n 个元素为 0 ,应忽略。nums2 的长度为 n