Web前端面试题之考官高频问点
1.对seo搜索优化的了解
SEO(Search Engine Optimization)全称是搜索引擎优化, 其目的是为了使网站能够更好的被搜索引擎抓取,提高在搜索引擎内的自然排名,从而带来更多的免费流量,获取收益。
SEO主要有两种方法,站内优化和站外优化,其中技术上主要以站内优化为主。
站内优化:
-
title : Title是整个html在搜索引擎结果返回的最重要且最为核心的要素,一般不超过100个字节。
-
Meta Keywords:
(1) 确信使用的关键词出现在网页文本中;
(2)不要重复使用关键词;
(3) 每个网页的关键词应该不一样;
(4)一个网页的关键词标签里应该包含3-5个最重要的关键词,不要超过5个;
(5)主流搜索引擎对其的建议是不超过160字节。
-
Meta Description :为搜索引擎提供参考,网页的描述信息;搜索引擎采纳后,作为搜索结果中的页面摘要显示,主流搜索引擎对其的建议是不超过400个字节。
-
图片的Alt属性:html中,图片的alt属性值也会被搜索引擎抓取,因此网站中图片都应有alt值有利于网站的优化。
站外优化:
站外优化是指在其他一些内容会被搜索引擎抓取的网站中,投放自己网站的链接,进行引流。如微博、贴吧、问答平台等等。
2.行内元素和块级元素
块级元素(block)特性:
总是独占一行,表现为另起一行开始,而且其后的元素也必须另起一行显示; 宽度(width)、高度(height)、内边距(padding)和外边距(margin)都可控制;
内联元素(inline)特性:
和相邻的内联元素在同一行;
3.img的title和alt的区别
alt 属性是当元素不能正常呈现时用作元素内容的替代文本,title 属性是将鼠标悬停在元素上时看到的工具提示文本,是对图片的描述和进一步的说明。
4.媒体查询的使用方式
首先用媒体查询我们得知道什么是媒体查询?
Media Queries能在不同的条件下使用不同的样式,使页面在不同在终端设备下达到不同的渲染效果
- 最大宽度最小宽度
@media 媒体类型and (媒体特性){你的样式}
然后我们来看一个例子
@media screen and (max-width:480px){
.ads {
display:none;
}
}
这个是最大宽度max-width, “max-width”是媒体特性中最常用的一个特性,其意思是指媒体类型小于或等于指定的宽度时,样式生效。有最大肯宽度定就有最小宽度min-width,他的意思和“max-width”正好相反
- 多个媒体特性使用
还可以多个媒体特性使用,当屏幕在600px~900px之间时,body的背景色渲染为“#f5f5f5”,如下所示。
@media screen and (min-width:600px) and (max-width:900px){
body {background-color:#f5f5f5;}
}
- 设备屏幕的输出宽度Device Width
在智能设备上,例如iPhone、iPad等,还可以根据屏幕设备的尺寸来设置相应的样式(或者调用相应的样式文件)。同样的,对于屏幕设备同样可以使用“min/max”对应参数,如“min-device-width”或者“max-device-width”。
<link rel="stylesheet" media="screen and (max-device-width:480px)" href="iphone.css" />
上面的代码指的是“iphone.css”样式适用于最大设备宽度为480px,比如说iPhone上的显示,这里的“max-device-width”所指的是设备的实际分辨率,也就是指可视面积分辨率。
- not关键词
使用关键词“not”是用来排除某种制定的媒体类型,也就是用来排除符合表达式的设备。换句话说,not关键词表示对后面的表达式执行取反操作,如:
@media not print and (max-width: 1200px){样式代码}
上面代码表示的是:样式代码将被使用在除打印设备和设备宽度小于1200px下所有设备中。
- only关键词
only用来指定某种特定的媒体类型,可以用来排除不支持媒体查询的浏览器。其实only很多时候是用来对那些不支持Media Query但却支持Media Type的设备隐藏样式表的。其主要有:支持媒体特性的设备,正常调用样式,此时就当only不存在;表示不支持媒体特性但又支持媒体类型的设备,这样就会不读样式,因为其先会读取only而不是screen;另外不支持Media Queries的浏览器,不论是否支持only,样式都不会被采用。如
<link rel="stylesheet" media="only screen and (max-device-width:240px)" href="android240.css" />
在Media Query中如果没有明确指定Media Type,那么其默认为all,如:
<link rel="stylesheet" media="(min-width:701px) and (max-width:900px)" href="mediu.css" /></pre>
另外在样式中,还可以使用多条语句来将同一个样式应用于不同的媒体类型和媒体特性中,指定方式如下所示。
<link rel="stylesheet" type="text/css" href="style.css" media="handheld and (max-width:480px), screen and (min-width:960px)" />
上面代码中style.css样式被用在宽度小于或等于480px的手持设备上,或者被用于屏幕宽度大于或等于960px的设备上。
5.src和href之间的区别
src 用于替换当前元素,href 用于在当前文档和引用资源之间确立联系。 src 是 source 的缩写,指向外部资源的位置,指向的内容将会嵌入到文档中当前标签所在 位置;在请求 src 资源时会将其指向的资源下载并应用到文档内,例如 js 脚本,img 图片 和 frame 等元素。
<script src =”js.js”></script>
当浏览器解析到该元素时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行 完毕,图片和框架等元素也如此,类似于将所指向资源嵌入当前标签内。这也是为什么将 js 脚本放在底部而不是头部。 href 是 Hypertext Reference 的缩写,指向网络资源所在位置,建立和当前元素(锚点) 或当前文档(链接)之间的链接,如果我们在文档中添加
<link href=”common.css” rel=”stylesheet”/>
那么浏览器会识别该文档为 css 文件,就会并行下载资源并且不会停止对当前文档的处理。 这也是为什么建议使用 link 方式来加载 css,而不是使用@import 方式。
6.css让元素看不到的方法
- display:none 是不占位隐藏
- text-indent,这个属性本来是用来设置文本缩进的,一般我们习惯是首行缩2个中文字所以一般的用法是
text-indent:2em。但它允许负值,假如给它一个负值,这个负值足够大,大到一般我们浏览器无法显示
p {
text-indent: -9999px; // 万一日后用户屏幕宽度达到1万肿么办?(这好像不可能。。。)
background: url(logo.png);
direction: ltr; // 设置为从左到右读的方向,避免 rtl 语言环境下出现横向滚动条
}
-
visibility,这个属性也是可以达到隐藏元素的目的,这个属性也是跟display属性正好相反,这个也只是“看不见”而已。用了该属性属性之后,元素在前端页面是解析不出来的,但是元素依然存在在哪里,只不过我们肉眼不可见,所以元素依然会影响到布局。
用法visibility:hidden -
opacity,这个是用到了元素不透明度的办法。这个不失为一个好的办法,巧妙地把元素不透明直接调节到了0,让其消失得无影无踪,详细介绍可以移步 opacity属性值 ,但是这样的写法蛋疼的就是IE6-IE8对opicty不感冒,必须要用IE透明专属写法:filter:alpha(opacity=x),x为元素的不透明值,从10~100,100为全不透明.
用法 opacity:0
7.重绘和回流
DOM性能 浏览器的性能大部分都是被这两个问题所消耗
- 重绘:DOM树没有元素增加或删除,只是样式的改变,针对浏览器对某一元素进行单独的渲染,整个过程就叫做重绘
- 回流:DOM书中的元素焙增加或删除,导致浏览器需要重新的去渲染整个DOM树,回流比重绘更消耗性能,发生回流必定重绘,重绘不一定会导致回流。 因为重绘和回流的存在导致真实DOM性能不佳没所以Vue和react还有angular等框架增加了虚拟DOM技术,就是为了减少DOM的重绘和回流从而见到浏览器性能消耗,这就是虚拟DOM的好处
8.new操作符具体干了什么
- 创建一个空对象,并且this变量引用该对象,同时还继承了该函数的原型
- 属性和方法被加入到this引用的对象中
- 新创建的对象由this所引用,并且最后隐式的返回this
9.ajax的原理
Ajax 的原理简单来说通过 XmlHttpRequest 对象来向服务器发异步请求,从服务器获得数据, 然后用javascript来操作DOM而更新页面。这其中最关键的一步就是从服务器获得请求数据。 要清楚这个过程和原理,我们必须对 XMLHttpRequest 有所了解。
XMLHttpRequest 是 ajax 的核心机制,它是在 IE5 中首先引入的,是一种支持异步请求的 技术。简单的说,也就是 javascript 可以及时向服务器提出请求和处理响应,而不阻塞用户。 达到无刷新的效果。
10. 常见的设计模式有哪些?
JS 设计模式有很多,但我知道的有单例模式,观察者模式
单例模式:就是保证一个类只有一个实例,实现的方法是先判断实例存 在与否,如果存在直接返回,如果不存在就创建了再返回,确保了一个类 只有一个实例对象。在 JavaScript 里,单例作为一个命名空间提供者,从全 局命名空间里提供一个唯一的访问点来访问该对象。
观察者模式: 观察者的使用场合就是:当一个对象的改变需要同时改变 其它对象,并且它不知道具体有多少对象需要改变的时候,就应该考虑使用 观察者模式。
总的来说,观察者模式所做的工作就是在解耦,让耦合的双方都依赖于抽 象,而不是依赖于具体。从而使得各自的变化都不会影响到另一边的变化
11.说说你对promise的理解
这种做法在逻辑比较复杂的回调嵌套中会相当复杂;也叫做回调地狱;
promise用来将这种繁杂的做法简化,让程序更具备可读性,可维护性;
promise内部有三种状态,pedding,fulfilled,rejected;
pedding表示程序正在执行但未得到结果,即异步操作没有执行完毕,fulfilled表示程序执行完毕,且执行成功,
rejected表示执行完毕但失败;这里的成功和失败都是逻辑意义上的;并非是要报错。
其实,promise和回调函数一样,都是要解决数据的传递和消息发送问题,
promise中的then一般对应成功后的数据处理,catch一般对应失败后的数据处理。
12.浏览器的缓存策略
它也是我们在日常开发中存在的一个非常重要的优化手段,无论在节省带宽、提高加载和渲染速度、减少网络阻塞,以及提高用户体验上,都发挥着很重要的作用。在此总结以下几点:
-
缓存分为强缓存和协商缓存。其中强缓存包括
Expires和Cache-Control,主要是在过期策略生效时应用的缓存。弱缓存包括Last-Modified和ETag,是在协商策略后应用的缓存。强弱缓存之间的主要区别在于获取资源时是否会发送请求。 -
Cache-Control中的max-age指令用于指定缓存过期的相对时间,优先级高于Expires。Cache-Control指定为no-cache时,由于no-cache相当于max-age:0,must-revalidate,所以都存在时优先级也是高于Expires。 -
no-cache并不是指不缓存文件,no-store才是指不缓存文件。no-cache仅仅是表明跳过强缓存,强制进入协商策略。 -
如果
Expires,Cache-Control: max-age,或Cache-Control:s-maxage都没有在响应头中出现,并且设置了Last-Modified时,那么浏览器默认会采用一个启发式的算法,即启发式缓存。通常会取响应头的Date_value - Last-Modified_value值的10%作为缓存时间
13.js的内存存储方式
有两种,一种是本地存储(localStorage)另一种是临时性 的 本地 存储 。SessionStorage:临时性的本地存储,只要关闭浏览器 , 数据就会被清理掉 , 仅当次会话有效。
14.js里如何判断是不是一个数组
- Array.isArray()
- [] instanceof Array
- [].constructor === Array
- Object.prototype.toString().call()
let a = [1,2,3]
Object.prototype.toString.call(a) === '[object Array]';//true
15.map和foreach的区别
- 能用 forEach () 做到的, map () 同样可以。反过来也是如此。
- map () 会分配内存空间存储新数组并返回, forEach () 不会返回数据。
- forEach () 允许 callback 更改原始数组的元素。 map () 返回新的数组。
16.vue2的双向数据绑定原理
vue.js则是采用数据劫持结合发布者-订阅模式的方式,通过Object.defineProperty()来劫持各个属性的setter,geeter,在数据变动时发布消息给订阅者,触发相应的监听回调
17.数组去重的方法
1.利用ES6 Set去重(ES6中最常用)
function unique (arr) {
return Array.from(new Set(arr))
}
2.利用for嵌套for,然后splice去重(ES5中最常用)
var arr = [1, 1, 8, 8, 12, 12, 15, 15, 16, 16];
function unlink(arr) {
for (var i = 0; i < arr.length; i++) {// 首次遍历数组
for (var j = i + 1; j < arr.length; j++) {// 再次遍历数组
if (arr[i] == arr[j]) {// 判断连个值是否相等
arr.splice(j, 1);// 相等删除后者
j--;
}
}
}
return arr
}
console.log(unlink(arr));
3.利用indexOf去重
var arr = [1, 1, 8, 8, 12, 12, 15, 15, 16, 16];
function unlink(arr) {
if (!Array.isArray(arr)) {
console.log('错误!')
return
}
var array = [];
for (var i = 0; i < arr.length; i++) { // 首次遍历数组
if (array.indexOf(arr[i]) === -1) { // 判断索引有没有等于
array.push(arr[i])
}
}
return array
}
console.log(unlink(arr));
4.利用includes
var arr = [1, 1, 8, 8, 12, 12, 15, 15, 16, 16];
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
var array =[];
for(var i = 0; i < arr.length; i++) {
if( !array.includes( arr[i]) ) {//includes 检测数组是否有某个值
array.push(arr[i]);
}
}
return array
}
console.log(unique(arr))
5.利用filter
var arr = [1, 1, 8, 8, 12, 12, 15, 15, 16, 16];
function unlink(arr) {
return arr.filter(function (item, index, arr) {
//当前元素,在原始数组中的第一个索引==当前索引值,否则返回当前元素
return arr.indexOf(item, 0) === index;
});
}
console.log(unlink(arr));
18.vue2的生命周期
vue 生命周期即为一个组件从出生到死亡的一个完整周期,主要包括以下 4
个阶段:创建,挂载,更新,销毁
创建前:beforeCreate, 创建后:created
挂载前:beforeMount, 挂载后:mounted
更新前:beforeUpdate, 更新后:updated
销毁前:beforeDestroy, 销毁后:destroyed
我平时用的比较多的钩了是 created 和 mounted,created 用于获取后台数据, mounted 用于 dom 挂载完后做一些 dom 操作,以及初始化插件等.beforeDestroy 用户清除定时器以及解绑事件等,
另外还新增了使用内置组件 keep-alive 来缓存实例,而不是频繁创建和销毁(开销 大) actived 实例激活 deactived 实例失效 以下为详解版,大家理解就 ok: 生命周期钩子函数(11 个)Function(类型),标注蓝色的那个是属于类型的 意思。
beforeCreate Function 在实例初始化之后,数据观测 (data observer) 和 event/watcher 事件配置之前被调用。
created Function 在实例创建完成后被立即调用。在这一步,实例已完成以 下的配置:数据观测 (data observer),属性和方法的运算,watch/event 事 件回调。然而,挂载阶段还没开始,$el 属性目前不可见。
beforeMount Function在挂载开始之前被调用相关的render 函数首次被调用。 mounted Function el 被新创建的 vm.el 也在文档内。
beforeUpdate Function 数据更新时调用,发生在虚拟 DOM 打补丁之前。 这里适合在更新之前访问现有的 DOM,比如手动移除已添加的事件监听器。该 钩子在服务器端渲染期间不被调用,因为只有初次渲染会在服务端进行。 updated Function 由于数据更改导致的虚拟 DOM 重新渲染和打补丁,在 这之后会调用该钩子。
activatedFunction keep-alive 组件激活时调用。该钩子在服务器端渲染 期间不被调用。
deactivated Function keep-alive 组件停用时调用。该钩子在服务器端 渲染期间不被调用。
beforeDestroyFunction 实例销毁之前调用。在这一步,实例仍然完全可用。 该钩子在服务器端渲染期间不被调用。
destroyedFunction Vue 实例销毁后调用。调用后,Vue 实例指示的所有东 西都会解绑定,所有的事件监听器会被移除,所有的子实例也会被销毁。该钩 子在服务器端渲染期间不被调用。
errorCaptured(2.5.0+ 新增) (err: Error, vm: Component, info: string) => ?boolean 当捕获一个来自子孙组件的错误时被调用。此钩子会收到三个参 数:错误对象、发生错误的组件实例以及一个包含错误来源信息的字符串。此 钩子可以返回 false 以阻止该错误继续向上传播。
19.标准盒子模型和怪异盒子模型
在了解这两种盒模型的区别之前首先我们要先了解什么是盒模型(box-mold),盒模型顾名思义就是在css中的盒子,把HTML的元素封装成盒子用来设计和布局时使用,盒模型中又包含了以下几个元素:
(1)内容(content) (2)填充(padding)
(3)边框(border) (4)边距(margin)
详细说明:
内容(content):盒子的内容,主要用来显示文字和图像。
填充(padding):也叫内边距,用来清除内容周围的区域,它是透明的。
边框(border):围绕在内边距和内容外的边框,盒子的外壳。
边距(margin):也叫外边距,用来清除边框外的区域,它跟填充一样都是透明的。
为了方便理解我们可以把盒模型比喻成一箱酸奶,内容就是箱子里的酸奶,内边距就是酸奶与箱子之间的泡沫板,边框就是我们的箱子,外边距就是我们从一箱酸奶到另一箱酸奶之间的距离。
标准盒模型 标准盒模型就是W3C的标准盒子模型 内盒尺寸(大小)=width+padding+border 外盒尺寸(空间尺寸)= width+padding+border+margin 怪异盒模型 怪异盒模型就是IE盒模型 内盒尺寸(大小)=width 外盒尺寸(空间尺寸)= width+ margin
知道这些之后怪异盒模型与标准盒模型的区别显而易见了,它们两个宽度相加的属性是一样的。不过在IE中content的宽度包括padding和border这两个属性。如下图所示:
知识拓展:
标准盒模型和怪异盒模型之间的转换:box-sizing : content-box/boeder-box/inherit ;
当为content-box时,将采取标准模式进行解析计算;
当为border-box时,将采取怪异模式解析计算;
当为inherit时,将从父元素来继承box-sizing属性的值;
20.如何清除浮动属性
- clear:both;
- overflow:hidden;
- 使用after伪元素清除浮动
- 使用before和after双伪元素清除浮动
.clearfix:after,.clearfix:before{
content: "";
display: table;
}
.clearfix:after{
clear: both;
}
.clearfix{
*zoom: 1;
}
<div class="fahter clearfix">
<div class="big">big</div>
<div class="small">small</div>
</div>
<div class="footer"></div>
21.ES6新增语法
- let
- const
- let、const、var区别
- 解构赋值
- 对象解构
- 箭头函数
- 剩余参数
- 扩展运算符
- ES6的内置对象扩展
- Set ES6 新增特性常用的主要有:let/const,箭头函数,模板字符串,解构赋 值,模块的导入(import)和导出(export default/export),Promise,还有一些 数组字符串的新方法
22.eventloop的理解
Event Loop即事件循环,是指浏览器或Node的一种解决javaScript单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。 JavaScript有一个基于事件循环的并发模型,事件循环负责执行代码、收集和处理事件以及执行队列中的子任务。这个模型与其它语言中的模型截然不同,比如 C 和 Java。
运行时概念
接下来的内容解释了这个理论模型。现代JavaScript引擎实现并着重优化了以下描述的这些语义。
可视化描述
栈
函数调用形成了一个由若干帧组成的栈。
function foo(b) {
let a = 10;
return a + b + 11;
}
function bar(x) {
let y = 3;
return foo(x * y);
}
console.log(bar(7)); // 返回 42
Copy to Clipboard
当调用 bar 时,第一个帧被创建并压入栈中,帧中包含了 bar 的参数和局部变量。 当 bar 调用 foo 时,第二个帧被创建并被压入栈中,放在第一个帧之上,帧中包含 foo 的参数和局部变量。当 foo 执行完毕然后返回时,第二个帧就被弹出栈(剩下 bar 函数的调用帧 )。当 bar 也执行完毕然后返回时,第一个帧也被弹出,栈就被清空了。
堆
对象被分配在堆中,堆是一个用来表示一大块(通常是非结构化的)内存区域的计算机术语。
队列
一个 JavaScript 运行时包含了一个待处理消息的消息队列。每一个消息都关联着一个用以处理这个消息的回调函数。
在 事件循环 期间的某个时刻,运行时会从最先进入队列的消息开始处理队列中的消息。被处理的消息会被移出队列,并作为输入参数来调用与之关联的函数。正如前面所提到的,调用一个函数总是会为其创造一个新的栈帧。
函数的处理会一直进行到执行栈再次为空为止;然后事件循环将会处理队列中的下一个消息(如果还有的话)。
事件循环
之所以称之为 事件循环,是因为它经常按照类似如下的方式来被实现:
while (queue.waitForMessage()) {
queue.processNextMessage();
}
queue.waitForMessage() 会同步地等待消息到达(如果当前没有任何消息等待被处理)。
执行至完成
每一个消息完整地执行后,其它消息才会被执行。这为程序的分析提供了一些优秀的特性,包括:当一个函数执行时,它不会被抢占,只有在它运行完毕之后才会去运行任何其他的代码,才能修改这个函数操作的数据。这与C语言不同,例如,如果函数在线程中运行,它可能在任何位置被终止,然后在另一个线程中运行其他代码。
这个模型的一个缺点在于当一个消息需要太长时间才能处理完毕时,Web应用程序就无法处理与用户的交互,例如点击或滚动。为了缓解这个问题,浏览器一般会弹出一个“这个脚本运行时间过长”的对话框。一个良好的习惯是缩短单个消息处理时间,并在可能的情况下将一个消息裁剪成多个消息。
添加消息
在浏览器里,每当一个事件发生并且有一个事件监听器绑定在该事件上时,一个消息就会被添加进消息队列。如果没有事件监听器,这个事件将会丢失。所以当一个带有点击事件处理器的元素被点击时,就会像其他事件一样产生一个类似的消息。
函数 setTimeout 接受两个参数:待加入队列的消息和一个时间值(可选,默认为 0)。这个时间值代表了消息被实际加入到队列的最小延迟时间。如果队列中没有其它消息并且栈为空,在这段延迟时间过去之后,消息会被马上处理。但是,如果有其它消息,setTimeout 消息必须等待其它消息处理完。因此第二个参数仅仅表示最少延迟时间,而非确切的等待时间。
下面的例子演示了这个概念(setTimeout 并不会在计时器到期之后直接执行):
const s = new Date().getSeconds();
setTimeout(function() {
// 输出 "2",表示回调函数并没有在 500 毫秒之后立即执行
console.log("Ran after " + (new Date().getSeconds() - s) + " seconds");
}, 500);
while(true) {
if(new Date().getSeconds() - s >= 2) {
console.log("Good, looped for 2 seconds");
break;
}
}
Copy to Clipboard
零延迟
零延迟并不意味着回调会立即执行。以 0 为第二参数调用 setTimeout 并不表示在 0 毫秒后就立即调用回调函数。
其等待的时间取决于队列里待处理的消息数量。在下面的例子中,"这是一条消息" 将会在回调获得处理之前输出到控制台,这是因为延迟参数是运行时处理请求所需的最小等待时间,但并不保证是准确的等待时间。
基本上,setTimeout 需要等待当前队列中所有的消息都处理完毕之后才能执行,即使已经超出了由第二参数所指定的时间。
(function() {
console.log('这是开始');
setTimeout(function cb() {
console.log('这是来自第一个回调的消息');
});
console.log('这是一条消息');
setTimeout(function cb1() {
console.log('这是来自第二个回调的消息');
}, 0);
console.log('这是结束');
})();
// "这是开始"
// "这是一条消息"
// "这是结束"
// "这是来自第一个回调的消息"
// "这是来自第二个回调的消息"
Copy to Clipboard
多个运行时互相通信
一个 web worker 或者一个跨域的 iframe 都有自己的栈、堆和消息队列。两个不同的运行时只能通过 postMessage 方法进行通信。如果另一个运行时侦听 message 事件,则此方法会向该运行时添加消息。
永不阻塞
JavaScript的事件循环模型与许多其他语言不同的一个非常有趣的特性是,它永不阻塞。 处理 I/O 通常通过事件和回调来执行,所以当一个应用正等待一个 IndexedDB 查询返回或者一个 XHR 请求返回时,它仍然可以处理其它事情,比如用户输入。
由于历史原因有一些例外,如 alert 或者同步 XHR,但应该尽量避免使用它们。注意,例外的例外也是存在的(但通常是实现错误而非其它原因)。
标准规范
| 标准规范 | 状态 | 注释 |
|---|---|---|
| HTML Living Standard Event loops | Living Standard | |
| Node.js 事件循环 | Living Standard |
23.常见的跨域方式
在前端领域中,跨域是指浏览器允许向服务器发送跨域请求,从而克服Ajax只能同源使用的限制。
什么是同源策略?
同源策略是一种约定,由Netscape公司1995年引入浏览器,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,浏览器很容易受到XSS、CSFR等攻击。所谓同源是指"协议+域名+端口"三者相同,即便两个不同的域名指向同一个ip地址,也非同源。
同源策略限制以下几种行为:
- Cookie、LocalStorage 和 IndexDB 无法读取
- DOM和JS对象无法获得
- AJAX 请求不能发送
跨域是浏览器做出的限制,和后端没关系
一、是 jsonp
jsonp 实现原理:主要是利用动态创建 script 标签请求后端接口 地址,然后传递 callback 参数,后端接收 callback,后端经过 数据处理,返回 callback 函数调用的形式,callback 中的参数 就是 json
二、 通过代理的方式(前端代理和后端代理) 前端代理我在 vue 中使用那个 vue.config.js 里面配置一个 proxy,里面有个 target 属性指向跨域链接.修改完重启项目就可 以了.实际上就是启动了一个代理服务器.绕开同源策略,在请求 的时候,通过代理服务器获取到数据再转给浏览器
三、 是 CORS CORS 全称叫跨域资源共享,主要是后台工程师设置后端代码来达 到前端跨域请求的 注:现在主流框架都是用代理和 CORS 跨域实现的
24.存储方式浏览器
主要有 cookie 、 localStorage 、 sessionStorage. cookie 属于文档对象模型DOM树根节点document,而 sessionStorage 和 localStorage 属于浏览器对象模型BOM的对象window. 其中 sessionStorage 和 localStorage 是 HTML5 Web Storage API 提供的. sessionStorage: 为每一个给定的源(given origin)维持一个独立的存储区域,该存储区域在页面会话期间可用(即只要浏览器处于打开状态,包括页面重新加载和恢复). localStorage: 同样的功能,但是在浏览器关闭,然后重新打开后数据仍然存在。
25.vue子父组件传值
这次,主要讲解一下子传父
26.cookie、sessionStorage、localStorage
- 存储大小:
cookie数据大小不能超过4k,sessionStorage和localStorage虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大 - 有效时间:
localStorage存储持久数据,浏览器关闭后数据不丢失除非主动删除数据;sessionStorage数据在当前浏览器窗口关闭后自动删除;cookie设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭 - 数据与服务器之间的交互方式,
cookie的数据会自动的传递到服务器,服务器端也可以写cookie到客户端;sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存
27.let、const、var的区别
-
使用
var声明的变量,作用域为该语句所在的函数内,且存在变量提升现象 -
使用
let声明的变量,作用域为该语句所在的代码块重,不存在变量提升 -
使用
const声明的常量,在后面出现的代码中不能再被修改var、let、const三者区别可以围绕下面五点展开: -
变量提升
-
暂时性死区
-
块级作用域
-
重复声明
-
修改声明的变量
-
使用
变量提升
var声明的变量存在变量提升,即变量可以在声明之前调用,值为undefined
let和const不存在变量提升,即它们所声明的变量一定要在声明后使用,否则报错
// var
console.log(a) // undefined
var a = 10
// let
console.log(b) // Cannot access 'b' before initialization
let b = 10
// const
console.log(c) // Cannot access 'c' before initialization
const c = 10
暂时性死区
var不存在暂时性死区
let和const存在暂时性死区,只有等到声明变量的那一行代码出现,才可以获取和使用该变量
// var
console.log(a) // undefined
var a = 10
// let
console.log(b) // Cannot access 'b' before initialization
let b = 10
// const
console.log(c) // Cannot access 'c' before initialization
const c = 10
块级作用域
var不存在块级作用域
let和const存在块级作用域
// var
{
var a = 20
}
console.log(a) // 20
// let
{
let b = 20
}
console.log(b) // Uncaught ReferenceError: b is not defined
// const
{
const c = 20
}
console.log(c) // Uncaught ReferenceError: c is not defined
重复声明
var允许重复声明变量
let和const在同一作用域不允许重复声明变量
// var
var a = 10
var a = 20 // 20
// let
let b = 10
let b = 20 // Identifier 'b' has already been declared
// const
const c = 10
const c = 20 // Identifier 'c' has already been declared
修改声明的变量
var和let可以
const声明一个只读的常量。一旦声明,常量的值就不能改变
// var
var a = 10
a = 20
console.log(a) // 20
//let
let b = 10
b = 20
console.log(b) // 20
// const
const c = 10
c = 20
console.log(c) // Uncaught TypeError: Assignment to constant variable
使用
能用const的情况尽量使用const,其他情况下大多数使用let,避免使用var
28.computed和watch的区别
computed:是vue独有的特性计算属性,可以对data中的依赖项再重新计算, 得到一个新值,应用到视图中, computed 是可缓存的,也就是说computed 中的依赖项没有变化,则computed中的值就不会重新计算。
Watch 是监听 data 和计算属性中的新旧变化。
29.vue3常用的API
| Api | 作用 |
|---|---|
| setup | setup函数是composotion api的入口函数,我们的变量,方法,函数等都是在该函数里定义的 |
| reactive | reactive方法是用来创建一个响应式的数据对象,该api很好的解决了vue2通过defineProperty实现数据响应式的缺陷(无法实现新增属性的响应式,无法实现删除属性的响应式,无法实现懒监听...) |
| ref | ref底层通过reactive包装了一个对象,然后将值传递给该对象的value属性,可以将ref(prop)理解为reactive({value: prop}),所以访问ref所包装的对象时需要加上.value |
| toRef | toRef是将某个对象中的某个值转化为响应式数据,接受两个参数,第一个参数为obj对象,第二个参数为对象的属性名 |
ref跟toRef的区别: | 1. ref是对传入数据的拷贝,toRef是对传入数据的引用2. ref值改变会更新视图,toRef值改变不会更新视图 |
| toRefs | toRefs的作用就是将传入对象所有的属性的值都转化为响应式数据对象,该函数只有一个参数,就是obj对象 |
| shallowReactive | 浅层次的reactive,reactive为深层次的,会为对象的每一层属性都使用proxy添加响应式,而shallowReactive只对对象的第一层属性添加响应式,可以进行性能优化 |
| shallowRef | 浅层次的ref,可以类比shallowReactive,这里不做多解释 |
| toRaw | toRaw用于获取ref或reactive对象的原始数据 |
| markRaw | markRaw可以将原始数据标记为非响应式数据,即便使用ref或者reactive包装后仍然无法实现响应式,接收一个参数,即原始数据,并返回被标记后的数据 |
| provide&inject | 与vue2中的provide&inject的作用是一样的,在vue3中需要手动引入provide:向子组件以及子孙组件传递数据,接收两个参数,第一个参数是key,即数据名,第二个参数为value,即数据值;inject:接收父组件或祖先组件传递过来的数据,接收一个参数key,父组件或祖先组件传递的数据名 |
| watch&watchEffect | 用来监视某项数据变化从而执行指定的操作;1. atch(source, cb, [options]);source:可以是表达式或函数,用于指定监听的依赖对象;cb: 依赖对象变化后执行的回调函数;options: 可选参数,可以配置的属性有immediate(立即触发回调函数),deep(深度监听);watch方法会返回一个stop方法,如果需要停止监听,可以直接执行stop方法;2. watchEffectwatchEffect跟watch不同,它不需要手动传入依赖,每次初始化的时候就会执行一次回调函数来自动获取到依赖,无法获取到原始值,只能获取改变后的值 |
| computed | 计算属性 const propA = ref(0); const propB = computed(()=> { return propA.value + 1 }) |
| useStore | vue3中使用vuex的方式跟vue2不一样,需要使用vuex中的useStore方法 |
| useRouter | vue3中使用路由的方式跟vue2不一样,需要使用router中的useRouter方法 |
| getCurrentInstance | vue3中获取实例的方式跟vue2不一样,需要使用getCurrentInstance方法 |
| 元素ref属性 | 元素ref属性可以获取到标签的元素或组件 |
30.js常见的创建方式
{}new Object()- 使用字面量
- 工厂模式
- 构造函数模式(constructor)
- 原型模式(prototype)
- 构造函数+原型模式 还有一些不常用的方式,如动态原型,寄生构造函数,稳妥构造函数。
31.==和===的区别
==, 两边值类型不同的时候,要先进行类型转换,再比较。
===,不做类型转换,类型不同的一定不等。
双等号==:
(1)如果两个值类型相同,再进行三个等号(===)的比较
(2)如果两个值类型不同,也有可能相等,需根据以下规则进行类型转换在比较:
1)如果一个是null,一个是undefined,那么相等
2)如果一个是字符串,一个是数值,把字符串转换成数值之后再进行比较
三等号===:
(1)如果类型不同,就一定不相等
(2)如果两个都是数值,并且是同一个值,那么相等;如果其中至少一个是NaN,那么不相等。(判断一个值是否是NaN,只能使用isNaN( ) 来判断)
(3)如果两个都是字符串,每个位置的字符都一样,那么相等,否则不相等。
(4)如果两个值都是true,或是false,那么相等
(5)如果两个值都引用同一个对象或是函数,那么相等,否则不相等
(6)如果两个值都是null,或是undefined,那么相等
32.阻止事件冒泡的方式
==, 两边值类型不同的时候,要先进行类型转换,再比较。
===,不做类型转换,类型不同的一定不等。
双等号==:
(1)如果两个值类型相同,再进行三个等号(===)的比较
(2)如果两个值类型不同,也有可能相等,需根据以下规则进行类型转换在比较:
1)如果一个是null,一个是undefined,那么相等
2)如果一个是字符串,一个是数值,把字符串转换成数值之后再进行比较
三等号===:
(1)如果类型不同,就一定不相等
(2)如果两个都是数值,并且是同一个值,那么相等;如果其中至少一个是NaN,那么不相等。(判断一个值是否是NaN,只能使用isNaN( ) 来判断)
(3)如果两个都是字符串,每个位置的字符都一样,那么相等,否则不相等。
(4)如果两个值都是true,或是false,那么相等
(5)如果两个值都引用同一个对象或是函数,那么相等,否则不相等
(6)如果两个值都是null,或是undefined,那么相等
33.http请求方法有哪些
什么是HTTP?
HTTP,即超文本传输协议,是一种实现客户端和服务器之间通信的响应协议,它是用作客户端和服务器之间的请求。
客户端(浏览器)会向服务器提交HTTP请求;然后服务器向客户端返回响应;其中响应包含有关请求的状态信息,还可能包含请求的内容。
HTTP的常用方法
1、GET方法
GET方法用于使用给定的URI从给定服务器中检索信息,即从指定资源中请求数据。使用GET方法的请求应该只是检索数据,并且不应对数据产生其他影响。
在GET请求的URL中发送查询字符串(名称/值对),需要这样写:
/test/demo_form.php?name1=value1&name2=value2
说明:
GET请求是可以缓存的,我们可以从浏览器历史记录中查找到GET请求,还可以把它收藏到书签中;且GET请求有长度限制,仅用于请求数据(不修改)。
注:因GET请求的不安全性,在处理敏感数据时,绝不可以使用GET请求。
2、POST方法
POST方法用于将数据发送到服务器以创建或更新资源,它要求服务器确认请求中包含的内容作为由URI区分的Web资源的另一个下属。
POST请求永远不会被缓存,且对数据长度没有限制;我们无法从浏览器历史记录中查找到POST请求。
3、HEAD方法
HEAD方法与GET方法相同,但没有响应体,仅传输状态行和标题部分。这对于恢复相应头部编写的元数据非常有用,而无需传输整个内容。
4、PUT方法
PUT方法用于将数据发送到服务器以创建或更新资源,它可以用上传的内容替换目标资源中的所有当前内容。
它会将包含的元素放在所提供的URI下,如果URI指示的是当前资源,则会被改变。如果URI未指示当前资源,则服务器可以使用该URI创建资源。
5、DELETE方法
DELETE方法用来删除指定的资源,它会删除URI给出的目标资源的所有当前内容。
6、CONNECT方法
CONNECT方法用来建立到给定URI标识的服务器的隧道;它通过简单的TCP / IP隧道更改请求连接,通常实使用解码的HTTP代理来进行SSL编码的通信(HTTPS)。
7、OPTIONS方法
OPTIONS方法用来描述了目标资源的通信选项,会返回服务器支持预定义URL的HTTP策略。
8、TRACE方法
TRACE方法用于沿着目标资源的路径执行消息环回测试;它回应收到的请求,以便客户可以看到中间服务器进行了哪些(假设任何)进度或增量。
34.rem和em的区别
em/rem:用于做响应式页面,不过我更倾向于rem,因为em不同元素的参照物不一样(都是该元素父元素),所以在计算的时候不方便,相比之下rem就只有一个参照物(html元素),这样计算起来更清晰。
rem 和 em 都是相对单位,主要参考的标签不同:
rem 是相对于根字号,即相对于<html>标签的 font-size 实现的,浏览
器默认字号是 font-size:16px
em:是相对于父元素标签的字号,和百分比%类似,%也是相对于父级的, 只不过是%相对于父级宽度的,而 em 相对于父级字号的
35.实现一个div上下左右居中的三种方法
第一种:定位:
第一种思路:通过给 div 设置绝对定位,并且left,right,top,bottom 设置为 0,margin:auto 即可以水平垂直居中
第二种思路:通过给 div 设置绝对定位,left 为 50%,top 为 50%,再给 div 设置距左是自身的一半即:margin-left:自身宽度/2,margin-top:自身高 度/2。
第三种思路:通过给 div 设置绝对定位,left 为 50%,top 为 50%,再给 div 设置跨左和跟上是自身的一半:transform:translate3d(-50%,-50%,0)
第四种:flex 布局:
思路:有两个div,父级div和子级div,给父级div设置display:flex, 并且设置父级 div 的水平居中 justify-content:center,并且给父级 div 设置 垂直居中 align-items:center
第五种:使用varticle-align属性
理念:
利用表格单元格的居中属性。
步骤:
(1)父div外层配置一个div,同时设置为表格元素 (display: table),宽度为400px。
(2)父div配置为表格单元格元素 (display: table-cell)。
(3)父div配置居中属性(vertical-align: middle),使子div上下居中。
(4)子div通过margin配置左右居中(margin-left:auto; margin-right:auto)。
36.v-for和v-if的区别
当 v-if 与 v-for 一起使用时, v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中 当它们处于同一节点, v-for 的优先级比 v-if 更高,这意味着 v-if 将分别重复运行于每个 v-for 循环中。 当你想为仅有的 一些 项渲染节点时,这种优先级的机制会十分有用,如下: 上面的代码只传递了未完成的 todos。 而如果你的目的是有条件地跳过循环的执行,那么可以将 v-if 置于外层元素 (或 <template> )上。 如: 面试官:为什么 Vue 中的 v-if 和 v-for 不建议 一起 用? 一、作用 v-if 指令用于条件性地渲染一块内容。
37.router传参的方式
第一种:使用router的name属性也就是params来传递参数
这个方法有一个bug就是当你传参过去的时候,再次刷新页面时参数就会丢失。解决方法下边会说到。
step:1,首先需要在router/index.js里边配置每个页面的路径,name属性,看例子:
import Vue from 'vue'
import Router from 'vue-router'
const _import = require('./_import_' + process.env.NODE_ENV)
Vue.use(Router)
export const constantRouterMap = [{
path: '/login/:userId/:id',
name:'Message', //就是要在路由配置里边配置这个属性,用来知道你要跳转到那个页面的名字
/***
* 如果想做到页面刷新,参数不丢失,就必须在path后面加上这个参数
* 但是这样做的话就会导致参数显示在url的后面,(在这一点上)跟query没什么区别了。
* 多个参数也可以一直往后边追加
*/
component: _import('login/index'),
hidden: true
},
{
path: '',
component: Layout,
redirect: 'dashboard',
icon: 'dashboard',
hidden: true,
noDropDown: true,
children: [{
path: 'dashboard',
name: '首页',
component: _import('main/index'),
meta: {
title: 'dashboard',
icon: 'dashboard',
noCache: true
}
}]
}
]
export default new Router({
routes: constantRouterMap
})
step:2,在传值页面的写法:
//用这种方法传参,必须这么些,不能写path,否则你在取参数的时候this.$router.params.userId就是undefined.这是因为,params只能用name来引入路由,
this.$router.push({
name:"'Message'",//这个name就是你刚刚配置在router里边的name
params:{
userId:"10011"
}
})
step:3,在取值页面的写法:
切记,再取参数的时候一定是this.route 不是 this.router,切记。
this.$route.params.userId
第二种:使用query来传递参数
step:1,在传值页面的写法:
this.$router.push({
path:"/login",//这个path就是你在router/index.js里边配置的路径
query:{
userId:"10011"
}
})
step:2,在取值页面的写法:
第一种:
this.$router.currentRoute.query.userId
第二种:
这种方法再取参数的时候一定是this.$route 不是 this.$router,切记。
this.$route.query.userId
第三种:使用vue里的<router-link>标签来传递参数
step:1,在传值页面的写法:
<router-link target="_blank"
:to="{path:'/login',query:{userId: "33333"}}">
</router-link>
step:2,在取值页面的写法:同第二种。
其实,router-link也可以使用name的方法传参
同样,这种方法也需要在router/index.js里边配置每个页面的路径,name属性
name:'Message', //就是要在路由配置里边配置这个属性,用来知道你要跳转到那个页面的名字
<router-link :to="{name:''Message'',params:{userId:'1234'}}">Hi页面1</router-link>
取参方法:
this.$route.params.userId
38.v-if和v-show的区别
v-if 和 v-show 都可以显示和隐藏一个元素,但有本质区别
v-if:根据表达式的值的真假条件渲染元素。在切换时元素及它的数据绑定组件被销毁并重建。它是惰性的,只是值为 false 就不会加载对应元素,为 true 才动态加 载对应元素
v-show:是无论为 true 和为 false 都会加载对应 html 代码,但为 false 时用 display:none 隐藏不在页面显示,但为 true 时页面上用 display:block 显示其效果
适用场景:切换频繁的场合用 v-show,切换不频繁的场合用 v-if
39.url输入到地址栏后发生了什么
DOM 树 构建一个样式表.组合成一颗 render 树,页面经过重绘(重塑)和回流 的过程.
- DNS 解析
- TCP 连接
- 发送 HTTP 请求
- 服务器处理请求并返回需要的数据
- 浏览器解析渲染页面
- 连接结束 输入了一个域名,域名要通过 DNS 解析找到这个域名对应的服务器地址(ip),通过 TCP 请求链接服务,通过 WEB 服务器(apache)返回数据,浏览器根据返回数据构建 DOM 树,再把 css 形成一个样式表.这两个东西结合,变成了 render 树.页面上通过重绘和回流的过程,渲 染出页面来
40.Number和parseInt的区别
Number()可以用于任何数据类型转换成数值;parseInt()用于将字符串转换成数值
Number() 和 parseInt() 对比的一张表
| 值 | Number() | parseInt() |
|---|---|---|
| '' | 0 | NaN |
| true/false | 1/0 | NaN |
| '0123' | 123 | 123 |
| '123x' | NaN | 123 |
| 'x123' | NaN | NaN |
| '01.1' | 1.1 | 1 |
parseInt() 还有第二个参数
第二个参数用于指定转换时,转换成多少进制(如2进制、8进制、10进制、16进制 等等),默认为10进制。
41.axios的封装有哪一些
http 封装
原文点此 http 封装,其实就是实例化一个 axios 对象,并对其进行一些配置:
- 设置请求超时
- post 头设置
- 请求拦截
- 响应拦截
- 重复请求取消(这里涉及到了如何取消请求)
- 错误处理
- 断网处理
- 工具函数
api 封装
api 封装,主要是用于单个模块所需要的接口进行管理。其中包括了
- 总 api 接口的映射
- 环境变量的切换
- 本地 mock 的功能
- 单个模块的接口列表
42.vueRouter的原理
vue-router的作用就是通过改变URL,在不重新请求页面的情况下,更新页面视图。 简单的说就是,虽然地址栏的地址改变了,但是并不是一个全新的页面,而是之前的页面某些部分进行了修改。
结语
以上就是我自己以及参考某些博主的博客总结的一些关于前端的一些面试问题,有什么不懂得可以私信或打在评论区都可以喔!