css +html 基础
1.position 对应的几个属性:
position:fixed; // 相对于浏览器窗口进行固定位置
拓展:
如何给默认是视口定位,改变成父元素定位
给父元素添加:
1. transform: translate(0,0);
2.
perspective: 100px;
3.
使得子元素便可相对父元素设置position:fixed
position:relative; //相对于他原本的位置进行移动
position:absolute; // 相对于他的父元素进行移动
position:sticky; // 粘性定位sticky relative+fixed 相结合
nav {
position: -webkit-sticky;
position: sticky;
top: 0;
}
适合导航的跟随定位效果。
position:Static; // 没有定位,元素出现在正常的流中
position:inherit; // 规定应该从父元素继承position 属性的值。
2.如何用css画一个三角形?
.d5{
width: 0;
height: 0;
border-width: 20px;
border-style: solid;
border-color:#0099CC transparent transparent transparent;
transform: rotate(90deg);
}
3.css水平、垂直居中的写法,请至少写出4种?
水平居中:
1.行内元素:text-align: center
2.块级居中:margin: 0 auto
3.定位+transform:
position:absolute; left:50%; transform:translateX(-50%) or margin-left:-width/2;
4.flex布局:display:flex; justify-content: center
垂直居中:
line-height 等于height
position:absolute +top:50%+ transform:translateY(-50%) or margin-left:-height/2;
display:flex + align-items: center
display:table son: display:table-cell + vertical-align: middle;

4. 清除浮动的几种方式,及原理?
1. clear: both; 给需要清除浮动的元素添加 clear: both
2. 在有浮动的父级元素的末尾插入了一个没有内容的块级元素div: <div style="clear:both"></div>
3. 利用伪元素(clearfix)
.clearfix:after {
content: '.';
height: 0;
display: block;
clear: both;
}
4. 给父元素添加 overflow: auto
5. 左边固定,右边自适应
1. 浮动: float+margin-left 记住在父元素上清除浮动
2. 定位:position + margin-left 左边绝对定位,右边margin-left
3. table: 父元素display:table 左右子元素display:table-cell
4. flex:父元素display:flex 左边元素:flex:0 0 200px 右边元素width:200px
6. Less 使用
1. 定义变量:用@方式定义 Sass是用$方式定义
2. 样式嵌套:div{height:100px;h1 {color:blue}}
3. 继承:使用@extend命令,
.class1 { border: 1px solid #ddd; }
.class2 { @extend .class1; font-size:120%;}
4. 可以混入:使用@mixin命令,定义一个代码块。使用@include调用
@mixin left {
float: left;
margin-left: 10px;
}
使用@include命令,调用这个mixin。
div {
@include left;
}
@mixin left($value: 10px) {
float: left;
margin-right: $value;
}
div {
@include left(20px);
}
5. 可以定义函数
@function double($n) {
@return $n * 2;
}
#sidebar {
width: double(5px);
}
7.行内元素,块级元素,空元素
行内元素:span,a,b,strong,em,i,img,br,em,del,input
块级元素:h1-h6,div,p,ul,ol,dl
空元素:br,hr,input,img,link,meta
8.bootstrap响应式实现原理
百分比布局+媒体查询
9.flex布局
容器属性:
flex-direction:row/row-reverse/column/column-reverse 决定主轴的方向
flex-wrap:nowrap/wrap/wrap-reverse(第一行在下方) 一条轴线排不下如何换行,默认不换行
flex-flow: row nowrap 是主轴方向以及是否换行的缩写,默认从左往右不换行
justify-content: flex-start/flex-end/center/space-betwen/spave-around 定义项目在主轴的对齐方式
eg:
<div class="container">
<header>header...</header>
<main>内容</main>
<footer>footer...</footer>
</div>
1.上下布局,中间自适应:header + main + footer
header{
height:100px;
background:#ccc;
}
footer{
height:100px;
background:#ccc;
}
.container{
display:flex; // flex 布局
flex-direction:column; // flex 主轴方向
height:100vh;
}
main{
flex-grow:1; // 自动填充剩余部分
}
2.圣杯布局:左右固定,中间自适应 left+main+right
.container{
display:flex;
height:100vh;
}
aside{
width:50px;
background:#ccc;
}
main{
flex-grow:1;
background:#def;
}
nav{
width:80px;
background:#ccc;
order:-1;
}
3.水平垂直居中
.container{
height:300px;
width:300px;
border:1px solid red;
display:flex;
justify-content:center;
align-items:center;
}
.inner{
border:1px solid black;
}
10.rem如何实现?
11.calc()是怎么实现计算?
12.伪类和伪元素?
伪类:
在正常的选择器后面加上伪类名称,中间用冒号(:)隔开。
标记状态的伪类:
:hover:选取鼠标悬停的元素,
:link选取未访问过的超链接元素,
:visited选取访问过的超链接元素,
:active选取点中的元素,
:focus选取获得焦点的元素
eg:
a:{
text-decoration: none;
}
a:hover{
text-decoration: underline;
}
筛选功能的伪类:
:empty,选取没有子元素的元素。
:checked,选取勾选状态的 input 元素, 只对 radio 和 checkbox 生效。
:disabled,选取禁用的表单元素。
:first-child,选取当前选择器下第一个元素。
:last-child,和 first-child 相反,选取当前选择器下最后一个元素。
:nth-child(an+b),选取指定位置的元素。这个伪类是有参数的,参数可以支持 an+b 的形式,这里 a 和 b 都是可变的,n 从0起。使用这个伪类可以做到选择第几个,或者选择序号符合 an+b 的所有元素。比如使用 li:nth-child(2n+1),就可以选中 li 元素中序号是2的整数倍加1的所有元素,也就是第1、3、5、7、9、2n+1个 li 元素。
:nth-last-child(an+b),这个伪类和 nth-child 相似,只不过在计数的时候,这个伪类是从后往前计数。
:only-child,选取唯一子元素。
:only-of-type,选取唯一的某个类型的元素。
伪元素:
伪元素选择器是用于向某些元素设置特殊效果。伪元素选择器选中的并不是真实的 DOM 元素,所以叫伪元素选择器。
伪元素选择器常用:
::first-line,为某个元素的第一行文字使用样式。
::first-letter,为某个元素中的文字的首字母或第一个字使用样式。
::before,在某个元素之前插入一些内容。
::after,在某个元素之后插入一些内容。
::selection,对光标选中的元素添加样式。
13.Flex:1的缩写: flex-grow,flex-shrink,flex-basis的缩写
详细:
父级容器属性:
1.flex-direction: row | row-reverse | column | column-reverse; 该属性定义了 子元素排列方向
2. flex-wrap: nowrap | wrap | wrap-reverse; // 不换行// 换行 // 换行,第一行在下方。
3. flex-flow: || ; 是flex-direction属性和flex-wrap属性的简写形式,默认值为row nowrap。
4. justify-content: flex-start | flex-end | center | space-between | space-around; 左对齐/右对齐/居中/两端对齐/项目之间的间隔都相等/每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。
5. align-items: flex-start | flex-end | center | baseline | stretch; 交叉轴的起点对齐/交叉轴的终点对齐/交叉轴的中点对齐。/项目的第一行文字的基线对齐。/默认值):如果项目未设置高度或设为auto,将占满整个容器的高度
6. align-content: flex-start | flex-end | center | space-between | space-around | stretch;
子级容器属性:
1.order:0,定义子元素或者子容器的排列顺序。数值越小,排列越靠前,默认为0。
2.flex-grow:0,定义子元素或者子容器的放大比例,默认为0
3.flex-shrink:1定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
4.flex-basis:auto定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
5.flex:flex-grow, flex-shrink 和 flex-basis的简写,默认值0,1,auto
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
6.align-self:性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。
eg:
<div class="main">
<div class="top">上</div>
<div class="contain">中</div>
<div class="footer">下</div>
</div>
样式如下:
.main{
width: 500px;
background: chocolate;
padding:20px;
display: flex;
flex-direction: row ;
flex-wrap: nowrap;
flex-flow: row nowrap;
justify-content:flex-start ;
align-content:stretch;
align-items: baseline;
}
.top{
background: seagreen;
width:200px;
height:100px;
}
.contain{
background: sienna;
order:0;
flex-grow:1;
flex-shrink:1;
flex-basis:auto; ;
flex :1;
height: 50px;
}
.footer{
background: slateblue;
width: 200px;
}
14:如何用CSS实现0.5px的直线?
1.创建伪元素去实现
2.设置宽高,和display 为block
3.用CSS3的新增属性transform去实现缩放
transform:scale(0.5)
translate移动; scale缩放; rotate旋转;skew倾斜
4.所以宽度设置成200%,
div::before{
content:'';
display:block;
height:1px;
width:200%;
transform:scale(0.5);
position:absolute;
background-color:red;
}
采用meta viewport的方式:仅针对移动端
<meta name="viewport" content="width=device-width, initial-scale=0.5, minimum-scale=0.5, maximum-scale=0.5"/>
采用transform: scale()的方式:
transform: scale(0.5,0.5);
15.html和xhtml区别?
1.HTML是基于一种web网页设计语言,XHTML是基于XML置标语言
2.XHTML必须正确的嵌套关系
3.XHTML必须正确的关闭
4.XHTML标签名必须是小写
5.XXHTML必须有根标签
16.如何修改input 中placeholder中字体颜色 ?(::伪类:input-placeholder)
input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{
color:#666;
font-size:16px;
}
input:-moz-placeholder,textarea:-moz-placeholder{
color:#666;
font-size:16px;
}
input::-moz-placeholder,textarea::-moz-placeholder{
color:#666;
font-size:16px;
}
input:-ms-input-placeholder,textarea:-ms-input-placeholder{
color:#666;
font-size:16px;
}
17.使动画无限循环?
-webkit-animation:gogogo 2s infinite linear ;
18.css新增特性?HTML新增标签?
css新增特性:
1.边框属性:
border-radius:圆角边框
border-image:图片边框
box-shadow: 水平距离 垂直距离 模糊距离 阴影尺寸 颜色 inset(内阴影)
2.背景属性:
background-size:背景的尺寸
3.文字属性:
text-shadow:文本阴影效果
word-wrap:单词太长的话就可能无法超出某个区域,允许对长单词进行拆分,并换行到下一行
-webkit-text-stroke:宽度 颜色文本描边
text-overflow:ellipse(省略号);要和overflow: hidden; white-space:nowrap使用。
4.动画效果:
.box{
transform:translate(平移) / rotate(旋转) / scale(缩放) / skew(扭曲);
}
5.css3多列布局
6.渐变linear-gradient:线性渐变
7.animation 动画
HTML新增标签:
<article>标签定义外部的内容(结构元素)
<aside>定义页面内容之外的内容。 aside的内容与article的内容相关。(结构元素)
<figure>定义一组媒介内容的分组,以及它们的标题。(结构元素)
<section>标签定义文档中的节(section,区段)。比如章节,页眉,页脚或文档中的其他部分(结构元素)
<meter>定义预定义范围内的度量。仅用于已知最大和最小值的度量(内联元素)
<progress>定义任何类型的任务的进度。可以使用<progress>标签来显示javascript中耗费时间的函数的进度(内联元素)
<time>定义一个日期/时间 (内联元素)
<audio>定义声音内容。(内嵌元素)
audio 元素允许多个 source 元素。source 元素可以链接不同的音频文件。浏览器将使用第一个可识别的格式
<video>定义视频。(内嵌元素)
19.什么是BFC?BFC的作用?如何触发BFC?
BFC:块级格式化上下文,页面上的一个隔离的独立容器,容器里面的子元素不会影响到外面的元素
BFC的作用:
1.利用BFC避免margin重叠。
2.自适应两栏布局overflow: hidden;
3.计算BFC的高度时,浮动元素也参与计算。
如何触发BFC:
1、float的值不是none。
2、position的值不是static或者relative。
3、display的值是inline-block、table-cell、flex、table-caption或者inline-flex
4、overflow的值不是visible
20.css预处理器?
css预处理器:通过预处理器自己独有的语法来生成 CSS 的程序
sass:$申明
less:@声明变量
stylus:
可以使用的方法:
定义变量:
$font-size: 10px;
.mark{
font-size: 1.5 * $font-size;
}
代码混合:
@mixin clearfix {
&:after {
display: block;
content: '';
clear: both;
}
}
.sidebar{
@include clearfix;
}
代码嵌套:
.nav {
> li {
> a:hover {
background-color: red;
}
}
}
代码模块化:
@import './common';
@import './github-markdown';
@import './mixin';
@import './variables';
缺点:
1.额外的编译配置 配置sass-loader
2.编译成本,占用时间和cpu
3.学习成本
4.调试问题
javascript 基础
1.如何判断数据类型:(3种方法)
var a = "abcdef";
var b = 12345;
var c = true;
var d = null;
var e = undefined;
var f= [1,2,3];
var g= {a:1};
var h = function(){ console.log(111); };
var i = new Date();
var j = new RegExp()
方法一:typeof(a) 方式判断类型 适合基础类型判断
结合instanceof判断已知类型
var ff = f instanceof Array
var ii = i instanceof Date
var jj = j instanceof RegExp
方法二:通用方式使用 prototype (比较繁琐) 区分大小写
Object.prototype.toString.call(a) === '[object String]'
Object.prototype.toString.call(b) === '[object Number]'
Object.prototype.toString.call(c) === '[object Boolean'
Object.prototype.toString.call(d) === '[object Null]'
Object.prototype.toString.call(e) === '[object Undefined]'
Object.prototype.toString.call(f) === '[object Array]'
Object.prototype.toString.call(g) === '[object Object]'
Object.prototype.toString.call(h) === '[object Function]'
Object.prototype.toString.call(i) === '[object Date]'
Object.prototype.toString.call(j) === '[object RegExp]'
方法3::无敌万能的方法:jquery.type()
jquery.type(a)
2.数组去重:(推荐2种方法)
var arr = [1,2,3,2,1]
方法一:es6新特性 new Set() 利用成员的唯一性
var temp = [...new Set(arr)]
方法二:通过indexOf() 重组数组
var newArr = (()=>{
let temp = []
for(let i = 0;i<arr.length;i++){
if(temp.indexOf(arr[i]) === -1){
temp.push(arr[i])
}
}
return temp
})()
方法有很多,推荐使用以上2种
3.深拷贝浅拷贝
浅拷贝:基本数据类型的拷贝,并没有深浅拷贝的区别,浅拷贝的意思就是只复制引用,而未复制真正的值。
深拷贝:深浅拷贝都是对于引用数据类型而言的,深拷贝就是对目标的完全拷贝,不像浅拷贝那样只是复制了一层引用,就连值也都复制了
1.基本类型和引用类型
基本类型:String、Number、Boolean、Null、Undefined、Symbol。
引用类型:Array、Object。
3.赋值:
可以理解拷贝的一种,如果是基本类型不影响原对象,如果是引用类型则仅仅拷贝了引用地址,会影响到源对象,从而引出深浅拷贝,浅拷贝
基本类型赋值:互不影响
let s = '你好'
let ss = s
ss = 'hello'
console.log(s,ss)
引用类型赋值:相互影响
let obj = {
name:'小红',
age:18,
hobby:['打球','唱歌']
}
let newObj = obj
newObj.name = '小红2'
newObj.age = '29'
newObj.hobby = ['跳舞']
obj === newObj
创建一个新对象,这个对象有着原始对象的精确拷贝,如果属性是基本类型则拷贝的是对应的值,如果是引用类型,则拷贝的是对应的内存地址,如果其中一个对象改变了这个地址,会直接影响到原始对象 (复制第一层,子子孙孙若改变,会影响到源对象)
方法1:
eg: 手写一个浅拷贝
function shallowCopy(source){
var target = {}
for(var i in obj){
if(obj.hasOwnProperty(i)){
target[i] = source[i]
}
}
return target
}
方法2: Object.assign()
et obj1 = { person: {name: "kobe", age: 41},sports:'basketball' };
let obj2 = Object.assign({}, obj1);
obj2.person.name = "wade";
obj2.sports = 'football'
console.log(obj1);
方法3:es6中的展开运算符 ...
let obj1 = { name: 'Kobe', address:{x:100,y:100}}
let obj2= {... obj1}
方法4:Array.prototype.concat()
结论:concat 只是对数组的第一层进行深拷贝。
方法5:Array.prototype.slice()
结论:concat 只是对数组的第一层进行深拷贝。
方法6:函数库lodash的_.clone方法
`var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.clone(obj1);
console.log(obj1.b.f === obj2.b.f);// true`
3.深拷贝:从堆内存中开辟一个新的区域存放新对象,对对象中的子对象进行递归拷贝,拷贝前后的两个对象互不影响。(复制子子孙孙,与源对象互不影响)
方法1:
eg: 手写一个深拷贝
function deepCopy(obj){
if(obj === null) return obj
if(obj.instanceof Date) return new Date(obj)
if(obj.instanceof RegExp) return new RegExp(obj)
if(typeof obj !== 'object') return obj
let cloneObj = {}
for(let key in obj){
if(obj.hasOwnProperty(key)){
cloneObj[key] = deepCopy(obj[key])
}
}
return cloneObj
}
方法2:JSON.parse(JSON.stringify())
undefined、function、symbol 会在转换过程中被忽略
存在弊端: 时间对象--字符串 正则和error---空对象 函数----undefined NaN infinity -infinity ---- null
1、如果obj里面存在时间对象,JSON.parse(JSON.stringify(obj))之后,时间对象变成了字符串。
2、如果obj里有RegExp、Error对象,则序列化的结果将只得到空对象。
3、如果obj里有函数,undefined,则序列化的结果会把函数, undefined丢失。
-Infinity,则序列化的4、如果obj里有NaN、Infinity和结果会变成null。
5、JSON.stringify()只能序列化对象的可枚举的自有属性。如果obj中的对象是有构造函数生成的, 则使用JSON.parse(JSON.stringify(obj))深拷贝后,会丢弃对象的constructor。
6、如果对象中存在循环引用的情况也无法正确实现深拷贝。
方法3:函数库lodash的_.cloneDeep方法
var _ = require('lodash');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = _.cloneDeep(obj1);
console.log(obj1.b.f === obj2.b.f);
方法4:jQuery.extend()方法
$.extend(deepCopy, target, object1, [objectN])
var $ = require('jquery');
var obj1 = {
a: 1,
b: { f: { g: 1 } },
c: [1, 2, 3]
};
var obj2 = $.extend(true, {}, obj1);
console.log(obj1.b.f === obj2.b.f);
综上所述:
赋值运算符 = 实现的是浅拷贝,只拷贝对象的引用值;
JavaScript 中数组和对象自带的拷贝方法都是“首层浅拷贝”;
JSON.stringify 实现的是深拷贝,但是对目标对象有要求;
若想真正意义上的深拷贝,请递归。
4. 用js递归的方式写1到100求和?
function add(num1,num2) {
var num = num1 + num2;
if(num2+1>100) {
return num;
}else {
return add(num,num2+1)
}
}
var sum = add(1,2)
5. 说一下事件代理?
事件三阶段:捕获---》目标---》冒泡
事件代理:通过事件冒泡实现,减少内存占用以及事件注册
事件委托是指将事件绑定到目标元素的父元素上,利用冒泡机制触发该事件
ulEl.addEventListener('click', function(e){
var target = event.target || event.srcElement;
if(!!target && target.nodeName.toUpperCase() === "LI"){
console.log(target.innerHTML);
}
}, false);
6.js哪些操作会造成内存泄漏
1. 意外的全局变量
2. 闭包引起的内存泄漏
3,没有清理的dom元素引用
4,被遗忘的定时器或者回调
5,子元素存在引起的内存泄漏
7.防抖和节流 闭包的实际应用 (输入搜索)
防抖:当持续触发事件,一定时间内再次触发,事件处理函数只会执行一次 (定时器)持续触发,会再次等待时间
输入结束后n秒才进行搜索请求,n秒内又输入内容,则重新计算
var input = document.getElementById('input')
function debounce(delay){
let timer
return (value)=>{
clearTimeout(timer)
timer = setTimeout(()=>{
console.log(value)
},delay)
}
}
let debounceFun = debounce(1000)
input.addEventListener('keyup',(e)=>debounceFun(e.target.value))
节流:当持续触发事件的时候,保证一段时间内,只调用一次事件处理函数
鼠标不断点击触发,规定在n秒内多次点击只有一次生效
function Thor(fun,awite){
let timer
return ()=>{
if(!timer){
timer = setTimeout(() => {
fun()
timer = null
}, awite);
}
}
}
function fun(){
console.log(Math.random())
}
document.getElementById('button').onclick = Thor(fun, 1000)
8.实现一个面试题 输入1234567 输出:1,234,567 (4种方式)
1.普通方式:
function formatNumber(str) {
let arr = [],
count = str.length
while (count >= 3) {
arr.unshift(str.slice(count - 3, count))
count -= 3
}
// 如果是不是3的倍数就另外追加到上去
str.length % 3 && arr.unshift(str.slice(0, str.length % 3))
return arr.toString()
}
console.log(formatNumber("1234567890")) // 1,234,567,890
2.进阶版:(先转换成数组,然后数组取反,然后每隔3位设置字符)
function formatNumber(str) {
// ["0", "9", "8", "7", "6", "5", "4", "3", "2", "1"]
return str.split("").reverse().reduce((prev, next, index) => {
return ((index % 3) ? next : (next +
})
}
console.log(formatNumber("1234567890")) // 1,234,567,890
3.使用正则表达式
function formatNumber(str) {
return str.replace(/\B(?=(\d{3})+(?!\d))/g,
}
console.log(formatNumber("123456789")) // 1,234,567,890
4.API 版:
(123456789).toLocaleString(
new Intl.NumberFormat().format(1234567890) // 1,234,567,890
优点:简单粗暴,直接调用 API
缺点:Intl兼容性不太好,不过 toLocaleString的话 IE6 都支持
9.
10.CommonJs和Es Module及它们的区别?
二者都是为了解决一下问题:
1.解决变量污染问题。
2.解决代码维护问题。
3.解决文件依赖问题。
CommonJs使用:
1.导出:(module可以省略,但是只可导出单个值,无法导出对象值)
module.exports = {
name: "小红",
age: 24,
sex: "male"
}
module.exports.name = "小红"
module.exports.sex = null
module.exports.age = undefined
2.导入:(不可重复导入)
直接导入:
let data = require(''./index.js')
动态导入:
let lists = ["./index.js", "./config.js"]
lists.forEach((url) => require(url))
if (lists.length) {
require(lists[0])
}
ES Module 使用:
1.导出:单个导出(export)、默认导出(export default)
export const name = "小红"
export const age = 24
export function fn() {}
export const test = () => {}
const name = "小红"
const sex = "male"
export { name, sex }
2.导入:(静态)不可动态导入
export const name = "小红"
export const age = 24
import { name, age } from './index.js'
console.log(name, age)
import * as all from './index.js'
console.log(all)
区别:
1.mmonJs可以动态加载语句,Es Module是静态的,不可以动态加载语句
2.CommonJs导出值是拷贝,可以修改导出的值;Es Module导出是引用值之前都存在映射关系,并且值都是可读的,不能修改
3.CommonJs混合导出,还是一种语法,只不过不用声明前面对象而已,当我导出引用对象时之前的导出就被覆盖了;Es Module混合导出,单个导出,默认导出,完全互不影响
11.原型链原理?
理解:
1.js分普通对象和函数对象, 每一个对象都有一个__proto__属性,并且只有函数对象有prototype属性
2. Object和Function都是js的内置对象,类似常用Array,RegExp,Date,Boolean,String,Number
3.属性__proto__是一个对象,包含2个属性 constructor和__proto__
4.原型对象prototype有一个默认的constructor属性,用于记录实例是由哪个构造函数创建的
eg:
function Person(name,age){
this.name = name
this.age = age
}
Person.prototype.motherLand = 'china'
var son = new Person('小红',18)
则:
son.__proto__=== Person.prototype
Person.prototype.constructor === Person
Object.prototype.__proto__ = null;
Array.prototype.__proto__ = Object.prototype;
Foo.prototype.__proto__ = Object.prototype;
function Supermarket(){}
Supermarket.prototype.product = '口罩'
function Shop(){}
Shop.prototype = new Supermarket()
var person = new Shop()
console.log(Shop.prototype.__proto__===Supermarket.prototype)
console.log(Supermarket.prototype.__proto__===Object.prototype)
console.log(Object.prototype)
console.log(person.__proto__===Shop.prototype)
console.log(person.__proto__.__proto__.__proto__===Object.prototype)
12:闭包原理?
概念:有权访问另一个函数作用域中变量的函数
优点:保护函数的私有变量不受外部的干扰。形成不销毁的栈内存。
保存,把一些函数内的值保存下来。闭包可以实现方法和属性的私有化
缺点:导致内存泄漏
eg:
var n = 10
function fn(){
var n =20
function f() {
n++;
console.log(n)
}
return f
}
var x = fn()
x()
面试题:
var data = []
for(var i=0;i<3;i++){
data[i] = function () {
console.log(i);
};
}
data[0]();
data[1]();
data[2]()
问:如何定义输出的是0,1,2?
方法1:使用立即执行函数
for(var i=0;i<3;i++){
(function(){
setTimeout( data[j] = function () {
console.log(j);
,0)
})()
}
方法2:es6中块级作用域定义 let 声明变量
for(var i=0;i<3;i++){
data[i] = function () {
console.log(i);
};
}
13. 本地存储方式 cookie localStorage 以及sessionStorage?
cookie:
服务端生成,客户端维护和存储 每次请求都需要带上
使用场景:
记住密码,下次自动登录。
购物车功能。
记录用户浏览数据,进行商品(广告)推荐。
使用:
Cookies.set("name", "value", { expires: 7 });
Cookies.get("name");
Cookies.remove("name");
localStorage:
本地永久性存储 在客户端使用 (setItem 设置,getItem取数据)
存入数据使用setItem方法。它接受两个参数,第一个是键名,第二个是保存的数据。
使用:
localStorage.setItem("name","value");
var valueLocal = localStorage.getItem("name");
localStorage.removeItem("name");
localStorage.clear();
sessionStorage:
会话级别的存储方式,当会话结束,数据被清空,设置和取值同理
14. get、post的区别
1.传参不同:
get传参方式是通过地址栏URL传递,是可以直接看到get传递的参数,把请求的数据在URL后通过?连接,通过&进行参数分割
post传参方式参数URL不可见,psot将参数存放在HTTP的包体内
2. 长度限制
get传递数据是通过URL进行传递,对传递的数据长度是受到URL大小的限制,URL最大长度是2048个字符。
post没有长度限制
3. get后退不会有影响,post后退会重新进行提交
4. get请求可以被缓存,post不可以被缓存
5. get请求只URL编码,post支持多种编码方式
6. get请求的记录会留在历史记录中,post请求不会留在历史记录
7. get只支持ASCII字符,post没有字符类型限制
15 .什么 arguments?
arguments 是一个对应于传递给函数的参数的类数组对象
arguments 是一个对象,不是一个 Array 。它类似于Array
如何将类数组对象转换成数组:
var args = [].slice.call(arguments);
var args = Array.prototype.slice.call(arguments);
es6中的内容:
let args = Array.from(arguments)
let args = [...arguments];
16.数组的扁平化:
function flatter(arr) {
if (!arr.length) return;
while (arr.some((item) => Array.isArray(item))) {
arr = [].concat(...arr);
}
return arr;
}
17.null和undefined的区别?
18.JS的严格模式有哪些?
a:变量:
1.不允许意外创建全局变量,给一个没有声明的变量赋值,那代码在执行时就会抛出 ReferenceError
2.不能对变量调用 delete 操作符
3.严格模式下对变量名也有限制,不能使用 implements、interface、let、package、 private、protected、public、static 和 yield 标识符作为变量名,使用以上标识符作为变量名会导致语法错误。
b:对象:
1.为只读属性赋值会抛出 TypeError
2.对不可配置的(nonconfigurable)的属性使用 delete 操作符会抛出 TypeError
3.为不可扩展的(nonextensible)的对象添加属性会抛出 TypeError
4.使用对象字面量时,属性名必须唯一
19.何为类数组,类数组转换成真正的数组?
20.javascript事件循环 Event Loop 微任务与宏任务?
js是单线程,进而引入了同步任务和异步任务
理解几个概念:
1.同步任务:
1主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务,因而形成一个“执行栈”
2.异步任务:(才有宏任务和微任务,微任务先执行)
不进入主线程、而进入”任务队列”(task queue)的任务,只有”任务队列”通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行
一旦“执行栈”中的所有同步任务执行完毕,系统就会读取“任务队列”,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
3.Event Loop:
主线程从“任务队列”中读取事件,这个过程是循环不断的,所有整个运行机制成为事件循环
4.微任务:
process.nextTick、Promise、MutationObserver等
5.宏任务:
setTimeout、setInterval、 setImmediate、script(整体代码)、I/O 操作等
6.调用栈:
真正执行代码,执行任务的地方
Event Loop 过程:
1.初始状态下,调用栈空,微任务队列空,宏任务任务队列里有且只有一个script脚本(整体代码),此时首先执行并出队的就是整体代码
2.整体代码作为宏任务进入调用栈,进行同步任务和异步任务的区分
3.同步任务直接执行并且在执行完之后出栈,异步任务进行微任务与宏任务的划分,分别被推入进入微任务队列和宏任务队列
4.等同步任务执行完了(调用栈为空)以后,再处理微任务队列,将微任务队列压入调用栈
5.当调用栈中的微任务队列被处理完了(调用栈为空)之后,再将宏任务队列压入调用栈,直至调用栈再一次为空,一次轮回结束
如图:

ES6相关
1.var 和 let,const 区别
var:
声明是全局作用域,可以在变量声明之前使用,值为undefined
let:
声明的是块级作用域声明变量一定声明之后使用,否则报错
暂时性死区:
var tmp = 123
if(true){
tmp = 'abc'
let tmp
}
首先tmp是全局变量,但是块级作用域中let声明了一个局部变量tmp,
所以tmp 是收到了let影响,由全局变成了块级,并且在声明之前使用
因此tmp会报错 凡是在声明之前就使用这些变量,就会报错。
let 不允许在相同作用域内,重复声明同一个变量,因此,不能在函数内部重新声明参数。
比如:
function(){
let a = 10
var a = 1
}// 报错
functio;n(){
let a = 1
let a = 2
}// 报错
2.async await的理解,内部原理 ?
async 函数返回一个 Promise 对象,当函数执行的时候,
一旦遇到 await 就会先返回,等到触发的异步操作完成,
再接着执行函数体内后面的语句。
eg:
function getNum(num){
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(num+1)
}, 1000)
})
}
const func = async ()=>{
const f1 = await getNum(1)
const f2 = await getNum(f1)
console.log(f2)
}
func()
3.promise原理,回调地狱?
Promise 本质是一个构造函数,是异步编程的一种解决方式,可以理解为一个异步操作的容器
用来解决回调地狱所带来的问题的,可以用链式调用的方式,来解决层层嵌套所带来的问题
test1().then(res=>{
console.log(res)
return test2();
}).then(res=>{
console.log(res)
return test3();
}).then(res=>{
console.log(res)
})
实例创建就会立即执行
export const postData= (params) => {
return new Promise((resolve, reject) => {
axios.post('/xxxUrl', params).then(res=>{
resolve(res)})
.catch(error=>{reject(error)});
})
};
Promise三种状态:
1.pending:进行中,Promise 实例创建后的初始状态
2.fulfilled:已成功。成功回调resolve()
3.rejected:已失败。失败回调reject()
Promise.prototype 回调函数对应的链式方法:
1.Promise.prototype.then(resolve())==>成功的回调
2.Promise.prototype.catch(reject())==>失败的回调
3.Promise.prototype.finally()==>无论成功还是失败的回调
Promise实现的方法并使用场景:
1.Promise.all([test1(),test2(),test3()]) --> 所有状态都是成功的 将成功的返回值组成一个数组,传递给对应的回调函数(接力,必须全部成功)
2.Promise.race([test1(),test2(),test3()])--> 谁率先改变状态,并将返回值传递给对应的回调函数(赛跑取最快)
3.Promise.allSettled([test1(),test2(),test3()]) --> 无论是成功还是失败都都将返回结果组成一个数组,传递给对应的回调函数,没有.catch()方法,只有.then()
如返回结果如下:
[ { status: 'fulfilled', value: 42 }, { status: 'rejected', reason: -1 } ]
success = results.filter(p => p.status === 'fulfilled')
error = results.filter(p => p.status === 'rejected')
每个对象都有一个status属性,返回值是字符串‘fulfilled’或者是‘rejected’,表示成功回调和失败回调
成功回调对象有value属性,失败回调有reason属性
可以通过过滤器区分成功回调和失败的回调
4.Promise.any([test1(),test2(),test3()]) --->只要有一个是回调成功的,包装实例就会变成成功状态,除非都是失败回调,则状态为失败
4.class 类 构造模板
class Parents {
constructor(){
this.name='王健林'
this.age=48
}
say(){
console.log('person的say')
}
}
let p = new Person()
p.say()
继承的写法:
class son extends Parents {
<!--
复杂的写法
constructor(){
super()
this.sonName='王思聪'
this.sonAge=18
}
hello(){
console.log('son say hello')
}
-->
sonName = '王思聪'
hello(){
console.log('son say hello')
}
}
5. 模板字符串:
反引号``
`Hello ${name}, how are you ${time}`
用${}使用,不用做字符拼接
6. 对象的扩展
当key和值相同,可以省略值
1. Object.keys()方法,获取对象的所有属性名或方法名
var obj={name: "john", age: "21", getName: function () { alert(this.name)}};
console.log(Object.keys(obj)); // ["name", "age", "getName"]
console.log(Object.keys(obj).length); //3
console.log(Object.keys(["aa", "bb", "cc"])); //["0", "1", "2"]
console.log(Object.keys("abcdef")); //["0", "1", "2", "3", "4", "5"]
2. Object.assign (),assign方法将多个原对象的属性和方法都合并到了目标对象上面。 对象拼接
var target = {}; //目标对象
var source1 = {name : 'ming', age: '19'}; //源对象1
var source2 = {sex : '女'}; //源对象2
var source3 = {sex : '男'}; //源对象3,和source2中的对象有同名属性sex
Object.assign(target,source1,source2,source3);
console.log(target); //{name : 'ming', age: '19', sex: '男'}
7. 函数扩展:函数名=(形参)=>{……} 箭头函数
8. for...of 循环
9. import和export
import用于在一个模块中加载另一个含有export接口的模块。
export用于对外输出本模块(一个文件可以理解为一个模块)变量的接口。
import和export命令只能在模块的顶部,不能在代码块之中。
10. 解构赋值 (解构失败则undefined)
a.数组: (一一对应的关系)
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
let [x, , y] = [1, 2, 3];
x // 1
y // 3
let [head, ...tail] = [1, 2, 3, 4];
head // 1
tail // [2, 3, 4]
let [x, y, ...z] = ['a'];
x // "a"
y // undefined
z // []
b.对象:对象的属性没有次序,变量必须与属性同名,才能取到正确的值。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' };
对象的解构赋值的内部机制,是先找到同名属性,然后再赋给对应的变量。真正被赋值的是后者,而不是前者。
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
baz // "aaa"
foo // error: foo is not defined
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]
11.set数据结构(去重)
它类似于数组,但是成员的值都是唯一的,没有重复的值。 (可以去重,数字,字符串)
let arr = [1,2,3,2,1];
let setArr = [...new Set(arr)]
console.log(arr,setArr)
let [x, y, z] = new Set(['a', 'b', 'c']);
x
12.数组新增常用的四个方法
1.map --映射
let arr = [20,30,40,50,10,30,15]
let result = arr.map(item=>{
return item>25? '及格' : '不及格'
})
console.log(`map--result:${result}`)
b.reduce 汇总
let arr2 = [20,30,40,50,10,30,15]
let result2 = arr.reduce((temp,item,index)=>{
console.log(temp,item,index)
return temp+item
})
console.log(result2)
13.ES6数据结构之Map?
let let map = new Map()
map.set("name", "小红")
console.log(map)
1.添加 map.set('age','18')
2.长度 map.size
3.获取:map.get('name')
4.查询:map.has('age')
5.删除:map.delete('name')
6.清除:map.clear()
7.map使用循环
map.forEach((v, k, self) => {
console.log(value, key, self)
})
8.Map 快速转换成对象(Object.fromEntries(map))
let map = new Map([
["name", "小红"],
["age", 24],
["sex", "male"]
])
console.log(Object.fromEntries(map))
9.优化if else
let text = ""
if (status == 1) {
text = "启用"
} else if (status = 2) {
text = "停用"
}
let operation = new Map([
[1, "启用"],
[2, "停用"],
[3, "注销"]
])
text = operation.get(status)
14.对于axios拦截器的理解?
request 请求拦截器:在请求发送前统一执行某些操作,常用在请求头中处理token等
var axios = axios.create({
timeout: 60000,
withCredentials: true
})
axios.interceptors.request.use(function (config){
config.headers.token = 'token'
return config
},function (error){
return Promise.reject(error)
})
axios.interceptors.response.use(
response => {
if (response.status === 200 && response.data.request_id) {
if (response.data.code == 0) {
return response.data;
} else if (response.data.code == 1) {
window.location.href = LOGIN_URL
} else if (response.data.code == 2) {
router.push({ path: '/unauthorized' })
} else if (response.data.code == 4) {
router.push({ path: '/buy' })
return response.data;
} else {
let msg = response.data.msg
Message.error({
message: msg,
duration: 3000,
center: true,
offset: 50,
showClose: true
})
return Promise.reject(error)
}
}
return response
},
error => {
if (error.response.status === 500) {
Message.error({
message: '服务器内部错误',
duration: 3000,
center: true,
offset: 50,
showClose: true
})
router.push({ path: '/errorpage' })
return Promise.reject(error)
}
if (error.response.status === 404) {
router.push({ path: "/undefined" })
return Promise.reject(error)
}
if (error.response.status === 403) {
store.dispatch("app/setServerError", "403")
removeCookie("csrftoken")
removeCookie("sessionid")
router.push({ path: "/errorpage" })
return Promise.reject(error)
}
if (error.response.status === 422) {
let msg = window.rootVueInstance.$i18n.t('Error.' + error.response.data.msg)
Message.error({
message: msg,
duration: 3000,
center: true,
offset: 50,
showClose: true
})
return Promise.reject(error)
}
if (error.response.status === 409) {
let msg409 = '获取列表失败,请检查AK信息是否正确'
return Promise.reject(error)
}
return Promise.reject(error.response.status)
})
最后导出:export default axios
TS相关:
1.ts和js的关系?
VUE2+Vue3相关
1.v-if和v-show 区别,好处?
2.Vue.nextTick()使用原理?
3.vuex使用原理?
可以用来组件之间的传值:父组件给多个组件传值
当组件需要修改数据的时候,通过store.dispatch来调用Actions中的方法
actions中的方法被触发的时候通过commit的方法来触发Mutations里面的方法,
mutations里面的方法来修改数据,数据是响应式的,因此视图数据也会改变
包含内容:
state 存储数据
actions 处理异步请求,用来触发mutations
mutations改变state
getter获取数据
1. mapState将vuex数据进行映射到当前组件中的计算属性
import { mapState } from 'vuex'
computed: {
...mapState(['counter'])
}
2. mapMutations把vuex映射到methods中
import {mapState,mapMutations} from 'vuex'
methods:{
...mapMutations(['add']),
4. 增删state中的数据
Vue.set(state,"age",15)
Vue.delete(state,"age")
5.Getters 对state值加工计算传递给外界
getters:{
nameInfo(state){
return "姓名:"+state.name
},
fullInfo(state,getters){
return getters.nameInfo+'年龄:'+state.age
}
}
组件中调用:
this.$store.getters.fullInfo
6. Models
当状态比较多的时候,采用模块化,每个模块都有state,actions,Mutations,getter
models:{
a:{
state:{},
getters:{},
....
}
}
组件调用模块a的状态:
this.$store.state.a
在提交dispatch方法时,需要加type
this.$store.commit('editKey')
this.$store.dispatch('aEditKey')
7. 目录规范:
store:.
│ actions.js
│ getters.js
│ index.js
│ mutations.js
│ mutations_type.js ##该项为存放mutaions方法常量的文件,按需要可加入
│
└─modules
Astore.js
8. 作用和场景
作用:管理全局变量
场景:登录的token,很多页面都需要这个信息
4. 组件之间的传值:
1. 子组件向父组件传值,通过$emit发射事件 ,父组件通过事件名称接收
2. 父组件向子组件传值:通过属性的方式:name传递给子组件,子组件通过props接收name
3. 兄弟组件之间传值:通过bus总线传值
将bus挂载在vue实例上 var bus = new Vue();
组件A向组件B传值:bus.$emit("事件名称",参数)
B组件要在钩子函数mounted中监听到该事件:mounted(){bus.$on("事件名称", (传递过来的参数) => {this.two = 传递过来的参数 })}
5.vue中router使用原理?
6.双向数据绑定原理?
7. vue中的computed和watch的区别:
计算属性computed:
支持缓存,数据改变才会重新计算,
不支持异步,是无法监听数据变化
如果computed属性值是函数,函数返回的值就是属性的属性值
在computed中属性都有一个Get,和一个set方法,当数据变化的时候才会调用set方法
watch:
不支持缓存,数据变,就会触发操作,支持异步
监听的函数接收2个参数,第一个参数是最新的值,第二个参数是输入之前的值
总结:当需要在数据变化时执行异步或开销较大的操作时,用watch
8.什么是单页面应用
指一个系统指加载一次资源,之后的操作交互,数据交互都是通过路由,ajax来进行的,页面并没有刷新
优点:
前后端分离
良好的交互体验
减轻服务器压力
共用一套后端代码
9.vue 和jQuery区别:
jq是使用选择器($)选取DOM对象,对其赋值,取值,事件绑定,与原生对比更方便选取和操作dom对象
数据和界面是在一起的
vue是通过Vue对象将数据和view完全分离开来,对数据的操作不在引用dom对象,数据的相互绑定,数据改变,视图也会跟着变化
比如:
在显示和隐藏操作,vue只需要控制isShow的值为true或者false,而jq还要操作dom元素控制按钮的显示和隐藏
10. keep-alive:
存在一个缓存机制,用来缓存组件,避免多次加载相应的组件,减少性能的损耗
使用:
<keep-alive>
<router-view> </router-view>
</keep-alive>
需要缓存部分页面或者组件
v-if = "$route.meta.keepAlive" 设置在router-view标签中
在router配置中:
routes:[
{path:"/test1",component:test1,meta:{keepAlive:true}}
{path:"/test2",component:test2,meta:{keepAlive:false}}
]
11. 路由传参
1. 定义路由:通过冒号传参
{
path:'/one/log/:num',
component:Log,
name:Log
},
2. 在父路由组件上使用router-link进行路由导航 通过to跳转路由并传参
<router-link to="/one/log/123">显示登录页面</router-link>
3. 子路由获取父路由传递过来的参数:
this.$route.params.num
4. 为了避免风险:
<router-link :to="{name:'Log',params:{num:666}}">显示登录页面</router-link>
上述这种利用params不显示url传参的方式会导致在刷新页面的时候,传递的值会丢失;
5. 携带参数的跳转:
this.$router.push({path:`/child/${id}`})
this.$router.push({name:"childView",params:{id:1}}) 注意该name是路由配置时候指定的name
6. 使用query来传递参数:那么query传递的参数会显示在url后面?id=?
query.id
得到的参数是:localhost:8080/
综上所述:
this.$router.push进行编程式路由跳转
router-link 进行页面按钮式路由跳转 通过to跳转
this.$route.params获取路由传递参数 localhost:8080/
this.$route.query获取路由传递参数 localhost:8080/
12. 路由的懒加载(按需加载)
三种方法:vue 异步组件加载,import路由懒加载,webpack提供的require.ensure()
路由的基本配置
const router = new VueRouter({
routes: [
{ path: '/list', component: List }
]
})
非懒加载:
import List from '@/components/list.vue'
懒加载:
第一种: const List = () => import('@/components/list.vue')
第二种:(resolve) => {
require(['@/components/list'], resolve)
第三种:使用webpack的require.ensure技术,也可以实现按需加载。 这种情况下,多个路由指定相同的chunkName,会合并打包成一个js文件。
const List = r => require.ensure([], () => r(require('@/components/list')), 'list');
const router = new Router({
routes: [
{
path: '/list',
component: List,
name: 'list'
}
]
}))
1、vue异步组件实现路由懒加载
component:resolve=>(['需要加载的路由的地址',resolve])
2、es提出的import(推荐使用这种方式)
const HelloWorld = ()=>import('需要加载的模块地址')
13. vue的生命周期过程
开始创建
created Mounted updated Destoryed
第一步进行创建,进而实现挂载渲染完成,其次数据更新渲染,组件销毁
14. v-for中key值的作用
为了高效的更新虚拟DOM,使用key值给每一个节点做一个唯一标识,避免渲染出现混乱
15.V-model语法糖?
接受一个 value 属性
在有新的value时触发input事件
<input v-bind:value="something" v-on:input="something=$event.target.value">
16.vue自定义指令?
Vue.directive 都是分为全局注册和局部注册定义自定义指令(全局定义)
vue响应式原理?
15.vue3 新增特性
a:在Vue3.x中支持在单个组件上可以创建多个v-model绑定。
b:提供一个新的组件,setup() 是组件comcomposition API的入口点
c:setup 函数无法是有this 函数,接收2个参数,props,context
接收组件的参数,通过props.title 且不可以使用解构方式{title}
context 上下文对象:暴露一些属性,如果emit,slots,attrs
并且需要用return将数据返回
d:reactive 创建一个响应式对象 let name = reactive({value: "蛙人"})
e:Ref:接收一个参数,可以是单值也可以是对象,并且都是响应数据 let name = ref("蛙人") 取值name.value 渲染模板可以省略
f:Computed默认该函数就是getter 数据是只读
let name = ref("蛙人")
let test = computed(() => name.value);
test.value = "123"
传入一个对象set和get函数方法,这样就可以修改啦
let test = computed({
get() {
return name.value;
},
set(val) {
return name.value = val;
}
});
test.value = "123"
g:Readonly (禁止修改)该方法接收传入一个对象,默认是只读功能,是深层对象只读,不管嵌套多少层的属性都是只读状态。
h:WatchEffect:该方法接收一个函数并且立即执行,并当该函数里的变量变更时,重新执行该函数。该方法无法获取到原值,只能是改变之后的值。
import { ref, watchEffect } from "vue"
export default {
name: 'test',
setup() {
let name = ref("蛙人");
let age = ref(23);
watchEffect(() => {
name.value;
age.value;
console.log(name.value)
console.log(age.value)
})
setTimeout(() => {
name.value = "前端娱乐圈"
}, 5000)
setTimeout(() => {
age.value = 18
}, 1000)
}
}
i:Watch 监听单个值或者多个值
setup() {
let name = ref("蛙人");
watch(name, (newVal, oldVal) => {
console.log(newVal, oldVal)
})
setTimeout(() => {
name.value = "前端娱乐圈"
}, 1000)
}
<!-- 多值 -->
setup() {
let name = ref("蛙人");
let age = ref(23);
watch([name, age], (newVal, oldVal) => {
console.log(newVal, oldVal)
})
setTimeout(() => {
name.value = "前端娱乐圈"
age.value = 18
}, 1000)
}
j: 生命周期
beforeCreate --> setup
created --> setup
beforeMount --> onBeforeMount
mounted --> onMounted
beforeUpdate --> onBeforeUpdate
updated --> onUpdated
beforeDestroy --> onBeforeUnmount
destroyed --> onUnmount
k:Provide && Inject
Provide:接收2个参数,第一个key值,第二个value值,进行传递
Inject:接收2个参数,第一个是provide的key值,默认第二个参数可选,可以设置默认值(当找不到key值,设置一个默认值)
L:Refs 获取dom元素,配合ref使用let el = ref(null)
M:isReadonly:用于检测该数据是不是可读数据。返回一个Boolean类型
let test = readonly({name: "蛙人"})
console.log(isReadonly(test))
N:isRef用于检测该数据是不是ref响应式数据。返回一个Boolean类型。
let test = ref("公众号:前端娱乐圈")
console.log(isRef(test))
O:isReactive用于检测该数据是不是reacttive响应式数据。返回一个Boolean类型
let test = reactive({name: "蛙人"})
console.log(isReactive(test))
p:移除过滤器filters
Q:不再限制Template一个根节点
工程化性能相关
1.前端从哪些方面进行性能优化?(加载方面)
a:减少Http请求(雪碧图,css,js文件合并,优先考虑css代替图片)
b:缩减文件大小(资源压缩,webpack打包,Gzip 压缩,图片压缩)
c:CDN(大图加载,大文件,类库)
d:http
e:SSR服务端渲染,预渲染
f:懒加载,减少首屏加载量
g:减少回流,使用定位,对于操作量比较大的DOM,用文档碎片(虚拟dom)
h:使用缓存(cache)
一、页面级优化:
1. JavaScript 压缩和模块打包
2. 按需加载资源
3. 在使用 DOM 操作库时用上 array-ids
4. 缓存
5. 启用 HTTP/2
6. 应用性能分析
7. 使用负载均衡方案
8. 为了更快的启动时间考虑一下同构
9. 使用索引加速数据库查询
10. 使用更快的转译方案
11. 避免或最小化 JavaScript 和 CSS 的使用而阻塞渲染
12. 用于未来的一个建议:使用 service workers + 流
13. 图片编码优化
2.HTTP状态码:
1xx(临时响应)
100: 请求者应当继续提出请求
101(切换协议) 请求者已要求服务器切换协议,服务器已确认并准备进行切换。
2xx(成功)
200:正确的请求返回正确的结果
201:表示资源被正确的创建。比如说,我们 POST 用户名、密码正确创建了一个用户就可以返回 201。
202:请求是正确的,但是结果正在处理中,这时候客户端可以通过轮询等机制继续请求。
3xx(已重定向)
300:请求成功,但结果有多种选择。
301:请求成功,但是资源被永久转移。
303:使用 GET 来访问新的地址来获取资源。
304:请求的资源并没有被修改过
4xx(请求错误)
400:请求出现错误,比如请求头不对等。
401:没有提供认证信息。请求的时候没有带上 Token 等。
402:为以后需要所保留的状态码。
403:请求的资源不允许访问。就是说没有权限。
404:请求的内容不存在。
5xx(服务器错误)
500:服务器错误。
501:请求还没有被实现。
3.在浏览器中输入URL并回车都发生了什么?
eg:https://www.baidu.com
www:服务器
https:传输协议(http,tsp协议)TSL,SSL 安全层
baidu.com:域名,每个域名对应一个ip 地址
a:解析url ,去域名系统匹配对应的ip
b:浏览器与网站的链接 (TCP 3次握手) 不会携带任何参数
c:请求数据
d:渲染页面(过程)
e:TCP 断开链接(4次挥手)
4.css 加载会造成阻塞吗?
a:css加载不会阻塞DOM解析
b:css加载会阻塞DOM渲染
c:css加载会阻塞JS执行
5.浏览器运行机制
构建DOM树,生成节点 -----> 构建渲染树(解析css文件)---->
布局渲染树(从根节点递归,计算节点位置) ----> 绘制渲染树 (展示页面)
6.重绘和回流/重排
重绘:元素大小,颜色等,按自有的特性重新绘制(外观)
回流:根据元素的尺寸,布局,隐藏等改变需要重新构建(内在)
注:重排之后必定重绘 重绘不一定导致重排 缺点:导致卡慢 ,减少操作dom 元素
7.前端SEO优化是什么
SEO:前端搜索引擎优化,是为网页带来高质量流量的做法
如何优化:
关键字密度
内部链接策略
HTML标签
锚文本
网址结构
内容
控制首页链接的数量
扁平化目录
导航优化
网站的结构布局
控制页面大小,减少http请求,提高网站的加载速度
8.http和https区别?
9.3次握手,4次挥手?
10.同步和异步?
11.同源策略?
12.生产如何解决同源策略的?
webpack相关
1.webpack中有哪些loader
2.webpack打包过程?
3.webpack打包优化?
4.webpack中的npm run dev 和npm run build 是什么区别?
5.
nodejs 相关
其他:
1.职业规划?
2.项目中的难点,亮点,解决方案?
3.项目中的登录注册验证如何做到加密?加密方式如何?
4.对称加密和非对称加密?
5.CDN