答题思路:
1.先讲简洁的概念
2.详细原理
3.缺点
4.注意点
5.总结
其中1.2点基本所有题都有,3,4,5看具体题目
HTML
1.src和href的区别
相同点:
src和href都是用来引用外部的资源
区别:
1.含义不同:src是表示对资源的引用,href是超文本引用,建立链接关系指向一些网络资源
2.对文档的影响不同:当浏览器解析到 src 属性时,会暂停其他资源的下载和处理,直到将该资源加载、编译、执行完毕。而解析到 href 属性时,会并行下载资源且不会停止对当前文档的处理。
3.适用范围不同,src适用于图片、音频、视频和脚本等资源的引用,href适用于css样式表、字体文件和网页链接
2.script标签中defer和async的区别
相同点:
defer 和 async属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面的解析
不同点:
1.执行顺序不同,有多个脚本时,执行顺序不同。多个带async属性的标签,不能保证加载的顺序;多个带defer属性的标签,按照加载顺序执行
2.执行时机不同,async加载完立即执行,defer加载完会到文档所有元素解析完成之后,DOMContentLoaded事件触发执行之前执行。
3.html5有哪些更新
1.语义化标签:<header>、<footer>、<nav>、<section>、<article>
2.媒体元素:audio,video
3.canvas和svg
4.存储方案:localStorage和sessionStorage
5.websocket:双向通信
6.web worker:创建后台线程
7.拖放api
8.地理定位:geolocation
4.行内元素,块级元素,空元素有哪些?
行内元素:a b span img input select strong
块级元素:div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p
空元素:没有内容的HTML元素。空元素是在开始标签中关闭的,也就是空元素没有闭合标签,即单标签
<br>、<hr>、<img>、<input>、<link>、<meta>
5.对HTML语义化的理解
含义:HTML5 的语义化标签是一类具有明确含义的标签
作用:
1.机器友好:有利于SEO,支持读屏软件
2.开发者友好:增强了代码的可读性和可维护性
常见的语义化标签:
<header></header> 头部
<nav></nav> 导航栏
<section></section> 区块(有语义化的div)
<main></main> 主要区域
<article></article> 主要内容
<aside></aside> 侧边栏
<footer></footer> 底部
CSS
1.CSS选择器及其优先级
标签选择器、伪元素选择器:1
类选择器、伪类选择器、属性选择器:10
id 选择器:100
内联样式:1000
注意:
!important声明的样式的优先级最高;
如果优先级相同,则最后出现的样式生效;
2.display属性值和作用
none
元素不显示,并且会从文档流中移除。
block
块类型。默认宽度为父元素宽度,可设置宽高,换行显示。
inline
行内元素类型。默认宽度为内容宽度,不可设置宽高,同行显示。
inline-block
默认宽度为内容宽度,可以设置宽高,同行显示。
table
此元素会作为块级表格来显示。
list-item
像块类型元素一样显示,并添加样式列表标记。
inherit
规定应该从父元素继承display属性的值。
3.display的block、inline、inline-block区别
块级元素block:
可以设置宽高;
设置margin和padding都有效;
可以自动换行;
多个块状,默认排列从上到下。
inline行内:
设置宽高无效;宽高由内容撑开
可以设置水平方向的margin和padding属性,不能设置垂直方向的padding和margin;
不会自动换行;
inline-block:
可以设置宽高,margin和padding,不会自动换行;
将对象设置为inline对象,但对象的内容作为block对象呈现,之后的内联对象会被排列在同一行内。
4.隐藏元素的方法有哪些?
方法 | 是否占据空间 | 是否响应绑定的事件 |
---|---|---|
display:none | 否 | 否 |
visibility:hidden | 是 | 否 |
opacity:0 | 是 | 是 |
z-index:负值 | 是 | 否 |
position: absolute; | ||
position: fixed; | ||
将元素移除可视区域内,以此来实现元素的隐藏 | 是 | 否 |
ransform: scale(0,0) | 是 | 否 |
5.对盒模型的理解
标准盒模型:css中设置盒子的width,height只代表内容的尺寸,不包括内边距、边框和外边距。
怪异盒模型:css中设置盒子的width,height,(元素的宽度和高度)不仅包括内容的尺寸,还包括内边距和边框。
通过CSS3的box-sizing属性来控制元素的盒模型。
当box-sizing属性的值为content-box时,使用的是标准盒模型;
当box-sizing属性的值为border-box时,使用的是怪异盒模型。
6.css3新特性
新增各种CSS选择器 :hover、:focus、:active、:visited、:target、:first-child、:last-child、:nth-child、:nth-last-child、:first-of-type、:last-of-type、:nth-of-type、:nth-last-of-type、:empty、:checked、:enabled、:disabled、:not、:before、:after
动画和过渡: transition 和 animation 。
3D 转换: transform 属性,支持旋转、缩放、移动和平移等 3D 转换效果。
渐变: linear-gradient 和 radial-gradient。
多重背景:CSS3 允许在一个元素上同时使用多个背景图象。
媒体查询: @media 规则
颜色模式:rgba() 和 hsla()
滤镜: filter 属性,允许开发者对元素进行颜色、亮度、对比度、饱和度和锐度的调整。
弹性盒布局: flexbox 布局模型
网格布局: grid 布局模型
7.单行,多行文本溢出实现
单行文本溢出:
1.设置不换行2.设置溢出处隐藏3.设置溢出省略号显示
overflow: hidden; // 溢出隐藏
text-overflow: ellipsis; // 溢出用省略号显示
white-space: nowrap; // 规定段落中的文本不进行换行
多行文本溢出
1…设置一处隐藏2.设置溢出省略号显示3.设置弹性盒子,4.设置弹性盒子垂直排列5.设置显示行数
overflow: hidden; // 溢出隐藏
text-overflow: ellipsis; // 溢出用省略号显示
display:-webkit-box; // 作为弹性伸缩盒子模型显示。
-webkit-box-orient:vertical; // 设置伸缩盒子的子元素排列方式:从上到下垂直排列
-webkit-line-clamp:3; // 显示的行数
8.为什么要清除浮动,清除浮动的方式有哪些?
浮动含义:子元素浮动时,容器高度不能被内容撑开。 此时,内容会溢出到容器外面而影响布局。这种现象被称为浮动
浮动的工作原理:浮动元素脱离文档流,不占据空间
清除浮动方法:
1.给父级div定义height属性
2.最后一个浮动元素之后添加一个空的div标签,并添加clear:both样式,对元素设置clear属性是为了避免浮动元素对该元素的影响
3.包含浮动元素的父级标签添加overflow:hidden或者overflow:auto开启BFC
4.使用 :after 伪元素。由于IE6-7不支持 :after,使用 zoom:1 触发 hasLayout
9.对BFC的理解,如何创建BFC?
BFC 英文名为 Block Formatting Context (块级格式化上下文)
- 内部的盒子会在垂直方向上一个接一个的放置
- BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然
- BFC的作用:
1.解决margin塌陷问题
2.解决浮动问题
- BFC有几种常见的方法:
满足下列条件之一就可以触发 BFC:
HTML 根元素
position 为 absolute 或 fixed
float 属性不为 none(常用)
overflow 不为 visible(常用)例如hidden、auto或scroll。
display 为 inline-block, table-cell, table-caption, flex
10.postion属性有哪些?区别是什么?
absolute 相对父元素
生成绝对定位的元素,相对于static定位以外的一个父元素进行定位。元素的位置通过left、top、right、bottom属性进行规定。
relative 相对原来位置
生成相对定位的元素,相对于其原来的位置进行定位。元素的位置通过left、top、right、bottom属性进行规定。
fixed 相对屏幕视口
生成绝对定位的元素,指定元素相对于屏幕视⼝(viewport)的位置来指定元素位置。元素的位置在屏幕滚动时不会改变,⽐如回到顶部的按钮⼀般都是⽤此定位⽅式。
static
默认值,没有定位,元素出现在正常的文档流中,会忽略 top, bottom, left, right 或者 z-index 声明,块级元素从上往下纵向排布,⾏级元素从左向右排列。
inherit
规定从父元素继承position属性的值
11.水平垂直居中实现
1.绝对定位加transform
.child {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%,-50%);
}
2.绝对定位加margin:auto
.parent {
position: relative;
}
.child {
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
margin: auto;
}
3.flex布局,住轴侧轴居中
.parent {
display: flex;
justify-content:center;
align-items:center;
}
12.对flex布局的理解,及使用场景
Flex是FlexibleBox的缩写,意为"弹性布局"
容器默认存在两根轴:水平的主轴(main axis)和垂直的交叉轴(cross axis),项目默认沿水平主轴排列。
属性 | 默认 | |
---|---|---|
父盒子属性如下: | ||
主轴对齐方式 | justify-content | flex-start |
侧轴对齐方式 | align-items | stretch(默认撑开) |
弹性盒子换行方式 | flex-wrap | no-wrap |
主轴方向 | flex-direction | row |
多轴线对齐方式 | align-content | stretch(默认伸开) |
子元素属性如下: | ||
放大 | flex-grow | 0(不放大)[0,+∞) |
缩小 | flex-shrink | 1(缩小)[0,+∞) |
元素主轴初始大小 | flex-basis | auto(比主轴的宽或高有更高优先级) |
以上三个简写 | flex | 0,1,auto |
单个子元素对齐方式,覆盖当前的align-items | align-self | auto |
flex:1 | 1,1,0% | |
表示: | ||
flex-grow:1 | ||
flex-shrink:1 | ||
flex-basis:0% |
13.如何解决1px问题
1px 问题指的是:在一些 Retina屏幕 的机型上,移动端页面的 1px 会变得很粗,呈现出不止 1px 的效果
原因:CSS 中的 1px 并不能和移动设备上的 1px 划等号
window.devicePixelRatio = 设备的物理像素 / CSS像素。
打开 Chrome 浏览器,启动移动端调试模式,在控制台去输出这个 devicePixelRatio 的值。这里选中 iPhone6/7/8 这系列的机型,输出的结果就是2:
这就意味着设置的 1px CSS 像素,在这个设备上实际会用 2 个物理像素单元来进行渲染,所以实际看到的一定会比 1px 粗一些。
解决方法:
1.把 1px 改成 1/devicePixelRatio 后的值
这是目前为止最简单的一种方法。这种方法的缺陷在于兼容性不行,IOS 系统需要8及以上的版本,安卓系统则直接不兼容。
2.伪元素先放大后缩小
#container[data-device="2"] {
position: relative;
}
#container[data-device="2"]::after{
position:absolute;
top: 0;
left: 0;
width: 200%;
height: 200%;
content:"";
transform: scale(0.5);
transform-origin: left top;
box-sizing: border-box;
border: 1px solid #333;
}
}
在目标元素的后面追加一个 ::after 伪元素,让这个元素布局为 absolute 之后、整个伸展开铺在目标元素上,然后把它的宽和高都设置为目标元素的两倍,border值设为 1px。接着借助 CSS 动画特效中的放缩能力,把整个伪元素缩小为原来的 50%。此时,伪元素的宽高刚好可以和原有的目标元素对齐,而 border 也缩小为了 1px 的二分之一,间接地实现了 0.5px 的效果。
3.viewport 缩放来解决
const scale = 1 / window.devicePixelRatio;
// 这里 metaEl 指的是 meta 标签对应的 Dom
metaEl.setAttribute('content', `width=device-width,user-scalable=no,initial-scale=${scale},maximum-scale=${scale},minimum-scale=${scale}`);
这样解决了,但这样做的副作用也很大,整个页面被缩放了。这时 1px 已经被处理成物理像素大小,这样的大小在手机上显示边框很合适。但是,一些原本不需要被缩小的内容,比如文字、图片等,也被无差别缩小掉了
14.两栏布局实现
两栏布局指的是左边一栏宽度固定,右边一栏宽度自适应
1.利用浮动,左右浮动,右边设置margin和宽度auto
利用浮动,将左边元素宽度设置为200px,并且设置向左浮动。将右边元素的margin-left设置为200px,宽度设置为auto(默认为auto,撑满整个父元素)
2.利用浮动,左侧固定大小左浮动,右边开启BFC
左侧元素设置固定大小,并左浮动,右侧元素设置overflow: hidden; 这样右边就触发了BFC,BFC的区域不会与浮动元素发生重叠,所以两侧就不会发生重叠。
3.利用flex布局,将左边元素设置为固定宽度200px,将右边的元素设置为flex:1。
4.利用绝对定位,将父级元素设置为相对定位。左边元素设置为absolute定位,并且宽度设置为200px。将右边元素的margin-left的值设置为200px。
15.三栏布局实现
三栏布局一般指的是页面中一共有三栏,左右两栏宽度固定,中间自适应的布局,三栏布局的具体实现
1.利用绝对定位,左右两栏设置为绝对定位,中间设置对应方向大小的margin的值
2.利用flex布局,左右两栏设置固定大小,中间一栏设置为flex:1。
3.利用浮动,左右两栏设置固定大小,并设置对应方向的浮动。中间一栏设置左右两个方向的margin值,注意这种方式,中间一栏必须放到最后(文档流的最后放)
16.实现一个三角形
CSS绘制三角形主要用到的是border属性,也就是边框
设置宽高为0,设置border宽度,设置border颜色只留下上border的颜色,其他颜色为透明
div {
width: 0;
height: 0;
border-top: 50px solid red;
border-right: 50px solid transparent;
border-left: 50px solid transparent;
}
JAVASCRIPT
数据类型:
1.js有哪些数据类型,有哪些区别
基本数据类型,也被称为原始值,包括:
Number:数值类型,包括整数和浮点数,也可以表示为科学记数法的形式。例如 123,0.123,1.23e4 等。
String:字符串类型,用于表示文本信息,比如 ‘Hello World’。
Boolean:布尔类型,只有两个可能的值,即 true 和 false。
Undefined:未定义类型,表示变量已经声明,但还未赋值。
Null:空类型,表示变量没有值。
Symbol:符号类型,ES6 新增的数据类型,主要用于创建唯一的标识符。
BigInt:大整数类型,ES 2020新增,能够表示超过 Number 类型大小限制的整数。
引用数据类型,引用数据类型,包括:
Object:对象类型,包括普通对象、数组和函数等。
区别:
基本数据类型存储在栈里;
引用数据类型存储在堆里。
2.数据类型检测方式有哪些
1.typeof 判断的粒度比较粗,它能准确判断基础类型(不包括null)和 Object 和 Function。 换句话,它不能判断null 和 Array ,会把他们都判断为object。
2.instanceof 用来判断对象的更具体的类型。instanceof的模拟实现, 它的主要原理的是沿着对象的原型链的方向,判断原型对象是否是构造器的prototype。
3.Object.prototype.toString.call 是最全面的方法了。它的代码运行如下
3.判断数组方式有哪些
1.通过ES6的Array.isArray()做判断
2.通过Object.prototype.toString.call()做判断
Object.prototype.toString.call(obj).slice(8,-1) === 'Array';
3.通过instanceof做判断
obj instanceof Array
4.通过Array.prototype.isPrototypeOf
Array.prototype.isPrototypeOf(obj)
4.null和undefined区别
相同点: Undefined 和 Null 都是基本数据类型,都只有一个值,就是 undefined 和 nul
不同点:
1.含义不同:undefined 代表的含义是未定义,null 代表的含义是空对象;null是关键字,undefined不是关键字
2.类型检测不同:typeof null的结果是"object",这是因为null在JavaScript中被视为一个空对象指针。而typeof undefined的结果是"undefined"。
3.数值转换结果不同:在进行数值转换时,null会被转换为0,而undefined会被转换为NaN
4.使用场景不同:null主要用于赋值给一些可能会返回对象的变量,作为初始化当你需要释放一个对象的引用时,你可以将该对象的值设为null。而undefined常用于表示尚未初始化的变量值
5.intanceof操作符实现原理及实现
作用:instanceof 运算符用于判断构造函数的 prototype 属性是否出现在对象的原型链中的任何位置。
实现:
1.传入构造函数和需要判断的对象
2.获取构造函数的原型,getPrototypeOf获取对象的原型
3.如果对象原型为null返回fallse,否则继续判断是否相等,相等返回true,不相等,获取对象原型的原型,递归判断是否和构造函数的原型相等,
function myInstanceof(left, right) {
// 获取对象的原型
let proto = Object.getPrototypeOf(left)
// 获取构造函数的 prototype 对象
let prototype = right.prototype;
// 判断构造函数的 prototype 对象是否在对象的原型链上
while (true) {
if (!proto) return false;
if (proto === prototype) return true;
// 如果没有找到,就继续从其原型上找,Object.getPrototypeOf方法用来获取指定对象的原型
proto = Object.getPrototypeOf(proto);
}
}
6.为什么0.1+0.2!==0.3,如何让其相等
结果:0.1+0.3= 0.30000000000000004
原因:由于某些十进制小数在二进制中无法精确表示,因此在进行加法运算时会产生舍入误差。
0.1的二进制是0.0001100110011001100…(1100循环),
0.2的二进制是:0.00110011001100…(1100循环),这两个数的二进制都是无限循环的数。
解决方法:
1.使用tofixed(1)保留1位小数四舍五入(n1 + n2).toFixed(1) // 注意,toFixed为四舍五入
2.相差小于机器精度,Number.EPSILON,就可以认为相等
3.放大10倍,加起来在除以10倍
7.==操作符类型转化规则
1首先会判断两者类型是否相同,相同的话就比较两者值;
2类型不相同的话,就会进行类型转换;
3会先判断是否在对比 null 和 undefined,是的话就会返回 true
4判断两者类型是否为 string 和 number,是的话就会将字符串转换为 number
5判断其中一方是否为 boolean,是的话就会把 boolean 转为 number 再进行判断
6判断其中一方是否object 且另一方为 string、number 或者 symbol,是的话就会把 object 转为原始类型再进行判断
8.Object.is()和比较操作符"===" ,==的区别
使用双等号()进行相等判断时,如果两边的类型不一致,则会进行强制类型转化后再进行比较。
使用三等号(=)进行相等判断时,如果两边的类型不一致时,不会做强制类型准换,直接返回 false。
使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。
ES6:
1.let,const,var区别
相同点 都是声明量的关键字
区别:
var 适用于全局作用域或函数作用域,且具有变量提升的特点,可以重新声明
let 和 const 适用于块作用域,不允许变量提升,
let 允许变量更新但不允许重新声明,
const 则完全不允许变量更新或重新声明。
2.箭头函数和普通函数的区别
(1)箭头函数比普通函数更加简洁
(2)箭头函数没有自己的this
(3)箭头函数的this指向永远不会改变,在函数被创建时就确定下来
(4)call()、apply()、bind()等方法不能改变箭头函数中this的指向
(5)箭头函数不能作为构造函数使用
(6)箭头函数没有自己的arguments
(7)箭头函数没有prototype
JS基础:
1.new操作符原理
(1)首先创建了一个新的空对象
(2)设置原型,这个新对象的内部属性 proto 会被设置为构造函数的 prototype 属性
(3)让函数的 this 指向这个对象,执行构造函数的代码(为这个新对象添加属性)
(4)判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
2.数组有哪些原生方法
- 判断方法
Array.isArray():用于确定传递的值是否是一个数组。 - 合并方法
concat():用于合并两个或更多数组。返回的是拼接好的数组,不影响原数组。 - 转换方法
toString():把数组转换为字符串,并用逗号分隔每个元素。
join():把数组转换为字符串,并用指定的分隔符分隔每个元素。 - 尾部操作方法
pop():删除并返回数组的最后一个元素。
push():向数组的末尾添加一个或多个元素,并返回新的长度。 - 首部操作方法
shift():删除并返回数组的第一个元素。
unshift():向数组的开头添加一个或多个元素,并返回新的长度。 - 重排序方法
reverse():反转数组的顺序。
sort():对数组的元素进行排序。可以传入一个函数来进行比较。 - 截取方法
slice():用于截取数组的一部分,返回一个新的数组对象,不影响原数组。
删除、替换或插入方法
splice():通过删除或替换现有元素或者原地添加新的元素来修改数组,并以数组形式返回被修改的内容。此方法会改变原数组。 - 元素查找方法
indexOf():返回数组中第一个匹配元素的位置。
includes():确定数组是否包含特定元素。
find():找出数组中满足条件的第一个元素。
findIndex():找出数组中满足条件的第一个元素的索引。 - 迭代方法
forEach():对数组中的每一个元素执行一次回调函数。
map():创建一个新的数组,其结果是该数组中的每个元素都调用一次提供的函数。
filter():创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
every():检查数组中的每个元素是否通过提供的条件。
some():检查数组中的某些元素是否通过提供的条件。 - 归并方法
reduce():通过指定的函数,对数组中的每一项累计计算,最终得出一个值。 - 扁平化方法
flat():创建一个新的、已扁平的数组。
3.什么是DOM和BOM
DOM 指的是文档对象模型;document,Element,Event
BOM 指的是浏览器对象模型;window,navigator,screen,history,location
4.对类数组的理解,如何转化为数组
含义:一个拥有 length 属性和若干索引属性的对象就可以被称为类数组对象。类数组对象和数组类似,但是不能调用数组的方法。
常见的类数组对象有 arguments 和 DOM 方法的返回结果
方法:
1.通过 Array.from 方法来实现转换
2.扩展运算符 …
3.Array.prototype.slice.call():这种方法会将类数组转化为数组的一个拷贝,不会影响原类数组
5.对ajax理解,实现一个ajax请求
理解:AJAX是 Asynchronous JavaScript and XML 的缩写,指的是通过 JavaScript 的 异步通信,从服务器获取 XML 文档从中提取数据,再更新当前网页的对应部分,而不用刷新整个网页。
1、创建一个新的 XMLHttpRequest 对象。
2、使用 open() 方法打开一个与服务器的连接。这个方法需要两个参数:请求方法和URL。
(可选)使用 setRequestHeader() 方法设置额外的 HTTP 头部。
3、使用 send() 方法发送请求。对于 GET 请求,这通常是空的,对于 POST 请求,这将是你要发送的数据。
4、在 onreadystatechange 事件上添加一个侦听器,以便在状态改变时得到通知。
6.JavaScript为什么要进行变量提升,他导致了什么问题?
含义:变量提升的表现是,无论在函数中何处位置声明的变量,好像都被提升到了函数的首部,可以在变量声明前访问到而不会报错。
本质原因: js 引擎在代码执行前有一个解析的过程,创建了执行上下文,初始化了一些代码执行时需要用到的对象。
作用:
1、提高性能;在JS代码执行之前,会进行语法检查和预编译,只进行一次。
解析和预编译过程中的声明提升可以提高性能,让函数可以在执行时预先为变量分配栈空间
2、容错性更好,一些不规范的代码不会报错
声明提升还可以提高JS代码的容错性,使一些不规范的代码也可以正常执行
原型:
1.对原型,原型链的理解
原型:JavaScript中的每个对象都有一个内部的[[Prototype]]属性,也称为原型(prototype),它指向另一个对象或者null。
原型链顶级原型是null。
原型链:原型链是JavaScript中实现对象间属性和方法共享的一种机制,当访问一个对象的属性时,如果对象自身没有这个属性,那么JavaScript会沿着这个对象的原型链向上查找,直到找到这个属性为止。
原型链查找机制:当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript会沿着它的原型链一层层向上查找,直到找到该属性或方法或者原型链到达顶端(即Object.prototype,它是所有对象的祖先)为止。
原型链的工作原理
当尝试访问一个对象的属性时,JavaScript不仅会在该对象本身上查找,还会在其原型上查找,然后再查找其原型的原型,这个过程会一直持续到找到匹配的属性或达到原型链的末尾。如果最终没有找到匹配的属性,那么JavaScript会返回undefined。
异步编程:
1.对promise的理解
1.含义:Promise是异步编程的一种解决方案,它是一个对象,可以获取异步操作的消息,避免层层嵌套的回调函数,解决回调地狱,自己身上有all.reject.race方法,原型上有then.catch等方法
2.promise三种状态, pending(等待)初始状态----fulfilled(成功)成功状态----rejected(失败)失败状态
3.promise两个过程,
pending —> fulfilled (初始状态到成功)
pending —> rejected (初始状态岛失败)
4.Promise实例方法 : then catch finally
5.Promise静态方法: all race resolve reject
Promise的缺点:
- 无法取消Promise,一旦新建它就会立即执行,无法中途取消。
- 如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
- 当处于pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
2.promise的基本用法
all方法可以完成并行任务, 它接收一个数组,数组的每一项都是一个promise对象。当数组中所有的promise的状态都达到resolved的时候,all方法的状态就会变成resolved,如果有一个状态变成了rejected,那么all方法的状态就会变成rejected。
race方法和all一样,接受的参数是一个每项都是promise的数组,但是与all不同的是,当最先执行完的事件执行完之后,就直接返回该promise对象的值。如果第一个promise对象状态变成resolved,那自身的状态变成了resolved;反之第一个promise变成rejected,那自身状态就会变成rejected。
finally方法用于指定不管 Promise 对象最后状态如何,都会执行的操作。该方法是 ES2018 引入标准的。
3.对async/await的理解
1.async返回的是一个promise
2.async ,await是promise 中的then的语法糖
3.在最外层不能用 await 获取其返回值的情况下,当然应该用原来的方式:then() 链来处理这个 Promise 对象
4.语法上强制规定await只能出现在asnyc函数中
4.async/await对比promise的优势
Promise 通过 then 链来解决多层回调的问题,现在又用 async/await 来进一步优化它
同步的写法实现异步
执行上下文、作用域链、闭包
1.对闭包的理解
含义:
(1) 闭包是有权访问另一个函数作用域变量的函数
(2) 闭包一般是函数嵌套,一个函数返回另外一个函数,内部函数访问外部函数的变量就形成了一个闭包
作用:
(1) 闭包的优点是可以私有化变量,避免全局变量污染,将变量私有化到函数内部,并在私有化的基础上进行数据保持
使用场景:
(1) 闭包在防抖节流函数柯里化,都应用里数据保持这个特性
(2) 在防抖函数中,第一次点击的时候,我们会let一个time一个定时器,如果不采用闭包的话,下次触发函数会重新创建一个新的定时器,两个定时器的引用不同,是没有关联的,使用闭包可以直接在内存中找到之前创建的计时器,调用就可以直接拿到对应的定时器的时间
缺点: 闭包的缺点是容易造成内存泄露,因为闭包创建的变量会一直存在内存中,需要及时置空,否则会造成内存泄露,影响程序性能
2.对作用域,作用域链的理解
作用域有:
全局作用域:window上的属性和最外层的变量
函数作用域:函数内部声明的变量
块级作用域:由{ }包裹的代码片段,使用let,const声明的变量常量
作用域链:
在当前作用域中查找所需变量,如果在自己作用域找不到该变量就去父级作用域查找,依次向上级作用域查找,直到访问到window对象就被终止,这一层层的关系就是作用域链。
作用域链的作用:保证对执行环境有权访问的所有变量和函数的有序访问,通过作用域链,可以访问到外层环境的变量和函数。
3.对执行上下文的理解?????
执行上下文类型:
(1)全局执行上下文
任何不在函数内部的都是全局执行上下文,它首先会创建一个全局的window对象,并且设置this的值等于这个全局对象,一个程序中只有一个全局执行上下文。
(2)函数执行上下文
当一个函数被调用时,就会为该函数创建一个新的执行上下文,函数的上下文可以有任意多个。
(3)eval函数执行上下文
执行在eval函数中的代码会有属于他自己的执行上下文,不过eval函数不常使用,不做介绍
this/call/apply/bind
1.对this的理解
this 是执行上下文中的一个属性,它指向最后一次调用这个方法的对象。在实际开发中,this 的指向可以通过四种调用模式来判断。
第一种是函数调用模式,当一个函数不是一个对象的属性时,直接作为函数来调用时,this 指向全局对象。
第二种是方法调用模式,如果一个函数作为一个对象的方法来调用时,this 指向这个对象。
第三种是构造器调用模式,如果一个函数用 new 调用时,函数执行前会新创建一个对象,this 指向这个新创建的对象。
第四种是 apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。其中 apply 方法接收两个参数:一个是 this 绑定的对象,一个是参数数组。call 方法接收的参数,第一个是 this 绑定的对象,后面的其余参数是传入函数执行的参数。也就是说,在使用 call() 方法时,传递给函数的参数必须逐个列举出来。bind 方法通过传入一个对象,返回一个 this 绑定了传入对象的新函数。这个函数的 this 指向除了使用 new 时会被改变,其他情况下都不会改变。
这四种方式,使用构造器调用模式的优先级最高,然后是 apply、call 和 bind 调用模式,然后是方法调用模式,然后是函数调用模式。
2.call apply bind的区别
共同点:
都可以修改this,第一个参数都是修改的this
不同点:
传参方式不同:call是逐一传参, apply是数组/伪数组传参
执行机制不同:call和apply会立即执行函数,bind不会立即执行
3.实现call,apply即bind函数
(1)call 函数的实现步骤:
●判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
●判断传入上下文对象是否存在,如果不存在,则设置为 window 。
●处理传入的参数,截取第一个参数后的所有参数。
●将函数作为上下文对象的一个属性。
●使用上下文对象来调用这个方法,并保存返回结果。
●删除刚才新增的属性。
●返回结果。
(2)apply 函数的实现步骤:
●判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
●判断传入上下文对象是否存在,如果不存在,则设置为 window 。
●将函数作为上下文对象的一个属性。
●判断参数值是否传入
●使用上下文对象来调用这个方法,并保存返回结果。
●删除刚才新增的属性
●返回结果
(3)bind 函数的实现步骤:
●判断调用对象是否为函数,即使是定义在函数的原型上的,但是可能出现使用 call 等方式调用的情况。
●保存当前函数的引用,获取其余传入参数值。
●创建一个函数返回
●函数内部使用 apply 来绑定函数调用,需要判断函数作为构造函数的情况,这个时候需要传入当前函数的 this 给 apply 调用,其余情况都传入指定的上下文对象。
面向对象:
1.对象的创建方式有哪些?
一般使用字面量的形式直接创建对象,但是这种创建方式对于创建大量相似对象的时候,会产生大量的重复代码。但 js和一般的面向对象的语言不同,在 ES6 之前它没有类的概念。但是可以使用函数来进行模拟,从而产生出可复用的对象创建方式,常见的有以下几种:
(1)第一种是工厂模式,工厂模式的主要工作原理是用函数来封装创建对象的细节,从而通过调用函数来达到复用的目的。但是它有一个很大的问题就是创建出来的对象无法和某个类型联系起来,它只是简单的封装了复用代码,而没有建立起对象和类型间的关系。
(2)第二种是构造函数模式。js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的,那么就可以把它称为构造函数。执行构造函数首先会创建一个对象,然后将对象的原型指向构造函数的 prototype 属性,然后将执行上下文中的 this 指向这个对象,最后再执行整个函数,如果返回值不是对象,则返回新建的对象。因为 this 的值指向了新建的对象,因此可以使用 this 给对象赋值。构造函数模式相对于工厂模式的优点是,所创建的对象和构造函数建立起了联系,因此可以通过原型来识别对象的类型。但是构造函数存在一个缺点就是,造成了不必要的函数对象的创建,因为在 js 中函数也是一个对象,因此如果对象属性中如果包含函数的话,那么每次都会新建一个函数对象,浪费了不必要的内存空间,因为函数是所有的实例都可以通用的。
(3)第三种模式是原型模式,因为每一个函数都有一个 prototype 属性,这个属性是一个对象,它包含了通过构造函数创建的所有实例都能共享的属性和方法。因此可以使用原型对象来添加公用属性和方法,从而实现代码的复用。这种方式相对于构造函数模式来说,解决了函数对象的复用问题。但是这种模式也存在一些问题,一个是没有办法通过传入参数来初始化值,另一个是如果存在一个引用类型如 Array 这样的值,那么所有的实例将共享一个对象,一个实例对引用类型值的改变会影响所有的实例。
(4)第四种模式是组合使用构造函数模式和原型模式,这是创建自定义类型的最常见方式。因为构造函数模式和原型模式分开使用都存在一些问题,因此可以组合使用这两种模式,通过构造函数来初始化对象的属性,通过原型对象来实现函数方法的复用。这种方法很好的解决了两种模式单独使用时的缺点,但是有一点不足的就是,因为使用了两种不同的模式,所以对于代码的封装性不够好。
(5)第五种模式是动态原型模式,这一种模式将原型方法赋值的创建过程移动到了构造函数的内部,通过对属性是否存在的判断,可以实现仅在第一次调用函数时对原型对象赋值一次的效果。这一种方式很好地对上面的混合模式进行了封装。
(6)第六种模式是寄生构造函数模式,这一种模式和工厂模式的实现基本相同,我对这个模式的理解是,它主要是基于一个已有的类型,在实例化时对实例化的对象进行扩展。这样既不用修改原来的构造函数,也达到了扩展对象的目的。它的一个缺点和工厂模式一样,无法实现对象的识别。
2.对象继承的方式有哪些?
(1)第一种是以原型链的方式来实现继承,但是这种实现方式存在的缺点是,在包含有引用类型的数据时,会被所有的实例对象所共享,容易造成修改的混乱。还有就是在创建子类型的时候不能向超类型传递参数。
(2)第二种方式是使用借用构造函数的方式,这种方式是通过在子类型的函数中调用超类型的构造函数来实现的,这一种方法解决了不能向超类型传递参数的缺点,但是它存在的一个问题就是无法实现函数方法的复用,并且超类型原型定义的方法子类型也没有办法访问到。
(3)第三种方式是组合继承,组合继承是将原型链和借用构造函数组合起来使用的一种方式。通过借用构造函数的方式来实现类型的属性的继承,通过将子类型的原型设置为超类型的实例来实现方法的继承。这种方式解决了上面的两种模式单独使用时的问题,但是由于我们是以超类型的实例来作为子类型的原型,所以调用了两次超类的构造函数,造成了子类型的原型中多了很多不必要的属性。
(4)第四种方式是原型式继承,原型式继承的主要思路就是基于已有的对象来创建新的对象,实现的原理是,向函数中传入一个对象,然后返回一个以这个对象为原型的对象。这种继承的思路主要不是为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5 中定义的 Object.create() 方法就是原型式继承的实现。缺点与原型链方式相同。
(5)第五种方式是寄生式继承,寄生式继承的思路是创建一个用于封装继承过程的函数,通过传入一个对象,然后复制一个对象的副本,然后对象进行扩展,最后返回这个对象。这个扩展的过程就可以理解是一种继承。这种继承的优点就是对一个简单对象实现继承,如果这个对象不是自定义类型时。缺点是没有办法实现函数的复用。
(6)第六种方式是寄生式组合继承,组合继承的缺点就是使用超类型的实例做为子类型的原型,导致添加了不必要的原型属性。寄生式组合继承的方式是使用超类型的原型的副本来作为子类型的原型,这样就避免了创建不必要的属性。
垃圾回收与内存泄漏:
1.浏览器的垃圾回收机制
垃圾回收:JavaScript代码运行时,需要分配内存空间来储存变量和值。当变量不在参与运行时,就需要系统收回被占用的内存空间,这就是垃圾回收。
垃圾回收方法:
标记清除:
- 标记清除是浏览器常见的垃圾回收方式,当变量进入执行环境时,就标记这个变量“进入环境”,被标记为“进入环境”的变量是不能被回收的,因为他们正在被使用。当变量离开环境时,就会被标记为“离开环境”,被标记为“离开环境”的变量会被内存释放。
●垃圾收集器在运行的时候会给存储在内存中的所有变量都加上标记。然后,它会去掉环境中的变量以及被环境中的变量引用的标记。而在此之后再被加上标记的变量将被视为准备删除的变量,原因是环境中的变量已经无法访问到这些变量了。最后。垃圾收集器完成内存清除工作,销毁那些带标记的值,并回收他们所占用的内存空间。
引用计数:
●
另外一种垃圾回收机制就是引用计数,这个用的相对较少。引用计数就是跟踪记录每个值被引用的次数。当声明了一个变量并将一个引用类型赋值给该变量时,则这个值的引用次数就是1。相反,如果包含对这个值引用的变量又取得了另外一个值,则这个值的引用次数就减1。当这个引用次数变为0时,说明这个变量已经没有价值,因此,在在机回收期下次再运行时,这个变量所占有的内存空间就会被释放出来。
●
这种方法会引起循环引用的问题:例如:obj1和obj2通过属性进行相互引用,两个对象的引用次数都是2。当使用循环计数时,由于函数执行完后,两个对象都离开作用域,函数执行结束,obj1和obj2还将会继续存在,因此它们的引用次数永远不会是0,就会引起循环引用。
(3)减少垃圾回收
虽然浏览器可以进行垃圾自动回收,但是当代码比较复杂时,垃圾回收所带来的代价比较大,所以应该尽量减少垃圾回收。
●对数组进行优化:在清空一个数组时,最简单的方法就是给其赋值为[ ],但是与此同时会创建一个新的空对象,可以将数组的长度设置为0,以此来达到清空数组的目的。
●对object进行优化:对象尽量复用,对于不再使用的对象,就将其设置为null,尽快被回收。●
对函数进行优化:在循环中的函数表达式,如果可以复用,尽量放在函数的外面。
2.哪些情况会导致内存泄漏?
以下四种情况会造成内存的泄漏:
●意外的全局变量:由于使用未声明的变量,而意外的创建了一个全局变量,而使这个变量一直留在内存中无法被回收。
●被遗忘的计时器或回调函数:设置了 setInterval 定时器,而忘记取消它,如果循环函数有对外部变量的引用的话,那么这个变量会被一直留在内存中,而无法被回收。
●脱离 DOM 的引用:获取一个 DOM 元素的引用,而后面这个元素被删除,由于一直保留了对这个元素的引用,所以它也无法被回收。
●闭包:不合理的使用闭包,从而导致某些变量一直被留在内存当中。
VUE框架
vue基础
1.vue基本原理
当一个Vue实例创建时,Vue会遍历data中的属性,用 Object.defineProperty(vue3.0使用proxy )将它们转为 getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化。 每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher重新计算,从而致使它关联的组件得以更新
2.双向数据绑定的原理
Vue.js 是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。主要分为以下几个步骤:
1需要observe的数据对象进行递归遍历,包括子属性对象的属性,都加上setter和getter这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化
2compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图
3Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: ①在自身实例化时往属性订阅器(dep)里面添加自己 ②自身必须有一个update()方法 ③待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。
4MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。
3.MVVM,MVC,MVP的区别
(1)MVC
MVC 通过分离 Model、View 和 Controller 的方式来组织代码结构。其中 View 负责页面的显示逻辑,Model 负责存储页面的业务数据,以及对相应数据的操作。并且 View 和 Model 应用了观察者模式,当 Model 层发生改变的时候它会通知有关 View 层更新页面。Controller 层是 View 层和 Model 层的纽带,它主要负责用户与应用的响应操作,当用户与页面产生交互的时候,Controller 中的事件触发器就开始工作了,通过调用 Model 层,来完成对 Model 的修改,然后 Model 层再去通知 View 层更新。
(2)MVVM
MVVM 分为 Model、View、ViewModel:
●Model代表数据模型,数据和业务逻辑都在Model层中定义;
●View代表UI视图,负责数据的展示;
●ViewModel负责监听Model中数据的改变并且控制视图的更新,处理用户交互操作;
(3)MVP
MVP 模式与 MVC 唯一不同的在于 Presenter 和 Controller。在 MVC 模式中使用观察者模式,来实现当 Model 层数据发生变化的时候,通知 View 层的更新。这样 View 层和 Model 层耦合在一起,当项目逻辑变得复杂的时候,可能会造成代码的混乱,并且可能会对代码的复用性造成一些问题。MVP 的模式通过使用 Presenter 来实现对 View 层和 Model 层的解耦。MVC 中的Controller 只知道 Model 的接口,因此它没有办法控制 View 层的更新,MVP 模式中,View 层的接口暴露给了 Presenter 因此可以在 Presenter 中将 Model 的变化和 View 的变化绑定在一起,以此来实现 View 和 Model 的同步更新。这样就实现了对 View 和 Model 的解耦,Presenter 还包含了其他的响应逻辑。
4.computed和watch区别
(1) 作用不同 : 计算属性解决模块渲染冗余问题,侦听器侦听某一个数据变化
(2) 语法不同 : 计算属性是新增一个属性,侦听器只能侦听data中的属性
(3) 计算属性有缓存,侦听器没有缓存
(4) 计算属性不支持异步操作,侦听器支持
(5) 计算属性可以监听多个数据变化,侦听器只能监听一个数据变化
(6) 计算属性默认会执行一次,而侦听器只有数据在第一次变化之后才会执行
watch的使用场景:一个数据影响多个数据,需要在数据变化时执行异步操作或者开销较大的操作时使用。
例如:搜索数据
computed的使用场景:一个数据受多个数据影响,处理复杂的逻辑或多个属性影响一个属性的变化时使用。
例如:购物车商品结算的时候
5.computed和methods的区别
可以将同一函数定义为一个 method 或者一个计算属性。对于最终的结果,两种方式是相同的
不同点:
●computed: 计算属性是基于它们的依赖进行缓存的,只有在它的相关依赖发生改变时才会重新求值;
●method 调用总会执行该函数。
6.v-if和v-show的区别
相同点: v-show 和v-if都是true的时候显示,false的时候隐藏
1.原理不同:v-if本质是元素新增与移除,v-show本质是修改元素的display属性
2.场景不同:v-if用于不需要频繁切换的元素,v-show用于需要频繁切换的元素
3.性能不同:v-if初始渲染性能高,切换性能低.v-show初始化渲染性能低,切换性能高
7.data为什么设计一个函数而不是一个对象
因为JavaScript的特性所导致,在component中,data必须以函数的形式存在,不可以是对象。
组建中的data写成一个函数,数据以函数返回值的形式定义,这样每次复用组件的时候,都会返回一份新的data,相当于每个组件实例都有自己私有的数据空间,它们只负责各自维护的数据,不会造成混乱。而单纯的写成对象形式,就是所有的组件实例共用了一个data,这样改一个全都改了。
8.vue单页应用和多页应用的区别????????
概念:
●SPA单页面应用(SinglePage Web Application),指只有一个主页面的应用,一开始只需要加载一次js、css等相关资源。所有内容都包含在主页面,对每一个功能模块组件化。单页应用跳转,就是切换相关组件,仅仅刷新局部资源。
●MPA多页面应用 (MultiPage Application),指有多个独立页面的应用,每个页面必须重复加载js、css等相关资源。多页应用跳转,需要整页资源刷新。
9.对react和vue的理解,他们的异同
React
React 是一个用于构建用户界面的 JavaScript 库,特别适合于构建复杂的大型应用。React 的主要特性包括:
组件化:React 鼓励开发者将应用分割成多个小部件,每个部件负责一部分 UI,这样可以提高代码的可重用性和可维护性。
虚拟 DOM:React 使用虚拟 DOM 来高效地更新视图,通过 Diff 算法来最小化实际 DOM 操作。
单向数据流:React 采用单向数据流,数据通过 props 向下传递,而不是通过事件向上传递。
JSX:React 使用 JSX 这种类 XML 的语法来描述用户界面,使得编写用户界面变得像编写 HTML 一样直观。
Vue
Vue 是一个用于构建用户界面的渐进式 JavaScript 框架,同样特别适合于构建复杂的大型应用。Vue 的主要特性包括:
组件化:Vue 也鼓励开发者将应用分割成多个小部件,每个部件负责一部分 UI,这样可以提高代码的可重用性和可维护性。
响应式数据绑定:Vue 使用响应式数据绑定,这意味着数据发生变化时,视图会自动更新。
虚拟 DOM:Vue 同样使用虚拟 DOM 来高效地更新视图,通过 Diff 算法来最小化实际 DOM 操作。
模板语法:Vue 使用模板语法,通过指令来处理 DOM 操作,使得编写用户界面变得像编写 HTML 一样直观。
相同点:
组件化:React 和 Vue 都推崇组件化,通过将页面拆分成一个一个小的可复用单元来提高代码的复用率和开发效率。
虚拟 DOM:React 和 Vue 都使用虚拟 DOM 来高效地更新视图,通过 Diff 算法来最小化实际 DOM 操作。
数据驱动视图:React 和 Vue 都实现了数据驱动视图,开发者只需要关注数据的变化,而不需要关心视图的更新。
不同点:
数据流:React 一直提倡单向数据流,数据通过 props 向下传递;而 Vue 默认支持双向绑定,数据发生变化时视图会自动更新。
模板语法:React 使用 JSX,将 HTML 直接嵌入 JavaScript 代码中;Vue 使用模板语法,通过指令来处理 DOM 操作。
学习曲线:React 学习曲线较陡峭,特别是对于理解虚拟 DOM 和 JSX 的新手;Vue 学习曲线较为平缓,文档清晰,适合初学者。
生态系统:React 生态系统庞大,有大量的第三方库和工具支持;Vue 生态系统相对较小,但也在不断发展壮大。
10.vue的优点
11.对spa单页面的理解,他的优缺点
生命周期:
1.vue生命周期
●轻量级框架:只关注视图层,是一个构建数据的视图集合,大小只有几十 kb ;
●简单易学:国人开发,中文文档,不存在语言障碍 ,易于理解和学习;
●双向数据绑定:保留了 angular 的特点,在数据操作方面更为简单;
●组件化:保留了 react 的优点,实现了 html 的封装和重用,在构建单页面应用方面有着独特的优势;
●视图,数据,结构分离:使数据的更改更为简单,不需要进行逻辑代码的修改,只需要操作数据就能完成相关操作;
●虚拟DOM:dom 操作是非常耗费性能的,不再使用原生的 dom 操作节点,极大解放 dom 操作,但具体操作的还是 dom 不过是换了另一种方式;
●运行速度更快:相比较于 react 而言,同样是操作虚拟 dom,就性能而言, vue 存在很大的优势。
组件通信
1.组件通信有哪些方式
1.props和emit
2.$ref,dispose
3.eventbus
4.provide/inject
5.插槽
6.$attrs
路由
1.路由hash和history模式区别
vuex/pinia
1.vuex原理和理解
2.vuex中action和mutation区别
3.redux和vuex的区别,共同思想
vue3
1.vue3的更新
2.defineProperty和proxy区别
虚拟dom
1.对虚拟dom的理解
2.diff算法的原理
网络
浏览器
1.BFC理解,那些可以开启BFC
BFC 英文名为 Block Formatting Context (块级格式化上下文)
- 内部的盒子会在垂直方向上一个接一个的放置
- BFC 就是页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素,反之亦然
- BFC的作用
元素开启BFC后,子元素不会发生margin塌陷问题,解决margin重叠(塌陷)问题
元素开启BFC后,子元素脱离文档流父元素无法撑开,解决子元素浮动的问题,
- BFC有几种常见的方法:
满足下列条件之一就可以触发 BFC:
HTML 根元素
position 为 absolute 或 fixed
float 属性不为 none(常用)
overflow 不为 visible(常用)例如hidden、auto或scroll。
display 为 inline-block, table-cell, table-caption, flex
2.标准盒模型和怪异盒模型区别,如何设置
通过CSS3的box-sizing属性来控制元素的盒模型。
当box-sizing属性的值为content-box时,使用的是标准盒模型;
当box-sizing属性的值为border-box时,使用的是怪异盒模型。
在标准盒模型中,元素的总宽度是由元素的内容宽度(content)、内边距(padding)、边框(border)和外边距(margin)四部分相加得到的。css中设置盒子的width,height只代表内容的尺寸,不包括内边距、边框和外边距。
在怪异盒模型中,元素的总宽度是由元素的内容宽度(content)加上内边距(padding)和边框(border)三部分相加得到的。也就是说,css中设置盒子的width,height,(元素的宽度和高度)不仅包括内容的尺寸,还包括内边距和边框。
3.rem,em区别
em和rem都是在CSS布局中常用的相对长度单位;
- em,em是相对于当前元素的字体大小。
- rem是CSS3新增的相对长度单位,全称为root em,是相对于根元素(通常是HTML元素)。通常的做法是给HTML元素设置一个字体大小,然后其他元素的长度单位就为rem。这意味着,如果HTML元素的font-size是20px,那么1rem就等于20px
4.数据类型,typeof null 是什么?
- 基本数据类型,也被称为原始值,包括:
Number:数值类型,包括整数和浮点数,也可以表示为科学记数法的形式。例如 123,0.123,1.23e4 等。
String:字符串类型,用于表示文本信息,比如 ‘Hello World’。
Boolean:布尔类型,只有两个可能的值,即 true 和 false。
Undefined:未定义类型,表示变量已经声明,但还未赋值。
Null:空类型,表示变量没有值。
Symbol:符号类型,ES6 新增的数据类型,主要用于创建唯一的标识符。
BigInt:大整数类型,ES 2020新增,能够表示超过 Number 类型大小限制的整数。
- 引用数据类型,引用数据类型,包括:
Object:对象类型,包括普通对象、数组和函数等。
typeof null == ‘object’
在 JavaScript 中,数据类型在底层都是以二进制形式表示的,二进制的前三位为 0 会被 typeof 判定为对象类型,如下所示:
000 - 对象,数据是对象的应用
1 - 整型,数据是31位带符号整数
010 - 双精度类型,数据是双精度数字
100 - 字符串,数据是字符串
110 - 布尔类型,数据是布尔值
而 null 值的二进制表示全是 0 ,自然前三位当然也是 000,因此,typeof 会误以为是对象类型。如果想要知道 null 的真实数据类型,可以通过下面的方式来获取。
Object.prototype.toString.call(null) ; // [object Null]
5.原型链
JavaScript中的每个对象都有一个内部的[[Prototype]]属性,也称为原型(prototype),它指向另一个对象或者null。当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript会沿着它的原型链一层层向上查找,直到找到该属性或方法或者原型链到达顶端(即Object.prototype,它是所有对象的祖先)为止。
在JavaScript中,每个对象都有一个指向它的原型的链接,这就是所谓的原型链。原型链是JavaScript实现继承的一种方式。
- 原型链的工作原理
当尝试访问一个对象的属性时,JavaScript不仅会在该对象本身上查找,还会在其原型上查找,然后再查找其原型的原型,这个过程会一直持续到找到匹配的属性或达到原型链的末尾。如果最终没有找到匹配的属性,那么JavaScript会返回undefined。
6.闭包,闭包会有什么问题,内存泄漏,怎么进行垃圾回收
(1) 闭包是有权访问另一个函数作用域变量的函数
(2) 闭包一般是函数嵌套,一个函数返回另外一个函数,内部函数访问外部函数的变量就形成了一个闭包
(3) 闭包的优点是可以私有化变量,将变量私有化到函数内部,并在私有化的基础上进行数据保持
(4) 闭包在防抖节流函数柯里化,都应用里数据保持这个特性
(5) 在防抖函数中,第一次点击的时候,我们会let一个time一个定时器,如果不采用闭包的话,下次触发函数会重新创建一个新的定时器,两个定时器的引用不同,是没有关联的,使用闭包可以直接在内存中找到之前创建的计时器,调用就可以直接拿到对应的定时器的时间
(6) 闭包的缺点是容易造成内存泄露,因为闭包创建的变量会一直存在内存中,需要及时置空,否则会造成内存泄露,影响程序性能
7.flex:1 是什么缩写
flex: 1 实际上是三个属性的缩写:flex-grow: 1; flex-shrink: 1 flex-basis: auto;
可放大可缩小,
8.vue.use做了那些事件
可以通过Vue.use方法来注册插件。该方法接收一个插件对象作为参数,该对象必须包含一个名为install的方法。如果插件对象带有install方法,Vue.use会执行该方法,并将Vue构造函数作为第一个参数传入。如果插件对象是一个函数,Vue.use会直接将该函数作为插件的注册方法,同样将Vue构造函数作为第一个参数。
Vue.use的工作流程包括以下步骤:
1.检查插件是否已经注册,如果已经注册则直接跳过注册过程。
2.处理入参,将第一个参数之后的参数归集,并在首部塞入this上下文。
3.执行注册方法,如果插件对象有install方法,则调用该方法,传入处理后的参数。如果插件对象是一个函数,则直接让该函数执行。
4.缓存插件,以避免重复注册。
9.跨域解决方法
1.JSONP
动态创建script请求
带上callback,服务器执行带上参数回调方法
缺点
具有局限性,只支持GET请求
不安全,可能会遭受XSS攻击
2.cors(跨域资源共享
需要浏览器和服务器同时支持
分为简单请求和非简单请求
简单请求不会触发cors预检请求
简单请求
浏览器直接发出
非简单请求
在正式通信前进行一次HTTP查询请求,称为预检请求
浏览器会询问服务器,当前所在网页是否在服务器允许访问的范围内,
以及可以使用哪些HTTP请求和头信息字段,
只有得到肯定的答复,才会进行正式的HTTP请求,否则就会报错
预检请求使用的请求方法是OPTIONS
3.postMessage跨域
是HTML5中XMLHttpRequest中的API
解决以下问题
页面和其打开的新窗口的数据传递
多窗口之间的消息传递
页面与嵌套的iframe消息传递
上面三个场景的跨域数据传递
a.html
<iframe id="iframe" src="http://www.domain2.com/b.html" style="display:none;"></iframe>
<script>
var iframe = document.getElementById('iframe');
iframe.onload = function () {
var data = {name: 'aym'};
// 向domain2传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data), 'http://www.domain2.com');
};
// 接受domain2返回数据
window.addEventListener('message', function (e) {
alert('data from domain2 ---> ' + e.data);
}, false);</script>
b.html
<script>
// 接收domain1的数据
window.addEventListener('message', function (e) {
alert('data from domain1 ---> ' + e.data);
var data = JSON.parse(e.data);
if (data) {
data.number = 16;
// 处理后再发回domain1
window.parent.postMessage(JSON.stringify(data), 'http://www.domain1.com');
}
}, false);
</script>
4.代理跨域
nginx代理
nodejs中间件代理
webpack-dev-server代理
5.iframe
document.domain + iframe
仅限主域相同子域不同的跨域场景
原理:两个页面都通过js强制设置document.domain为基础主域
location.hash + iframe跨域相互通信
原理:a与b跨域通信,通过中间页来实现,
不同域通过iframe的location.hash传值,相同域用js访问
window.name + iframe跨域相互通信
原理:name在不同页面加载后依旧存在
通过iframe的src属性由外域转向本地域,跨域数据window.name由外域转向本地域
巧妙的绕过了浏览器的跨域访问限制
6.WebSocket协议跨域
它实现了浏览器与服务器的全双工通信,同时允许跨域通信
10.src和href的区别,
src和href都是用来引用外部的资源
区别:
1.src是表示对资源的引用,href是表示超文本引用,它指向一些网络资源,建立和当前元素或本文档的链接关系
2.对文档的影响不同,src会直接影响文档的加载和显示,当浏览器识别到它他指向的⽂件时,就会并⾏下载资源,不会停⽌对当前⽂档的处理
3.适用范围不同,src适用于图片、音频、视频和脚本等资源的引用,href适用于css样式表、字体文件和网页链接
11.script标签中的defer和async的区别,
如果没有defer或async属性,浏览器会立即加载并执行相应的脚本,defer 和 async属性都是去异步加载外部的JS脚本文件,它们都不会阻塞页面的解析
区别:
1.多个脚本的执行顺序不同,多个带async属性的标签,不能保证加载的顺序;多个带defer属性的标签,按照加载顺序执行
2.执行时机不同,async加载完立即执行,defer加载完会到文档所有元素解析完成之后才执行,DOMContentLoaded事件触发执行之前。
12.sass less是什么,为什么使用他们
是 CSS 预处理器,CSS预处理器的主要目的是增强CSS的功能,并提供一些在原生CSS中不可用或不便于使用的特性。
- 变量和嵌套:Sass和Less都支持使用变量来存储和重用样式属性,这样可以减少重复的代码,并且使样式表更易于维护。
- 混合器和继承:Sass和Less允许定义和使用混合器(Mixin),可以将一组样式属性定义为一个混合器,然后在需要的地方引用。实现样式的复用。
- 导入和模块化:Sass和Less允许将样式表拆分为多个文件,并通过导入语句组合在一起。这样可以实现样式的模块化,提高可维护性。
- 运算和函数:Sass和Less都支持使用算术运算和自定义函数,可以在样式表中进行计算和操作。
箭头函数与普通函数的区别
与普通函数相比,他:
1.写法更加简洁,可以根据具体情况省略 小括号,return 等。这一点在高阶函数的使用中特别方便。例如,数组的map, forEach等.
2.箭头函数内部没有自己的 this ,它的this就是外层作用域的 this 。它不能通过call,apply,bind来修改。
3.箭头函数内部没有arguments对象。但是,es6配套提供了剩余参数,可以用来替代argument.
4.不能当前构造器来使用。
5.没有原型
6.new箭头函数会发生什么
不能成功,因为它没有prototype,也没有自己的this指向
new操作符的实现步骤如下:
1创建一个对象
2将构造函数的作用域赋给新对象(也就是将对象的proto属性指向构造函数的prototype属性)
3指向构造函数中的代码,构造函数中的this指向该对象(也就是为这个对象添加属性和方法)
4返回新的对象
所以第二部第三部无法完成
7.Vue的基本原理
vue实例创建时,
1.遍历data属性,vue3是ref和reative,
2.用 Object.defineProperty(vue3.0使用proxy )将它们转为 getter/setter,并且在内部追踪相关依赖,在属性被访问和修改时通知变化
3. 每个组件实例都有相应的 watcher ,在组件渲染的过程中把属性记录为依赖,之后当依赖项的setter被调用时,会通知watcher,更新关联的组件。
8.vue-router的基本原理
Vue-Router有两种模式:hash模式和history模式。默认的路由模式是hash模式
hash模式:
hash模式是开发中默认的模式,它的URL带着一个#;
hash模式的主要原理就是onhashchange()事件:
使用onhashchange()事件的好处就是,在页面的hash值发生变化时,无需向后端发起请求
history模式:
history api可以分为两大部分,切换历史状态和修改历史状态:
使用浏览器的history属性
●
修改历史状态:History的 pushState() 和 replaceState() 方法,当
他们进行修改时,虽然修改了url,但浏览器不会立即向后端发送请求。如果要做到改变url但又不刷新页面的效果,就需要前端用上这两个API。
●切换历史状态: 包括forward()、back()、go()三个方法,对应浏览器的前进,后退,跳转操作
块元素,行内元素有哪些?行内元素怎么变成块元素,行内元素和行内块元素区别
(1)block:会独占一行,多个元素会另起一行,可以设置width、height、margin和padding属性;
h,p,div
(2)inline:元素不会独占一行,设置width、height属性无效。但可以设置水平方向的margin和padding属性,不能设置垂直方向的padding和margin;
span,a,img
(3)inline-block:将对象设置为inline对象,但对象的内容作为block对象呈现,之后的内联对象会被排列在同一行内。
for……in……和for……of……区别
1.功能不同
for-in是遍历数组的下标
for-of是遍历数组的元素
2.原型的属性
for-in会遍历原型的属性
for-of不会遍历原型的属性
3.数据类型
for-in可以遍历Object类型
for-of不可以遍历对象Object类型,不是可迭代对象
map和weakmap区别
-
Map 和 WeakMap 都属于 ES6 中新增的数据类型,用于存储键值对。
-
Map 是一个普通的键值对集合,可以使用任何类型的值作为键或值,包括基本类型和对象。
而 WeakMap 的键必须是对象,值可以是任何类型。 -
Map 中的键值对是强引用关系,即只要 Map 中的键或值存在,Map 对象就会一直保留这个键值对,不会被垃圾回收。而 WeakMap 中的键值对是弱引用关系,如果 WeakMap 的键不再被引用,那么这个键值对就会被自动删除。
-
由于 WeakMap 中的键是弱引用,所以 **WeakMap 对象的 size 属性无法访问,**也无法使用 forEach() 和 clear() 等方法。
-
WeakMap 对象的主要应用场景是需要与另外一个对象关联,并且不想影响到这个对象的垃圾回收机制,以避免内存泄漏。例如,将对象存储在 WeakMap 中,可以确保这个对象只在其他地方仍然被引用时才被保留,否则会自动被删除,从而避免内存泄漏。
垃圾回收机制
原理:垃圾收集器会定期(周期性)找出那些不在继续使用的变量,然后释放其内存
通常情况下有两种实现方式:
标记清除:
当变量进入执行环境是,就标记这个变量为“进入环境“。进入环境的变量所占用的内存就不能释放,当变量离开环境时,则将其标记为“离开环境“
垃圾回收程序运行的时候,会标记内存中存储的所有变量。然后,它会将所有在上下文中的变量,以及被在上下文中的变量引用的变量的标记去掉
在此之后再被加上标记的变量就是待删除的了,原因是任何在上下文中的变量都访问不到它们了
随后垃圾回收程序做一次内存清理,销毁带标记的所有值并收回它们的内存
引用计数::
引用引擎有一张"引用表",保存了内存里面所有的资源(通常是各种值)的引用次数。如果一个值的引用次数是0,就表示这个值不再用到了,因此可以将这块内存释放
浏览器渲染过程
解析 HTML,构建 DOM 树
解析 CSS ,生成 CSS 规则树
合并 DOM 树和 CSS 规则,生成 render 树
布局 render 树( Layout / reflow ),负责各元素尺寸、位置的计算
绘制 render 树( paint ),绘制页面像素信息
浏览器会将各层的信息发送给 GPU,GPU 会将各层合成( composite ),显示在屏幕上
从输入url开始到页面渲染过程
1、用户在浏览器中输入url地址
2、先判断是否有缓存,浏览器从dns解析域名得到服务器ip地址
3、TCP三次握手建立客户端和服务器的连接
三次握手:指建立一个tcp连接时,需要客户端和服务端总要发三个包。保证数据在传输时的一个完整性。
4、客户端发送HTTP请求获取服务器端的静态资源
5、服务器发送HTTP响应报文给客户端,客户端获取到页面静态资源
6、TCP四次挥手关闭客户端和服务器的连接
四次挥手:TCP的连接的拆除需要发送四个包,因此称为四次挥手。
为什么挥手要四次:因为Tcp是全双工通信的,同时也是为了数据的完整性。
7、浏览器解析文档资源并渲染页面
回流重绘区别
回流:布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
回流触发时机:
添加或删除可见的DOM元素
元素的位置发生变化
元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代
页面一开始渲染的时候(这避免不了)
浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)
重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制
重绘触发时机:
颜色的修改
文本方向的修改
阴影的修改
如何判断数据类型,typeof null 为什么是object
1.typeof 判断的粒度比较粗,它能准确判断基础类型(不包括null)和 Object 和 Function。 换句话,它不能判断null 和 Array ,会把他们都判断为object。
2.instanceof 用来判断对象的更具体的类型。instanceof的模拟实现, 它的主要原理的是沿着对象的原型链的方向,判断原型对象是否是构造器的prototype。 instanceof和typeof的区别
3.Array.isArray 专门用来判断是否是数组。
4.Object.prototype.toString.call 是最全面的方法了。它的代码运行如下
如何继承原型对象???
1、原型链继承;将父类的实例作为子类的原型。
2、构造继承;使用父类的构造函数来增强子类实例。
3、实例继承;为父类实例添加新特性,作为子类实例返回。
4、拷贝继承。
5、组合继承。call式继承 + 原型继承
ex6中 extends继承
如何改变this执行,有什么区别
apply,bind,call
共同点:
都可以修改this,第一个参数都是修改的this
不同点:
传参方式不同:call,bind是逐一传参,, apply是数组/伪数组传参
执行机制不同:call和apply会立即执行函数,bind不会立即执行
v-if,v-show,v-html的原理
-
v-if会调用addIfCondition方法,生成vnode的时候会忽略对应节点,render的时候就不会渲染;
-
v-show会生成vnode,render的时候也会渲染成真实节点,只是在render过程中会在节点的属性中修改show属性值,也就是常说的display;
-
v-html会先移除节点下的所有节点,调用html方法,通过addProp添加innerHTML属性,归根结底还是设置innerHTML为v-html的值。
v-if,v-show区别
相同点: v-show 和v-if都是true的时候显示,false的时候隐藏
1.原理不同:v-if本质是元素新增与移除,v-show本质是修改元素的display属性
2.场景不同:v-if用于不需要频繁切换的元素,v-show用于需要频繁切换的元素
3.性能不同:v-if初始渲染性能高,切换性能低.v-show初始化渲染性能低,切换性能高
v-model是如何实现的
v-model的本质上来说,是一个语法糖 目前咱们习惯性的写法是这样的:
是:value=“val” 和@input="val=$event.target.value"的语法糖
vue3是:model-value和@update:modelvalue
nextick原理,作用
Vue 的 nextTick 其本质是对 JavaScript 执行原理 EventLoop 的一种应用。
nextTick 的核心是利用了如 Promise 、MutationObserver、setImmediate、setTimeout的原生 JavaScript 方法来模拟对应的微/宏任务的实现,本质是为了利用 JavaScript 的这些异步回调任务队列来实现 Vue 框架中自己的异步回调队列。
作用是确保操作的是更新完成之后的dom
vue2vue3区别
1、生命周期的改变(setup代替了之前的beforeCreate和created,其他生命周期名字有些变化,功能都是没有变化的)
2、 proxy代替defineProperty
3、性能方面的改变(Diff算法的提升)
4、选项式api新增的compositionAPI(组合式API)
5、v-model的变化
6、更支持ts
父子组件传值
1.props,emit
2.ref
3.provide,inject
4.eventbus
●子组件通过 props 属性来接受父组件的数据,然后父组件在子组件上注册监听事件,子组件通过 emit 触发事件来向父组件发送数据。
●通过 ref 属性给子组件设置一个名字。父组件通过 $refs 组件名来获得子组件,子组件通过 $parent 获得父组件,这样也可以实现通信。
●使用 provide/inject,在父组件中通过 provide提供变量,在子组件中通过 inject 来将变量注入到组件中。不论子组件有多深,只要调用了 inject 那么就可以注入 provide中的数据。
vue3生命周期
2.四个阶段8个钩子:8个
(1)初始化阶段: beforeCreate created
(2)挂载阶段: beforeMount mounted
(3)更新阶段: beforeUpdate updated
(4)销毁阶段: beforeDestroy destroyed
3.两个常用
(1)created() : 一般用于发送ajax(页面一加载需要发送ajax在这个钩子)
(2)mounted(): 一般用于操作DOM(页面一加载需要操作DOM在这个钩子)
渲染列表为什么不用index作为key值
key 是为 Vue 中 vnode 的唯一标记,通过这个 key,diff 操作可以更准确、更快速
使用index 作为 key和没写基本上没区别,因为不管数组的顺序怎么颠倒,index 都是 0, 1, 2…这样排列,比如数组中间的一个数删掉了,就会导致 Vue 会复用错误的旧子节点,做很多额外的工作