前端面经高频考点

文章目录

    • HTML
    • 1、高频1之行内元素、块级元素、行内块元素的区别
    • 2、高频2之script标签中defer和async的区别
    • 3、src和href的区别
    • 4、lable的作用
    • 5、ifram的使用以及有优缺点
    • 6、img的srcset属性
    • 7、head标签的作用
    • 8、对HTML语义化的理解
    • 9、文档类型的作用
    • 10、meta标签的作用
    • 11、HTML5有哪些更新
    • 12、svg和canvas之间的区别
    • 13、常见的drag api
    • 14、HTML5的离线存储(应用程序缓存)
    • 15、title和h1、strong和b、em和i的区别
    • 16、浏览器乱码
    • 17、浏览器的渐进增强和优雅降级
    • 18、前端存储的方式
    • 19、web worker
    • CSS
    • 1、高频1之说一下你认知的定位
    • 2、高频2之浮动
    • 3、高频3之margin合并的问题
    • 4、高频4之BFC布局
    • 5、高频5之如何进行移动端的适配
    • 6、高频5之display float 和 position之间的关系
    • 7、水平垂直居中的实现
    • 8、两栏布局的实现
    • 9、三栏布局的实现
    • 8、flex布局的理解以及应用场景
    • 10、对盒子模型的理解
    • JS
    • js对象属性和描述符object.defineproperty以及proxy
    • 1、ES6有哪些新特性
    • 1.1、var let const的区别
    • 1.2、const对象的属性可以更改吗
    • 1.3、可以new一个箭头函数吗
    • 1.4、箭头函数和普通函数有什么区别?
    • 1.5、箭头函数的this指向哪里?
    • 1.6、对象和数组的解构
    • 1.7、rest参数的理解
    • 5、JS循环事件、微任务宏任务
    • 6、
    • VUE
    • 1、vue的基本原理
    • 2、双向绑定的原理
    • 3、MVVM MVC MVP分别是什么?
    • 4、computed watcher methods的区别
    • 5、slot是什么?有什么作用?原理是什么?
    • 6、过滤器是什么 有什么作用?
    • 7、如何保存页面的当前状态?
    • 8、常见的事件修饰符
    • 9、v-if和v-show的区别
    • 10、data为什么是一个函数而不是一个对象?
    • 11、keep-alive的理解
    • 计算机网络和浏览器相关的
    • 1、浏览器安全(6.28)
    • 手写代码篇
    • 1、new操作符(6.28)
    • 2、改变函数的this指向的call方法(6.28)
    • 3、改变函数的this指向的apply方法(6.28)
    • 4、改变函数的this指向的bind方法(6.28)
    • 5、图片的懒加载(6.28)
    • 平时学习相关的
    • 1、代码怎么debug
    • 2、代码怎么存放
    • 3、怎么学的前端

HTML

1、高频1之行内元素、块级元素、行内块元素的区别

设置方式:display:block(块级元素)/inline(行内元素)/inline-block(行内块元素)
块级元素:div p h1-h6 ol ul li dl dt dd
行内元素:span a img strong(b) em(i) input select textarea
空元素:没有内容的HTML元素,即没有闭合标签。比如:meta link img input br
区别:块级元素独占一行,另一个块级元素是独占一行,可以设置width height padding margin。行内元素:不会独占一行,多个行内元素是呈现水平排列的,设置width height无效,只能设置水平方向的padding margin,不能设置垂直方向的padding margin。行内块元素:既有块级元素的特点,也有行内元素的特点,可以设置width height padding margin也可以一行放多个元素。

2、高频2之script标签中defer和async的区别

如果没有defer和async属性的话,当解析到script标签的时候,会停止对后续文档的加载,转去加载和执行script对应的脚本文档,这样的话,会阻塞后续文档的加载。加了defer和async的话,可以实现后续文档的加载和当前文档的加载是异步执行的。
不同的是,async不能保证加载顺序,并且后续文档的加载和渲染和js脚本的加载和执行是完全异步的;defer能保证加载顺序,但是后续文档的加载与JS文档的加载是异步的,js文档的执行是要等到后续文档解析完之后再去执行的。

3、src和href的区别

相同点:都是表示对外部资源的引用,
不同点
1>、src表示对资源的引用,它所指向的内容一般会嵌入到当前元素所在的位置,当浏览器解析到该元素的时候,会停止对当前文档的加载和处理,直至对该元素加载 编译 执行完毕,所以一般情况下 js脚本的引用会被放在最后边。
2>、href表示超文本引用,一般指向网络资源,用来建立当前文本和所指向资源的一一对应关系。当浏览器解析到该元素的时候会并行处理该元素和当前文档资源。

4、lable的作用

用来定义表单控件的,当用户点击lable标签的时候浏览器自动聚焦到与lable绑定的表单控件上。
实例:

//使用方法一:
<label for="shixue">请输入您的姓名:</label>
<input type="text" id="shixue">
//使用方法二:
<label for="shikai">date: <input type="text" id="shikai"></label>

5、ifram的使用以及有优缺点

ifram元素是一个创建包含另一个文档的内联框架。
常见属性:src height width scrolling(是否有滚动条) IframBorder(是否有边框0是没有 1是有) allowTransparency(是否允许透明)等
优点:
实现跨域通信,实现js脚本的并行加载,用来加载速度较慢的广告
缺点:
会阻塞主页面的onload 事件,产生多个页面,不容易管理。

<iframe src="https://www.baidu.com/" frameborder="0" allowfullscreen="true" width="500px" height="500px" allowTransparency="true" scrolling="no"></iframe>

6、img的srcset属性

作用:响应式页面中会根据不同的屏幕密度选择不同的图片,需要用srcset属性来设置。

<img src="image-128.png" srcset="image-256.png 2x" />

解析:在屏幕密度为 1x 的时候,采用图片 image-128.png,当屏幕密度为 2x 的时候采用图片 image-256.png,但是屏幕密度有 1x 2x 3x 4x,如果给每一张图片都设置四张的话,会增加服务器的加载负担,所以有了下边的 srcset 使用

<img src="image-128.png"
     srcset="image-128.png 128w, image-256.png 256w, image-512.png 512w"
     sizes="(max-width: 360px) 340px, 128px" />

w为图片质量,当可视区域小于图片质量值的时候,就采用该图片,浏览器会优先选择一张最小的图片。sizes表示图片的临界尺寸,默认情况下是128px,当可视区宽度大于360px的时候,采用 340px的尺寸。

7、head标签的作用

作用:定义文档的头部,描述文档的各种属性和信息。
有哪些:script link meta title style base(比如a标签没有href属性的话默认情况下会使用base里边的内容)
哪些必不可少: title

8、对HTML语义化的理解

就是根据内容的结构化来选择合适的标签,就是用正确的标签做正确的事情。
优点:对开发者友好,能够清晰代码结构,增强代码的可读性。
常见的语义标签有

标签 语义
header 头部
nav 导航栏
aside 侧边栏
section 区块,有语义的div
footer 底部
main 主要区域
article 主要内容

9、文档类型的作用

DOCTYPE:是一个文档类型声明,告诉浏览器当前的文档是以哪个版本的HTML文档写的,这样的话浏览器才能正确的解析执行该文档,模式设置通过document.compatMode,有两种模式CSS1compat和backcompat
CSS1compat:是标准模式,默认模式,是指浏览器按照w3c标准来解析代码。
backcompat:怪异模式或者是混杂模式,浏览器模拟老式浏览器的行为,以一种向后兼容的模式来解析代码,防止老式浏览器无法正常工作。

<!DOCTYPE html> //就是告诉浏览器文档是以HTML5编写的,以标准模式来渲染,不写或者是写错,均按照混杂模式解析。

总而言之,标准模式让各个浏览器统一执行一套兼容模式,保证旧网站的正常运行。

10、meta标签的作用

作用:描述网页文档的属性,一般由name和content组成。
常见属性
1>、charset 规定编码方式

<meta charset="UTF-8">

2>、浏览器渲染

<meta http-equiv="X-UA-Compatible" content="IE=edge">

告诉浏览器,IE8/9及以上版本的浏览器均以最高IE来渲染页面。http-equiv="X-UA-Compatible"是因为在刚出现IE8浏览器的时候存在页面重构问题,这句代码只对IE8有效就是告诉浏览器在这种情况下只需要在IE6/7下能正常渲染就可以了,不用管最新的IE8。
3>keywords

<meta name="keywords" content="关键词">

4>、description

<meta name="description" content="网页描述">

5>、viewport

<meta name="viewport" content="width=device-width, initial-scale=1.0">
content 含义
width device-width
height device-height
initial-scale 初始缩放
maximum-scale 最大缩放
minimum-scale 最小缩放
user-scalable 用户自己缩放 yes/no

6>、robots搜索引擎索引方式

content 含义
all 文件被检索,链接可以被查询
none 文件不允许被检索,链接不允许被查询
index 文件允许被检索
noindex 文件不允许被检索
follow 链接允许被查询
nofollow 链接不允许被查询

11、HTML5有哪些更新

1、语义化标签
header nav aside footer section main article
2、媒体标签
视频标签:video

属性 含义
src 视频路径
controls 向用户展示播放控件
autoplay 自动播放
loop 循环播放
muted 静音播放
poster 视频未加载时显示的图片,即第一帧的画面
<video src="mi.mp4" controls autoplay loop=true” poster="th.jpg"></video>

音频标签:audio

属性 含义
src 音频指定来源
controls 向用户展示播放控件
autoplay 自动播放
muted 静音播放
loop 循环播放
<audio src="muscic.mp3" controls autoplay loop="true"></audio>

兼容不同的浏览器指定文件来源标签:source

<video   controls muted autoplay='autoplay'>
        <source src="mi.mp4" type="video/mp4">
</video>
<audio  controls autoplay="autoplay" muted loop="true">
        <source src="music.mp3" type="audio/mp3">
</audio>

实现的效果和上边一样
3、新增input表单类型和属性
input表单类型

<form action="www.baidu.com">
        邮箱:<input type="email"> 
        url: <input type="url">
        数字:<input type="number">
        手机号码:<input type="tel">
        颜色:<input type="color">
        搜索框:<input type="search">
        提交:<input type="submit">
        时间(时分秒)<input type="time">
        日期(年月日)<input type="date">
        日期时间控件:<input type="datetime-local">
        周:<input type="week">
        月:<input type="mouth">
</form>

下边是关于时间的控件
在这里插入图片描述

点击提交的时候必须按照正确的表单类型写才能提交成功。否则的话,提示提交失败。
input表单属性

<form action="www.baidu.com">
        搜索:<input type="search" placeholder="请输入搜索内容" required autocomplete="on">
        提交文件:<input type="file" multiple>
        提交:<input type="submit">
</form>
属性 含义
placeholder 默认显示内容
required 字段不能为空
autocomplete 默认显示搜索记录,设置为off关掉
multiple 可以提交多文件
pattern 写入想要的正则表达式如 pattern=“/^(+86)?d{10}$/”

表单事件
oninput:表单内容每改变一下就触发该事件
oninvalid:当验证不通过时触发此事件

4、进度条

<body>
    下载进度:
    <progress value="22" max="100"></progress> //max表示总任务数,value表示当前执行的任务数
</body>

5、度量器
用于显示剩余容量或内存

<body>
    <meter min="0" max="1" low="0.3" high="0.8" optimum="0.2" value="0.9"></meter>
</body>

度量器效果:
在这里插入图片描述

参数值有6个,
前端面经高频考点_第1张图片
6、DOM的查询操作

<script>
        document.querySelector()
        document.querySelectorAll()
</script>

后边可以跟标签,类名(加 .),id名(加 #)
7、Web存储
新增了在客户端的数据存储,包括localStroge和sessionSrtoge。
localStrog:没有时间的存储
sessionSrtoge:临时的session存储,关闭浏览器就释放数据的存储。

<script>
        localStorage.setItem(key, value)
        localStorage.getItem(key, value)
        localStorage.removeItem(key, value)
    </script>

8、HTML5 API
1、canvas
定义:使用JS在网页上绘制图像
1>、绘制矩形

<canvas id="myCanvas" width="200" height="100" style="border:1px solid #000000;">绘制的第一个画布</canvas>
<script> 
var c=document.getElementById("myCanvas"); //获取该元素
var ctx=c.getContext("2d"); //创建该元素的内置H5对象
ctx.fillStyle="#FF0000"; //矩形的颜色
ctx.fillRect(0,0,150,75); //矩形的起始位置 0 0,大小150*75
</script>

2>、绘制线条

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.moveTo(0,0); //线条的起始位置
ctx.lineTo(200,100); //线条的终止位置
ctx.stroke(); //开始绘制

3>、绘制圆形


var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.beginPath();
ctx.arc(95,50,40,0,2*Math.PI); //圆心角的x坐标 圆心角的Y坐标 半径 起始角度 终止角度
ctx.stroke(); //绘制图形

4>、绘制实心文本

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
ctx.font="30px Arial";
ctx.fillText("Hello World",20,100); //包括绘制的文本内容 起始的x坐标 终止的y坐标 strokeText绘制的是空心文本

5>、绘制线性渐变图形

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
 
// 创建渐变
var grd=ctx.createLinearGradient(0,0,200,0); //起始 x y终止 x y的坐标
grd.addColorStop(0,"red");
grd.addColorStop(1,"white");
 
// 填充渐变
ctx.fillStyle=grd;
ctx.fillRect(10,10,150,80); //起始x 起始y 绘制的图形大小150*80

6>、径向渐变


var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
 
// 创建渐变
var grd=ctx.createRadialGradient(75,50,5,90,60,100);
grd.addColorStop(0,"red");
grd.addColorStop(1,"white");
 
// 填充渐变
ctx.fillStyle=grd;
ctx.fillRect(10,10,150,80);

7>、把一幅图片放在canvas中

var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("scream");
ctx.drawImage(img,10,10);

2、SVG
可伸缩矢量图形

<svg xmlns="http://www.w3.org/2000/svg" version="1.1" height="190">
<polygon points="100,10 40,180 190,60 10,60 160,180" style="fill:lime;stroke:purple;stroke-width:5;fill-rule:evenodd;"> //polygon是用来绘制折线的 points代表绘制端点,x与y之间用逗号隔开,点与点之间用空格隔开
</svg>

3、拖放

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8"> 
<title>菜鸟教程(runoob.com)</title>
<style type="text/css">
#div1 {width:350px;height:70px;padding:10px;border:1px solid #aaaaaa;}
</style>
<script>
function allowDrop(ev)
{
    ev.preventDefault();
}
 
function drag(ev)
{
    ev.dataTransfer.setData("Text",ev.target.id);
}
 
function drop(ev)
{
    ev.preventDefault();
    var data=ev.dataTransfer.getData("Text");
    ev.target.appendChild(document.getElementById(data));
}
</script>
</head>
<body>
 
<p>拖动 RUNOOB.COM 图片到矩形框中:</p>
 
<div id="div1" ondrop="drop(event)" ondragover="allowDrop(event)"></div>
<br>
<img loading="lazy" id="drag1" src="/images/logo.png" draggable="true" ondragstart="drag(event)" width="336" height="69">
 
</body>
</html>

12、svg和canvas之间的区别

canvas是一个画布。用JS来在页面中绘制2D图形,Canvas 是逐像素进行渲染的。在 canvas 中,一旦图形被绘制完成,它就不会继续得到浏览器的关注。如果其位置发生变化,那么整个场景也需要重新绘制,适合大型游戏的开发。
svg:可伸缩矢量图形,是一种xml格式的2d图形的语言。svg的任何DOM元素都是可用的,支持事件处理函数,svg绘制的每一个图形都是对象,如果对象属性发生变化,浏览器会进行重新绘制,适用于有大型渲染页面的情况,比如谷歌地图,不适合做游戏开发,因为游戏开发中有频繁重绘的情况。图形在元素改变尺寸或者是放大的时候不会失真。

13、常见的drag api

drag:事件主体是被拖放元素,在被拖放元素开始拖放的时候触发。
dragstart:事件主体是被拖放元素,被拖放元素开始移动的时候触发。
dragenter:事件主体是目标元素,被拖放元素进入目标元素时触发。
dragover:事件主体是目标元素,被拖放元素在目标元素内移动的时候触发。
dragleave:事件主体是目标元素,被拖放元素在目标元素内离开的时候触发。
drop:事件主体是目标元素,目标元素完全接受被拖放元素的时候触发。
dragend:事件主体是被拖放元素,在整个拖放过程结束的时候触发。

14、HTML5的离线存储(应用程序缓存)

定义:当用户没有与互联网连接的情况下,可以正常显示网页内容。
原理:HTML5的manifest文件缓存机制,通过解析manifest文件清单,把资源缓存到本地,这样当处于离线状态下,会用本地资源来展示网页。
使用方法:
1、在html标签中通过manifest属性引入一个同源同名的appache文件
2、在manifest文件中编写cache(需要缓存的资源) network(必须在联网的情况下才会请求的资源) fallback(替代资源,必须和manifest文件同源)等内容
3、离线状态下通过window.applicationCache进行缓存操作
如何更新缓存:
1、更新manifest文件
2、清空浏览器缓存
优点:
1、提升请求速度
2、减少浏览器负载
3、可以离线浏览
注意事项
1、浏览器对数据缓存的限制可能不太一样,有些浏览器的限制是每个站点5MB
2、引用manifest文件的HTML文件必须和manifest文件同源
3、fallback中的资源必须和manifest文件同源
4、当manifest文件更新的时候,资源请求本身也会发生更新
5、站点中的其他页面即使没有manifest属性,但是如果缓存过,也会请求缓存中的资源。
6、浏览器更新缓存的唯一方法就是更新manifest文件,即使是服务器被更新也还是会展示原来缓存的内容。
浏览器如何对缓存资源进行管理的呢?
离线状况下,会直接请求缓存资源进行展示。
在线状况下,浏览器会先看HTML标签是否有manifest属性,有的话,就去请求缓存资源,如果是第一次加载页面就会根据manifest文件的清单缓存资源,如果不是第一次就会请求缓存资源加载页面,然后对比新旧manifest文件,如果manifest文件发生改变,就会对新的manifest文件对应的资源进行缓存。

15、title和h1、strong和b、em和i的区别

title是文章的标题,h1-h6有明显的层次感。
strong:表示对文本内容的强调,只不过对文本内容的强调是通过加粗展示的;b是单纯的样式的加粗。
em:表示对文本内容的强调,只不过是通过斜体展示强调内容的;i是单纯的样式的倾斜。

16、浏览器乱码

浏览器的网页源码是gbk编码,但是内容的中文字是UTF-8编码,反之也是;
浏览器的网页源码是gbk编码,但是数据库中调出呈现是UTF-8编码的内容;
浏览器不能自动检测网页编码。
解决方法:
1、针对第一个采用编译软件进行编码;
2、对于第二个,在数据库呈现数据之前先进行数据转码;
3、针对第三个,在浏览器中找到转换编码的菜单进行转换。

17、浏览器的渐进增强和优雅降级

渐进增强:首先针对低版本的浏览器进行重构,在保证基本的内容展示正确的前提之下,在针对高级浏览器进行效果,交互功能的追加,增强用户体验。
优雅降级:一开始就针对高版本的浏览器,然后对低版本的浏览器进行兼容处理。
合理的设计范例:渐进增强,内容永远最重要。

18、前端存储的方式

1、localstroge: HTML5加入的以键值对形式存储的主要方式,优点是操作方便,永久性存储,大小为5M
保存数据:localStorage.setItem(key,value);
读取数据:localStorage.getItem(key);
删除单个数据:localStorage.removeItem(key);
删除所有数据:localStorage.clear();
得到某个索引的key:localStorage.key(index);
**localStorage:**用于长期存储浏览器数据,即使是页面关闭之后在打开也仍是会存储之前的信息。
基本实现:

<!DOCTYPE html>
<html>
<body>

<div id="result"></div>

<script>
// 首先检查浏览器版本是否支持 storage
if (typeof(Storage) !== "undefined") {
    // 保存数据 以键值对的形式
    localStorage.setItem("lastname", "Gates");
    // Retrieve
    document.getElementById("result").innerHTML = localStorage.getItem("lastname");
} else {
    document.getElementById("result").innerHTML = "抱歉!您的浏览器不支持 Web Storage ...";
}
</script>
</body>
</html>

实现效果:把lastname的值Gates显示在网页中
前端面经高频考点_第2张图片
下边实现用一个localStroge实现计数:当再次打开浏览器页面的时候,clickcount从上一次页面的计数开始计数

<body>
    <p>点击下边的按钮实现计数</p>
    <button onclick="clickcount()">按钮</button>
    <div class="result"></div>
    <script>
        function clickcount() {
            if(typeof(Storage) !== 'undefined') {
                if(localStorage.clickcount) {
                    localStorage.clickcount = Number(localStorage.clickcount) + 1
                } else {
                    localStorage.clickcount = 1
                }
                document.querySelector('.result').innerHTML = '当前计数:' + localStorage.clickcount
            } else {
                document.querySelector('.result').innerHTML = '您的浏览器版本不支持'
            }
        }
    </script>
</body>

2、sessionStroge:效果和localStroge一样,但是当页面关闭的时候后台会被清理
案例:下边实现用一个sessionStroge实现计数:当再次打开该浏览器页面的时候,原来的clickcount从0开始

<body>
    <p>点击下边的按钮实现计数</p>
    <button onclick="clickcount()">按钮</button>
    <div class="result"></div>
    <script>
        function clickcount() {
            if(typeof(Storage) !== 'undefined') {
                if(sessionStorage.clickcount) {
                    sessionStorage.clickcount = Number(sessionStorage.clickcount) + 1
                } else {
                    sessionStorage.clickcount = 1
                }
                document.querySelector('.result').innerHTML = '当前计数:' + sessionStorage.clickcount
            } else {
                document.querySelector('.result').innerHTML = '您的浏览器版本不支持'
            }
        }
    </script>
</body>

3、cookie:HTML5之前主流的本地存储的方式,优点是兼容性好,请求头自带cookie方便,缺点是大小只有4k,并且每个domain限制20个cookie

19、web worker

在HTML页面中执行脚本的时候页面是不可相应的直到脚本执行完毕,页面才变成可响应,webworker是在后台运行的js,独立于其他脚本不会影响页面性能,并且通过postmassage把结果回传到主线程,这样在进行复杂操作的时候就不会阻塞主线程了。
原理:当前的JS叫做主线程,会导致页面停止响应;创建一个webworker对象,当做子线程,通过postMessage将结果返回到主线程,不会导致主线程的阻塞,把复杂的运算挪到子线程来执行。
我做过的demo就是下边这个,在子线程中创建一个计数函数,通过postMessage把i的值返回给主线程,当主线程中点击webworker开始工作的按钮的时候,浏览器页面开始计数;但是这个时候主线程中地input输入框仍然可以正常输入,我认为本质上来讲就是支持我们把数据刷新和页面渲染分开来实现。

//主线程
<!DOCTYPE html>
<html>
<body>
<p>Count numbers: <output id="result"></output></p>
<button onclick="startWorker()">Start Worker</button>
<button onclick="stopWorker()">Stop Worker</button>
<input type="text" value=""/>
<script>
var w;
function startWorker () {
	//首先检查浏览器版本是否支持 worker
  if (typeof(Worker) !== "undefined") {
    if (typeof(w) === "undefined") {
      w = new Worker("demo_workers.js");
    }
    //接收从子线程传过来的数据
    w.onmessage = function (event) {
      document.getElementById("result").innerHTML = event.data;
    };
  } else {
    document.getElementById("result").innerHTML = "Sorry, your browser does not support Web Workers...";
  }
}

function stopWorker () {
  w.terminate();
}
</script>
</body>
</html>

子线程 就是demo_workers.js中的代码

function timedCount () {
  for (var i = 0; i < 10000000000; i++) {
    if (i % 100000 === 0) {
      postMessage(i);
    }
  }
}
timedCount();

实现效果:在页面不断更新i的值的时候,还可以实现input的输入。
前端面经高频考点_第3张图片

CSS

1、高频1之说一下你认知的定位

定位的作用:定位是把某一个元素固定到屏幕的某一个位置并且可以压住下边的盒子的所有内容。
常见的定位属性有relative absolute fixed sticky这四个。
relative:相对定位;是相对于自身而言的;移动后仍然占据原来的位置,不会脱标。
absolute:绝对定位;是相对于上一级带有定位的父级元素而言的,如果父级元素没有定位以浏览器为准,如果父级元素有定位,那就相对于最近的一个带有定位的父级元素而言;移动后不再占据原来的位置,会脱标(所以就不会触发外边距合并的问题);会变成一个行内块元素;在浏览器页面滚动时会滚动;常见的用法就是子绝父相,实例是实现遮罩层。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>土豆网遮罩层</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }
        .tudou {
            position: relative;
            width: 444px;
            height: 320px;
            margin: 30px auto;
        }
        .tudou img {
            width: 100%;
            height: 100%;
        }
        .mask {
            display: none;
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0,0, 0, 0.4) url(images/arr.png) no-repeat center;
        }
        .tudou:hover .mask {
            display: block;
        }
    </style>
</head>
<body>
    <div class="tudou">
        <div class="mask"></div>
        <img src="images/tudou.jpg" alt="">
    </div>
    <div class="tudou">
        <div class="mask"></div>
        <img src="images/tudou.jpg" alt="">
    </div>
</body>
</html>

加了绝对定位的盒子margin: 0 auto无效,应该如何设置让子元素处于父元素中间的位置

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>浏览器右侧导航栏固定不动</title>
    <style>
        .w {
            position: absolute;
            width: 300px;
            height: 300px;
            background-color: purple;
            left: 50%;
            margin-left: -150px;
            top: 50%;
            margin-top: -150px;
        }
        .father {
            position: relative;
            margin: 0 auto;
            width: 600px;
            height: 600px;
            background-color: red;
        }
    </style>
</head>
<body>
    <div class="father">
        <div class="w">版心盒子</div>
    </div> 
</body>
</html>

fixed:固定定位;是相对于浏览器而言的;移动后不再占据原来的位置会脱标(所以就不会触发外边距合并的问题;当浏览器页面滚动的时候,它不会滚动;常见用法:让固定定位的盒子永远沿着版心右侧显示。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>浏览器右侧导航栏固定不动</title>
    <style>
        .w {
            width: 400px;
            height: 1600px;
            background-color: red;
            margin: 0 auto;
        }
        .fixed {
            position: fixed;
            width: 100px;
            height: 100px;
            background-color: purple;
            left: 50%;
            margin-left: 200px;
        }
    </style>
</head>
<body>
    <div class="fixed"></div>
    <!-- 一定把固定盒子的位置放在前边,如果把版新盒子放在前边的话,可能会出现w盒子压住下边的 -->
    <div class="w">版心盒子</div>
</body>
</html>

sticky:粘性定位;以浏览器的可视窗口为准;移动后仍然占据原来的位置不会脱标;常见用法:先把某个盒子放到右下角,拉动滚轮时往上走,但是走到某一个top值的时候就不走了,在走到之前呈现相对定位,走到之后呈现固定定位。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>粘性定位</title>
    <style>
        body {
            height: 4000px;
        }
        .nav {
            position: sticky;
            top: 0;
            width: 800px;
            height: 50px;
            background-color: pink;
            margin: 100px auto;
            font-size: 20px;
        }
    </style>
</head>
<body>
    <div class="nav">我是导航栏</div>
</body>
</html>
//实现效果:刚开始的时候,盒子在`margin: 100px auto`的位置,之后滚动页面到达设定值 `top: 0`的时候就固定在这里了。

定位为relative absolute fixed的元素有一个叠放次序:z-index,可以设置盒子距离浏览器页面的顺序,数字越大越靠近浏览器页面。什么情况下会失效?
1>、父元素的position:relative的时候,子元素的z-index会失效,解决方法就是将父元素的position改成absolute或者是static。
2>、该元素没有设置那三个定位属性
3>、该元素既设置了z-index又设置了浮动,解决方法:清除浮动,设置display:inline-block。
absolute和fixed的相同点与不同点
相同点:都会脱标;都变成行内块元素;都会压住下边的所有内容。
不同点:absolute相对于有定位的父元素,fixed相对于浏览器窗口;在页面滚动的时候,absolute会跟着滚动但是fixed不会跟着滚动。

2、高频2之浮动

为什么设置浮动:改变元素默认标签的排列方式,比如让两个块级元素的盒子一行内显示。
属性值:left right none
浮动元素的特性:脱离标准流(所以不会有外边距合并的问题);浮动元素有行内块元素的特性;如果块级盒子未设置浮动那么他的默认宽度是和父亲一样宽,加了浮动之后宽度是由内容决定的。
为什么清除浮动:因为父级元素没有高度,子元素浮动了,影响后边的布局了。
清除浮动的方式:伪元素法:只要是子盒子浮动了,不管父盒子有没有给高度,都加上这个属性来清除浮动。

.clear::after{
  content:'';
  display: block; 
  clear:both;
}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>为什么需要清除浮动</title>
    <!-- 因为
    1、有些情况下,父盒子不能给高度,得根据里边的内容来调整
    2、添加了浮动的盒子。不占有原来的位置,会导致后续的排版出现错误。 -->
    <style>
        .box {
            width: 700px;
            background-color: pink;
        }
        .damao {
            width: 200px;
            height: 200px;
            background-color: red;
            float: left;
        }
        .ermao {
            width: 200px;
            height: 300px;
            background-color: purple;
            float: left;
        }
        .putongliu {
            width: 800px;
            height: 300px;
            background-color:black;
        }
        .clearfix:after {
            content: "";
            display: block;
            clear: both;
        }
    </style>
</head>
<body>
    <div class="box clearfix">
        <div class="damao">大毛</div>
        <div class="ermao">二毛</div>
    </div>
    <div class="putongliu">hahha</div>
</body>
</html>

使用clear属性清除浮动元素的原理
clear: 官方解释,元素盒子的边不能和前边的浮动元素相邻,设置clear属性是为了避免浮动元素对该元素造成的影响,而不是清除掉浮动。考虑到float属性要么是 left 要么是 right,不可能同时存在,并且clear对后边的元素不闻不问,所以当float left有效的时候right必定无效,也就是clear: left = clear: both; clear: right = clear: both,所以在clear中clear: left clear: right 没有任何作用,所以就用clear:both来代替了,并且由于伪元素属于内联样式,然而clear只对块级元素有效,所以就用display:block转化成块级元素。

3、高频3之margin合并的问题

定义:两个上下级排列的块级元素的盒子,不管是兄弟之间还是父子之间均会产生外边距重叠的问题(脱离标准流的元素不会触发外边距合并,比如相对定位(absolute和fixed)和浮动
合并值:
如果两个都是正值,取大的那个;如果两个都是负值,取绝对值大的那个;如果一正一负,则让两个值相加。
解决方法:兄弟之间的margin问题:让下边那个盒子变成BFC(比如display: inline-block; float: left/right;position: absolute/fixed);父子之间的margin问题:父级元素加入overflow:hidden或者是让子元素变成BFC盒子。

4、高频4之BFC布局

1、定义:BFC就是一个大的布局环境。一旦一个盒子成了一个BFC的环境,他的 布局将不再受外部元素的影响。
2、触发BFC的条件
根元素:body
元素设置浮动:float:left/right
元素设置定位:position:absolute/fixed
display: inline-block
overflow: hidden/auto/scroll
3、BFC的特点
不会与浮动的元素发生重叠;不会影响外部元素的排列
4、常见作用:
解决外边距合并的问题:兄弟之间的话给下边那个兄弟一个BFC环境;父子之间的话给孩子一个BFC环境或者是给父亲一个overflow:hidden。
解决加了浮动的子元素父盒子高度塌陷的问题:给父元素 加 overflow:hidden
解决两栏盒子自适应布局的问题:左边盒子正常设置宽度,给一个左浮动;右边盒子加一个overflow:hidden,这样的话右边的盒子就变成了一个BFC环境。

.first {
            width: 200px;
            background-color: red;
            float: left;
        }
.second {
            overflow: hidden;
            background-color: green;
}

5、高频5之如何进行移动端的适配

1、流式布局
2、flex
3、rem+媒体查询
4、rem+flexable.js
5、rem+vw/vh

6、高频5之display float 和 position之间的关系

优先级最高的是 position: absolute/fixed,有它在的时候float失效,display设置成inline-block;然后元素的float属性不是none的时候或者它是根元素的时候设置display,注意有position:relative和float同时存在的情况,先按照float浮动在设置position;最后是非根元素,非浮动元素,非定位元素的时候是display的特性值等同于设定值。

7、水平垂直居中的实现

1、行内元素在父盒子中加text-align 和 line-height
2、块级元素采用position+transform:translate
3、块级元素采用position+margin-left 和 margin-top
4、块级元素采用position+margin
5、采用flex justify-content 和 align-items

8、两栏布局的实现

<div class="outer">
        <div class="left">左边</div>
        <div class="right">右边</div>
</div>

两栏布局一般指的是左边宽度固定右边实现宽度的自适应
1、利用浮动:左边给一个浮动和固定宽度x,右边给一个margin-left: x即可。

.outer {
        height: 100px;
        }
        .left {
        float: left;
        width: 200px;
        background: tomato;
        }
        .right {
        margin-left: 200px;
        background: gold;
        }

2、利用flex布局:将父元素设置一个display:flex,左边的元素给一个宽度,右边的元素设置为flex:1即可。

.outer {
  display: flex;
  height: 100px;
}
.left {
  width: 200px;
  background: tomato;
}
.right {
  flex: 1;
  background: gold;
}

3、利用定位:父元素给一个相对定位,左边的子元素给一个绝对定位和一个宽度x,右边的元素给一个margin-left:x即可。

 .outer {
        position: relative;
        height: 100px;
        }
        .left {
        position: absolute;
        width: 200px;
        background: tomato;
        }
        .right {
        margin-left: 200px;
        background: gold;
        }

4、利用定位:父元素设为相对定位,左边给一个宽度x,右边设为固定定位给一个left:x即可。

.outer {
  position: relative;
  height: 100px;
}
.left {
  width: 200px;
  background: tomato;
}
.right {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 200px;
  background: gold;
}

5、利用BFC:左边一个浮动,给右边一个overflow:hidden,变成BFC,因为BFC不会与浮动元素发生重叠。

.left{
     width: 100px;
     height: 200px;
     background: red;
     float: left;
 }
 .right{
     height: 300px;
     background: blue;
     overflow: hidden;
 }

9、三栏布局的实现

左右均固定,中间自适应宽度

<div class="outer">
        <div class="left">左边</div>
        <div class="right">右边</div>
</div>

1、利用浮动:左边左浮动右边右浮动,中间设置margin-left和margin-right

.outer {
  height: 100px;
}

.left {
  float: left;
  width: 100px;
  height: 100px;
  background: tomato;
}

.right {
  float: right;
  width: 200px;
  height: 100px;
  background: gold;
}

.center {
  height: 100px;
  margin-left: 100px;
  margin-right: 200px;
  background: lightgreen;
}

2、利用flex布局:左右两栏设置宽度,中间给一个flex

.outer {
  display: flex;
  height: 100px;
}

.left {
  width: 100px;
  background: tomato;
}

.right {
  width: 100px;
  background: gold;
}

.center {
  flex: 1;
  background: lightgreen;
}

3、利用定位:左右两边均设置固定定位,中间设置margin-left和margin-right

.outer {
  position: relative;
  height: 100px;
}

.left {
  position: absolute;
  width: 100px;
  height: 100px;
  background: tomato;
}

.right {
  position: absolute;
  top: 0;
  right: 0;
  width: 200px;
  height: 100px;
  background: gold;
}

.center {
  margin-left: 100px;
  margin-right: 200px;
  height: 100px;
  background: lightgreen;
}

8、flex布局的理解以及应用场景

flex布局是css3一种新增的布局方式,任何一个元素都可以设为flex布局,设置方式为display:flex,此时这个元素称之为容器,其下的子元素称之为项目。传统的布局方式使用于PC端,对于移动端需要适配屏幕大小来讲,需要使用flex布局。设置flex布局之后,float clear vertival-align等属性会失效。
常见的容器属性

属性 含义
flex-direction 设置主轴方向 参数有row row-reverse column column-reverse
justify-content 设置主轴元素的排列方式 常见参数有 flex-start flex-end center space-around space-between
flex-wrap 设置元素是否换行 wrap nowrap
align-items 设置侧轴的排列方式 ,这时候是单行的情况之下
align-content 设置侧轴的排列方式,多行的情况之下
flex-flow flex-direction和flex-wrap的缩写

常见的项目属性

属性 含义
flex 布局占比
align-self 可以设置自己的项目的排列方式 替代align-items
order 设置子项的排列方式 数值越小越往前
flex-grow 当项目有剩余空间时,项目的放大比例,默认是0,不放大
flex-shrink 当项目剩余空间不足时,项目的缩小比例,默认是1,缩小一半

flex:1就是flex-grow flex-shrink flex-basis的缩写,flex-basis代表的是伸缩盒子的基准值,当子项目中有这个值的时候width失效,他还有max-width和min-width两个限值,flex:1代表的是flex-grow:1 ;flex-shrink :1;flex-basis: 0%

10、对盒子模型的理解

盒子包括四个部分:content padding border margin
盒子模型有两种:标准盒子模型和IE盒子模型
标准盒子模型的宽度就是 content的宽度(默认盒子);IE盒子模型的宽度就是content+border+padding的宽度
设置方式:box-sizing: content-box(标准盒子模型)/border-box(IE盒子模型)

JS

js对象属性和描述符object.defineproperty以及proxy

object.defineproperty的基本用法:用于给对象设置属性的

let obj1 = {
            name: 'shixue'
        } 
        //JS对象有两种属性 数据属性和访问器属性 所以描述符有两种 数据描述符和访问器描述符
        //下边这个是数据描述符 值可写可不写
        Object.defineProperty(obj1, 'sex',{
            value:'女', //属性值 默认是undefined
            enumerable: true, //可枚举 就是用 for in 遍历
            configurable: true, //该属性是否可以delete 或者是属性值是否可以变化
            writable: true //属性值是否可写 默认false
        }) 
        console.log(obj1.sex);
        console.log(Object.getOwnPropertyDescriptor(obj1, 'sex'));

        //下边这个是访问器描述符 有get set  enumerable  configurable四个参数
        let obj = {
            _hello:'hello world' //表示私有变量
        };
        
        Object.defineProperty(obj,'hello',{
            get() { //访问属性时被调用
                console.log('get');
                return this._hello;
            },
            set:function (value) { //设置属性时被调用
                console.log('set');
                this._hello = value;
            }
        });
        
        console.log(obj.hello); //get hello world
        obj.hello = 'goodbye';
        console.log(obj.hello);     //先调用set属性 在调用get属性 set get goodbye


		//proxy的使用
		let obj = {
            hello:'hello world'
        };
        
        let proxy = new Proxy(obj, {
            get(target, property) {
                console.log('get');
                return target[property];
            },
            set(target,property,value) {
                console.log('set');
                target[property] = value;
            }
        });
        
        console.log(proxy.hello); //get hello world
        proxy.hello = 'goodbye';
        console.log(proxy.hello); //set get goodbye


		//数据描述符和访问器描述符不能够同时使用
        function Hello() {
            let hello = "hello world";
            Object.defineProperty(this, 'hello', {
                get(){
                    console.log('get');
                    return hello;
                },
                set(value){
                    console.log('set');
                    hello = value;
                },
                writable:true
            })
        }
        
        let hahh = new Hello(); //Type Error

1、ES6有哪些新特性

1.1、var let const的区别

前端面经高频考点_第4张图片
暂时性死区:变量必须先声明在使用,否则未定义

<script>
        var a = 10
        if(true) {
            console.log(a); //Uncaught ReferenceError: Cannot access 'a' before initialization
            let a = 10
        }
</script>

解析:变量必须先声明在使用
常见面试题

<script>
        var arr = []
        for(var i = 0; i < 2; i++) {
            arr[i] = function() {
                return i
            }
        }
        console.log(arr[0]); //2
        console.log(arr[1]); //2
</script>
<script>
        var arr = []
        for(let i = 0; i < 2; i++) {
            arr[i] = function() {
                return i
            }
        }
        console.log(arr[0]); //0
        console.log(arr[1]); //1
</script>

1.2、const对象的属性可以更改吗

const不能更改的是变量指向的内存地址,即保存的是指针,指针指向内存地址。对于简单数据类型,变量指向的是一个内存地址,数据值就保存在变量指向的内存地址,因此不能改变。但是对于复杂数据类型,比如数组和对象,变量指向的是内存地址,保存的只是一个指针,所以里边的内容是const不能控制的,即内容是可以更改的。

1.3、可以new一个箭头函数吗

不可以,new的操作过程如下:
1>、开辟一个新的内存空间
2>、执行构造函数,并且把构造函数的属性和方法赋给该对象
3>、让this指向这个新对象
4>、返回新对象
但是箭头函数没有this 没有arguments 也没有prototype,所以不能new

1.4、箭头函数和普通函数有什么区别?

1、书写更简洁,只有一个参数的时候不用写()只有一个函数体的时候不用写{}
2、没有自己的this指向,this是自己作用域链的上一层的this,并且一旦赋予不能更改

<script>
        var id = 'GLOBAL';
        var obj = {
            id: 'OBJ',
            a: function(){
                console.log(this.id); //this 指向obj
            },
            b: () => {
                console.log(this.id); //箭头函数没有自己的this 他的this指向作用域链的上一层的this 即window
            }
        };
        obj.a();    // 'OBJ'
        obj.b();    // 'GLOBAL'
        //箭头函数不能当做构造函数来使用
        new obj.b()  // Uncaught TypeError: obj.b is not a constructor
</script>

3、不能当构造函数使用
4、没有自己的arguments 即使有也是继承的上一层的
5、没有prototype 所以不能当构造函数使用

1.5、箭头函数的this指向哪里?

// ES6 
const obj = { 
  getArrow() { 
    return () => { 
      console.log(this === obj);  //true
    }; 
  } 
}

等价于下边的代码

// ES5,由 Babel 转译
var obj = { 
   getArrow: function getArrow() { 
     var _this = this; 
     return function () { 
        console.log(_this === obj);  //true
     }; 
   } 
};

1.6、对象和数组的解构

作用:用于提取特定的数据。
数组解构:使用元素位置来匹配的

 <script>
        const [a, b, c] = [1, 2, 3]
        console.log(a); //1
        console.log(b); //2
        console.log(c); //3

        const [d,e] = [1,2,3]
        console.log(d); //1
        console.log(e); //2
</script>

对象解构:使用属性名来匹配的

<script>
        const obj = {
            name: 'shixue',
            age: 18
        }
        let {age, name} = obj
        console.log(name); //shixue
        console.log(age); //18
</script>

对象的增强写法

 <script>
        const name = 'shixue'
        const age = 18
        const obj = {
            age, name
        }
        console.log(obj); Object //{age: 18, name: 'shixue'}
</script>

函数的增强写法

<script>
        const fn = {
            fun() {

            }
        }
        //等价于下边的
        const fn = {
            fun: function() {
                
            }
        }
</script>

1.7、rest参数的理解

作用:把一个分离的参数序列整成一个数组

<script>
      function mutiple(...args) {
  	  console.log(args)
}
mutiple(1, 2, 3, 4) // [1, 2, 3, 4]
</script>

解析:在这里参数(1,2,3,4)变成了[1,2,3,4]

5、JS循环事件、微任务宏任务

6、

VUE

1、vue的基本原理

当一个vue实例创建的时候,vue会遍历data中的所有属性,通过object.defineproperty(vue 3中用proxy)将他们转换成getter/setter,并且在内部追踪相关依赖,当属性被访问或者是修改的时候通知变化。每个组件实例都有对应的watcher程序实例,会在组件渲染过程中把属性记录为依赖,当依赖的setter被调用的时候通知watcher重新计算,使其关联的组件得以更新。
object.defineproperty和proxy的区别:vue在初始化实例对象的时候会遍历data中的所有属性,并且通过object.defineproperty把他们转换成getter(收集依赖)/setter(触发依赖),这样当追踪数据发生变化的时候会自动调用setter,
但是会存在下边的问题,就是当添加或者是删除对象的属性的时候,vue检测不到,因为刚开始的时候新添加或者是删除的属性没有做响应式处理,并且只能通过$set来调用object.defineproperty还有就是无法检测数组下标和长度的变化。
proxy监测数据的整个对象而不是对象的属性,作用就是定义基本操作的自定义行为(如属性的增加删除枚举等),这样只需要给对象做一层代理就可以监测同级结构下的所有属性的变化(包括属性的新增和删除),并且可以监测数组的变化。
为什么用proxy:在vue2中object.defineproperty会改变原始数据,vue3中的proxy是创建对象的虚拟表示,并且提供get set delete等处理器,这些处理器会在访问或者是修改原始对象的属性时触发,好处就是不需要set delete来触发响应,可以全方位监测数组变化。
使用object.defineproperty进行数据劫持的缺点:就是当添加或者是删除对象的属性的时候,vue检测不到还有就是监测不到数据下标和长度的变化。所以vue3中使用proxy来代理整个对象而不是对象属性。

2、双向绑定的原理

vue.js通过数据绑定结合发布-订阅者的方式,通过object.defineproperty来劫持属性的getter/setter,当数据发生变化的时候发布消息给订阅者,更新视图,主要步骤如下。
1>、通过Observer的数据对象进行递归遍历,包括子属性对象的属性,添加setter/getter,这样给某一个属性赋值的时候,就会触发setter,监听到数据的变化。
2>、complier解析模板指令,并且将模板的变量替换成数据然后初始化渲染页面视图,给每条指令对应的节点绑定更新函数,添加监听数据的订阅者,当收到数据变化通知更新视图。
3>、Watcher作为Observer和complier之间通信的桥梁,主要作用有三个,一是在初始化实例的时候把自己添加到dep订阅器,二是有自己的updata方法,三是收到dep.notice通知,调用自己的updata方法,并触发complier绑定的监听回调,功成身退。
4>、MVVM作为数据绑定的入口,通过Observer complier和Watcher,Observer 用来实现数据的监听,complier解析编译模板指令,Watcher作为他们两个之间通信的桥梁,实现了数据变化-更新视图,视图组件交互-数据更新变化的双向绑定效果。
前端面经高频考点_第5张图片

3、MVVM MVC MVP分别是什么?

MVVM MVC MVP是三种软件架构模式,通过分离关注点的方式来组织代码结构,优化开发效率。
在单页面应用中,一个路由文件往往对应一个js文件,这样的话,页面的渲染,数据的获取以及用户的交互事件的逻辑都会混合在一起,在复杂的大型项目中代码很长,不利于页面的开发和后期的维护。
MVC模式分离model view 和 controller,view负责页面的显示逻辑,model用于数据的存储和对数据的操作。model和view采用了观察者模式,当model中的数据发生变化的时候会通知view层更新视图。controller作为model和view之间的纽带,当用户与页面发生交互的时候会调用model,实现model数据的改变,然后model通知view层进行视图的更新。
MVP模式与MVC模式不一样的是controller和presenter。MVP模式的model和view是采用观察者模式,当model层数据变化的时候,通知view进行视图的更新,但是当业务逻辑很复杂的时候,model和view会出现高度的耦合并且不利于代码的复用,MVP模式中的presenter可以解决这个问题。MVC中的controller只有model对其暴露接口,他不能控制view的变化,presenter是view和model的接口都对其暴露,这样的话,可以对model和view中的数据进行实时更新,降低了代码的耦合度。
MVVM模式:view负责页面的显示逻辑。model负责业务逻辑数据的存储和操作,viewmodel用于监测model层的数据变化 控制view层的视图刷新 处理用户的交互操作。model和view没有直接的联系,model和viewmodel实现了数据的双向绑定,当model数据变化的时候view自动刷新,当用户交互使得view改变的数据也会在model进行同步。总的来说,MVVM模式实现了view和model层的自动更新,开发者只需要关注数据的操作即可,不需要操作DOM。
MVVM的优缺点
优点:分离model和view,减少了代码耦合度,提高视图和逻辑的复用性;避免手动操作DOM,利用双向绑定,当数据变化时视图自动更新,避免了频繁的手动操作DOM.
缺点:bug很难调试,当页面出现bug的时候不知道是view的问题还是model的问题,并且通过数据绑定一个地方的bug很容易传递到别的位置,很难找到原始的出现bug的地方。数据绑定的声明是指令式的写在view模板中的,这些内容是无法通过断点debug的。还有就是一个大型的图形应用程序的时候,视图会很多,viewmodel的构建和维护成本很高。

4、computed watcher methods的区别

computed是计算属性:只有当依赖的数据发生变化的时候才会重新计算;不支持异步;computed中的默认值是走缓存的,计算属性是根据响应式的依赖进行缓存的,即必须是data中声明过得数据或者是从父组件传递过来的props中的数据;当一个属性需要借助其他属性来得到时,用computed;当属性值是函数的时候默认会调用get方法,函数的返回值就是属性值,computed有两个方法,get和set,当数据变化的时候触发set。
watcher侦听器:没有缓存,当数据发生变化的时候立即触发响应操作;支持异步监听;监听的函数接收两个参数,第一个参数是当前值,第二个参数是变化之前的值;监听的数据必须是data中声明过的或者是父组件传递过来的props中的数据。
使用场景:一般用于计算的属性放在computed中,根据computed的缓存属性,只要data中的数据不发生改变就会重新计算;当需要监听异步操作的时候,用watcher侦听器,当数据改变的时候立即执行相应地操作,限制执行该操作的频率。
methods:对于同一个函数可以放在computed中和methods中,最终得到的结果是相同的。在computed中,计算属性是根据响应式的依赖进行缓存的,只有当依赖的数据发生变化的时候才会重新计算,否则该函数只执行一次;在methods中调用多少次就执行多少次。

5、slot是什么?有什么作用?原理是什么?

slot是插槽,是vue的内容分发机制,插槽slot是子组件的一个模板标签元素,这个元素是否显示以及怎么显示是由父组件决定的,插槽有三种:
1>、匿名插槽:没有name属性的插槽是匿名插槽,一个组件中只能有一个匿名插槽。
2>、具名插槽:有name属性的插槽,一个组件中可以有多个具名插槽。
3>、作用域插槽,可以是匿名插槽也可以是具名插槽,不同点在于子组件在执行渲染函数的的时候,会把数据传递给父组件,父组件根据子组件的传递过来的数据决定如何渲染该插槽。
原理:子组件vm在实例化的时候,会接收来自父组件的插槽内容,存放在vm. s l o t 中 , 匿 名 插 槽 存 放 在 v m . slot中,匿名插槽存放在vm. slotvm.slot.default中,具名插槽存放在vm. s l o t . x x x ( x x x 是 插 槽 名 字 ) , 当 执 行 到 组 件 渲 染 函 数 的 时 候 , 遇 到 s l o t 标 签 使 用 v m . slot.xxx(xxx是插槽名字),当执行到组件渲染函数的时候,遇到slot标签使用vm. slot.xxx(xxx)slot使vm.slot中的内容进行替换,此时可以为插槽传递数据,如果有数据,则该插槽就是作用域插槽。

6、过滤器是什么 有什么作用?

过滤器:顾名思义,就是对数据格式进行更改后在输出展示。他没有修改原数据(computed和methods对原始数据均做了更改),只是对输出格式做了更改,用在插值表达式和v-bind中,放在操作符 | 的后边。常见的有,比如进行价格的展示和时间格式的展示(从后台拿到的是时间的字符串形式的表达式),需要转换成正确的格式。

<li>商品价格:{{item.price | filterPrice}}</li>

 filters: {
    filterPrice (price) {
      return price ? ('¥' + price) : '--'
    }
  }

7、如何保存页面的当前状态?

当从home.vue切换到分类页面的时候,home.vue会被销毁,为了不让home.vue被销毁,要在app.vue中加一个keep-alive属性把路由包起来。

<keep-alive exclude="Detail">
      <router-view></router-view>
</keep-alive>

这样的话是不会被销毁了,但是存在当再次切换到home.vue的时候回不到原来的浏览位置,解决方法:
在home.vue中给一个saveY: 0的data,然后在组件被切换之前记录scrollY的值,当组件被切换回来的时候,直接scrollTo到原来的saveY的位置。

activated() {
      this.$refs.scroll.scrollTo(0, this.saveY, 0)
      //如果不刷新的话可能会 出现滚不动的问题
      this.$refs.scroll.refresh()
    },
deactivated() {
	    this.saveY = this.$refs.scroll.scroll.y
},

8、常见的事件修饰符

.stop:阻止冒泡
.prevent:阻止默认事件
.capture:进行捕获模式
.once:只触发一次
.self:只触发自己范围内的事件,不包含子元素

9、v-if和v-show的区别

1>、手段。v-if是动态的向dom树中添加和删除dom元素,v-show是通过设置元素的display属性来控制显隐的。
2>、编译条件。v-if的初始值为假的时候,就不会进行编译,只有初始值为true的时候才会编译渲染DOM;v-show是不管初始值的真假都进行编译渲染DOM.
3>、编译过程。v-if切换有一个局部编译/卸载的过程,切换过程中合适的销毁和重建内部的事件监听和子组件,v-show切换就是简单的css切换。
4>、性能消耗。v-if有更高的切换性能消耗,v-show有更高的初始渲染消耗。
5>、使用场合。v-show适用于频繁切换的场合,v-if适用于运行条件一般不变的情况。

10、data为什么是一个函数而不是一个对象?

js中的对象是引用类型的数据,当多个实例引用同一个对象的时候,只要有一个实例对这个对象进行修改,那么其余实例的数据也会做相应的修改。但是vue更多的是要求组件的复用,即组件之间的数据相互独立,所以data是一个函数而不是一个对象,这样组件的数据以函数返回值的形式定义,每一个组件都有自己独立的数据,组件之间不会相互干扰。

11、keep-alive的理解

当组件之间进行切换,需要保存组件当前的状态的时候,用keep-alive组件包裹需要缓存的组件。
有三个属性:
1>、include字符串或者是正则表达式,只有名字匹配的组件才会被匹配
2>、exclude字符串或者是正则表达式,任何名字匹配的组件均不会被匹配
3>、max数字,能够包裹的最大的组件数。

计算机网络和浏览器相关的

1、浏览器安全(6.28)

1、xss攻击
定义:代码注入攻击。攻击者将恶意代码放在网站上,并且将其在用户的浏览器上执行,从而窃取用户信息,比如cookie。xss代码注入攻击的本质是网站没有对恶意代码进行过滤,使之与正常代码混合在一起,浏览器分不清哪些是恶意代码,从而使得恶意代码执行。
类型
1>、存储型:恶意代码存储在后台的数据库中,当服务端收到请求的时候,将恶意代码拼接到HTML中返回,从而导致恶意代码的执行。
2>、反射型:攻击者创建特殊的 URL,当服务端收到请求的时候URL被拼接到HTML中返回,从而导致恶意代码的执行。
3>、DOM型:攻击者创建特殊的URL,当打开网站的时候,js脚本从URL中获取数据,从而导致恶意代码的执行。
解决方法
1>、从浏览器的执行来看,一是使用纯前端,不接收服务端返回的数据;二是对插入到HTML中的代码进行转义,DOM型攻击主要是因为前段脚本不安全造成的,所以对数据的获取渲染和字符串拼接的时候对可能出现的恶意代码进行判断。
2>、使用CSP, CSP的本质是建立一个白名单,告诉浏览器哪些外部资源可以加载和执行。打开CSP的方式有两种,一是在HTTP的请求头设置 Content-Security-Policy或者是在meta标签中设置
3>、对敏感信息进行保护,在cookie中设置http-only,使得脚本无法获取,或者是使用验证码,避免脚本冒充用户进行一系列操作。
2、CSRF攻击
定义:跨站请求伪造攻击。攻击者通过诱导用户进入一个第三方网站,通过这个第三方网站向被攻击网站发送跨域请求,如果用户在被攻击网站保存了登录状态,攻击者就会利用这个登录状态,绕过后台的用户验证,直接冒充用户向服务器进行操作。本质是cookie在同源请求中可以携带发送给服务器。
类型
1>、GET类型
比如通过img发送请求,当用户打开页面的时候就会自动提交请求。
2>、POST请求
比如创建一个表单,然后隐藏他,当用户打开页面的时候自动提交这个表单。
3>、链接类型的攻击
比如在a 的 href属性中向服务器发送一个请求,诱导用户点击这个链接。
解决方法
1>、通过在cookie中设置Samesite属性,限制cookie被作为第三方使用,samesite分为严格模式和宽松模式,宽松模式下当请求是GET并且可以发生页面跳转的情况可以被请求,严格模式下,cookie在任何情况下都不允许被作为第三方使用。
2>、通过CSRF Token,服务器端向用户返回一个随机数token,当浏览器再次发送请求时,在请求参数中加入服务器端返回的token,服务端对token进行验证。
3、中间人攻击
定义
中间人攻击就是拦截通讯双方的通话,并且插入新的内容。
过程
客户端向服务器发送请求,请求被中间人拦截,服务端发送公钥给客户端,公钥被中间人劫持,生成假的公钥给客户端;客户端拿到假的公钥之后生成加密HSAH值发送给服务端,中间人劫持加密HSAH值,利用私钥解密得到真的HASH值,在生成一个假的加密HASH值给服务端;服务端通过私钥解密HASH值发送加密数据给客户端。
解决方法
使用数字证书:利用hash算法对公钥和其他信息加密形成信息摘要,然后用数字证书认证中心的私钥进行加密形成签名,签名和其他信息一起打包形成数字证书。当接收方收到数字证书的时候根据原始信息使用相同的hash算法生成信息摘要,然后用数字证书的公钥进行解密得到信息摘要,看一下这两个信息摘要是不是相同,以此来验证有没有发生过中间人攻击和验证数据的完整性。
4、有哪些可能会引起前端安全
1、xss攻击
2、CSRF攻击
3、恶意第三方库
4、中间人攻击
5、网络劫持有哪几种
1>、DNS劫持,就是输入淘宝显示京东页面,这种违法,没人用
2>、HTTP劫持,比如在打开谷歌页面的时候会弹出广告。因为HTTP是明文传输的,运营商会修改你的http响应内容,解决方法:全站HTTPS传输,将HTTP进行加密,获取不到响应明文了,自然就无法更改响应内容了。

手写代码篇

1、new操作符(6.28)

function Father(name, age) {
            this.name = name
            this.age = age
        }
function myNew1() {
            //new 的执行过程 首先创建一个空对象 然后让这个空对象的__proto__属性指向构造函数的prototype属性 让this指向这个对象并且执行构造函数的代码 判断返回的函数类型如果是值类型的话就返回创建的对象如果是引用类型就返回引用类型的对象
            let [constructor, ...args] = [...arguments]

            let obj = {}
            obj.__proto__ = constructor.prototype
            let res = constructor.apply(obj, args)
            return res instanceof Object ? Object : obj
        }
var son = myNew1(Father, 'shixue', 24)
console.log(son);

2、改变函数的this指向的call方法(6.28)

function Father1(name, age) {
            this.name = name
            this.age = age
}
Function.prototype.myCall1 = function(context) {
            //先判断被调用的是不是一个函数 然后判断传入的对象是不是真的存在 然后处理参数 把被调用的函数设置为该对象的方法 用这个方法处理参数 删除定义的方法 返回处理参数的结果
            if(typeof this !== 'function') {
                console.error('被调用的不是一个函数');
            }
            context = context || window 
            let args = [...arguments].slice(1)
            let res = null
            context.fn = this
            res = context.fn(...args)
            delete context.fn
            return res
}
function son1(name, age) {
            Father1.myCall1(this, name, age)
}
var son2 = new son1('shixue', 25)
console.log(son2);

3、改变函数的this指向的apply方法(6.28)

function Father1(name, age) {
            this.name = name
            this.age = age
}
Function.prototype.myApply1 = function(context) {
            //首选判断被调用的是不是一个函数 然后判断传入的对象是不是存在 然后处理参数 把该函数设置为该对象的一个方法 然后用这个方法去处理参数 删除新定义的方法 返回最终的结果
            if(typeof this !== 'function') {
                console.error('被调用的不是一个函数');
            }
            context = context || window
            let res = null
            context.fn = this
            if(arguments[1]) {
                res = context.fn(...arguments[1])
            } else {
                res = context.fn()
            }
            delete context.fn
            return res
}
function son3(name, age){
            Father1.myApply1(this, [name, age])
}
var son4 = new son3('shixue', 25)
console.log(son4);

4、改变函数的this指向的bind方法(6.28)

Function.prototype.myBind1 = function(context) {
            //首先判断被调用的是不是一个函数 然后判断传入的对象是否存在 然后处理参数和call一样 然后改变this的指向如果被调用的是一个构造函数就指向构造函数反之指向传入的对象
            if(typeof this !== 'function') {
                console.error('被调用的不是一个函数');
            }
            context = context || window
            let args = [...arguments].slice(1)
            let fn = this
            return function Fn() {
                return fn.apply(this instanceof Fn ? Fn : context, args.concat(...args))
            }
}
var c = 0

function Obj2() {
            this.c = 1,
            this.getNum1 = function() {
                setTimeout(function() {
                    console.log(this.c); //定时器函数的this指向window
                },5000)
            },
            this.getNum2 = function(){
                setTimeout(function(){
                    console.log(this.c);
                }.myBind1(this),5000) //绑定了之后 this就指向创建的构造函数了
            }

}
var A = new Obj2
A.getNum1() // 5秒之后 输出 0
A.getNum2() //5 秒之后输出 1 两个是同时输出的 也就是 两个定时器函数均在宏任务队列的第5秒执行的 不是先执行完一个5秒再等下一秒才去执行下一个定时器函数

5、图片的懒加载(6.28)

var img = document.querySelectorAll('img')
function lazyLoad() {
            var scrollHeight = document.body.scrollTop || document.documentElement.scrollTop
            var viewHeight = window.innerHeight

            for(var i = 0; i < img.length; i++) {
                if(img[i].offsetTop < scrollHeight + viewHeight) {
                    img[i].src = img[i].getAttribute('data-src') //得到自定义属性 用 getAttribute
                }
            }
}
window.addEventListener('scroll', lazyLoad) //如果加了括号的话 是立即执行的 不加括号才是用到时 在去加载

平时学习相关的

1、代码怎么debug

2、代码怎么存放

3、怎么学的前端

你可能感兴趣的:(前端面试,笔记,前端,javascript,css,html5,vue.js)