一、JS设计模式
单例模式:一个构造函数一生只能new一个对象(应用场景:alert弹出框)
function Person(){
this.name='rose'
}
var instance=null
function single(){
if(instance===null){
instance==new Person()
}
return instance
}
var p1=new single()
var p2=new single() //p1==p2
组合模式:把若干启动方式一样的构造函数放在一起,准备一个总开关,总开关启动,那些构造函数就都启动了(应用场景:轮播图)
- 实现:需要一个承载所有构造函数的实例数组-;需要一个方法向数组里面添加内容;需要一个方法将数组里面的内容都启动
- 观察者模式(又称:发布/订阅模式):当一个对象的状态发生改变时,所有依赖它的对象都得到通知并自动更新;解决了主体对象与观察者之间功能的耦合,即一个对象状态改变给其他对象通知的问题;
递归
- 即自己调用自己;递归函数:一个函数内部自己调用自己,循环往复
- 需要有初始化,自增,执行代码,条件判断,不然就是一个没有尽头的递归函数,我们叫做死递归
function fn(){
fn()
};
fn();
- 斐波那契数列(兔子数列)的第n项,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34
function Fibonacci(n){ if(n==1){ return 0; } if(n==2){ return 1; } return Fibonacci(n-1)+Fibonacci(n-2) }
闭包
1.闭包是可以访问函数内部私有变量的函数。可以简单理解为在函数A内部直接或间接返回一个函数B,函数B内部使用函数A的私有变量,函数A外部有一个变量接收函数B。形成了一个不会销毁的空间
function a(){ var n=100; return function b(){ console.log(n) } } var res=a() res()
2.特点:延长了变量的生命周期,可以访问函数内部私有变量,保护私有变量。
- 3.致命的缺点:当前内存空间中有一个不会被销毁的空间,导致内存被占用,如果过多会导致内存溢出
ES6新增语法
- 1.let和const用于声明变量。与var的区别:不允许重复声明,不会在预解析时解析,会被代码块限制作用域。let声明变量的值可以被改变,const声明变量的值不能被改变。let声明时可以不赋值,const声明时必须赋值。
- 2.箭头函数:函数可以简写成箭头函数。箭头函数内部没有this、this指向上下文;内部没有arguments;函数参数只有一个时,括号可以不写;函数只有一行代码时可以不写{}并且会自动return
- 3.解构对象指快速从对象或数组中取出一个成员的方式。[]专门用于解构数组使用,{}专门用于解构对象使用。
- 4.模板字符串:es6中可以使用返单引号``表示字符串。它的特点是可以换行书写,可以在字符串中直接拼接变量,用${}来书写变量的位置。
- 5.展开运算符:es6中添加了一个…运算符,叫做展开运算符。它的作用是把数组或对象展开。合并数组,对象时可用。
- 6.Arry.from:将类似数组转换成真正的数组。
- 7.set:使用构造函数定义一个set类型,构造函数是一个数组。set类型里面的元素不允许重复。可以用于数组去重
- 8.Map类型是一个数据集合,是一个类似于对象的集合。和new连用。它的特点是在Map中,key可以为任意数据类型。
- 9.import/export语法:用于引入文件。
cookie/localstorage/sessionstorage
- cookie:存储在客户端的存储空间,以字符串的形式存储一些数据。它的特点是按照域名存储,存储大小限制在4KB或50条左右,具有时效性 默认是会话级别的实效,请求自动携带,前后端都能操作cookie;
- webStorage分为localstorage和seesionstorage
- localstorage和seesionstorage都是存储在浏览器的存储空间,以key和value的形式存储数据。key和value必须是字符串。大小限制在5MB左右。只有前端可以操作。请求中不会携带。
- localstorage用于长久存储整个网站的数据。保存的数据没有过期时间,直到手动删除
- seesionstorage用于会话临时存储,只有会话时才存在,当我们关闭浏览器,再打开它,连接服务器时,服务器端会分配一个新的session,也就是说会启动一个新的会话。很多人会觉得浏览器关闭就消失,但不是的。关闭浏览器只是在客户端的内存中清除了与原会话相关的cookie,再次打开浏览器进行连接时,浏览器无法发送cookie信息,所以服务器会认为是一个新的会话。它的销毁应该是过期时间到了才进行销毁
传输协议
- http:超文本传输协议,信息是明文传输。用于前后端数据的沟通。默认使用80端口。
- https:是具有安全性的SSL加密传输协议,简单来讲就是http的安全版。为浏览器和服务器之间的通信加密,确保数据传输安全。默认使用443端口。
- 怎样配置一个网站,让它是https协议:1.购买、下载SSL证书 2.升级前做好网站备份 3.安装证书
- http的缓存机制?有两个缓存机制:
- 强制缓存机制:简单理解为设置一个时间,浏览器在这个时间内都不会向服务器发送请求,而是使用缓存中的资源文件。当浏览器请求资源的时候会查看缓存中的资源是否存在并且确定该缓存的资源是否过了“保质期”,若没有超过保质期则将取得缓存中的资源进行下一步处理。
- 协商缓存(对比缓存):浏览器第一次请求数据时,服务器会将缓存标识与数据一起返回给客户端,客户端将二者备份至缓存数据库中。再次请求数据时,客户端将备份的缓存标识发送给服务器,服务器根据缓存标识进行判断,判断成功后,返回304状态码,通知客户端比较成功,可以使用缓存数据
- 请求步骤:建立连接,前端发送请求,后端返回响应,断开连接。
- 建立连接是基于TCP/IP的三次挥手。目的是确保前后端可以正常通信
- 前端发送请求是以请求报文的形式发送。请求报文中主要包含请求行、请求头、请求体。请求行是指请求方式。常见的请求方式有八种。其中GET和post是http请求中常用的两种方式。
- 后端响应:每一个响应都是以响应报文的形式返回
- 断开连接是基于TCP/IP协议四次挥手。目的是保证互相不进行通信
- GET:倾向于向服务器获取数据,大小限制在2KB左右,可以直接在浏览器后面拼接,采用明文发送不是很安全,数据格式必须是URL编码格式,会被浏览器主动缓存
- POST:倾向于向服务器传递数据,大小理论上没有限制,需要在请求体中发送,采用暗文发送相比起GET比较安全,数据格式理论上没有要求但要与请求头一致,不会别浏览器主动缓存,需要手动设置。
- 响应状态码:响应报文中的一个信息,表示本次请求的状态。分为5类
- 100-199:连接继续
- 200-299:200标准成功:202服务器已接受请求但未处理,204服务器处理完成但没有返回实际内容
- 300-399:重定向;301永久定向,302临时重定向,304缓存
- 400-499:客户端错误;404请求地址有误,403权限不够查看、413传输数据量太大、405请求方法不支持
- 500-599:服务端错误;502服务器过载、504防火墙超时
节流和防抖
- 防抖是指事件触发后在规定时间内回调函数只执行一次,如果规定时间内又触发了该事件,则会重新开始计算时间。可以总结为延迟执行。原理是:通过定时器将回调函数进行延迟,如果在规定时间内继续回调,发现存在之前的定时器,则将该定时器清除,并重新设置定时器。应用场景:搜索框,用户在不断输入值时,用防抖来节约请求资源。
- 节流是当持续触发事件时,在规定时间内只能调用一次回调函数。如果规定时间内再次触发了该事件,则什么也不做,也不会重置定时器。应用场景:监听滚动事件,比如下滑页面出现回到顶部按钮;鼠标不停点击触发时;
- 节流与防抖相比,防抖是将多次执行变成最后一次执行,节流是将多次执行变为规定时间内只执行一次,不会重置定时器。
网络攻击
- XSS攻击:跨站脚本攻击,web中主流的攻击方式,利用web漏洞,恶意程序为javascript。这类漏洞能使得攻击者嵌入恶意脚本代码到正常用户会访问到的界面中,当正常用户访问到该页面时,则会导致该恶意脚本的执行。
- 解决方案:过滤和转义。将特殊的符号转义、替换。不然innerHTML—>innerText
- CSRF攻击:跨站请求伪造.利用了web中用户身份验证的一个漏洞.解决:加token
跨域
- 同源策略:浏览器的安全策略、是为了保护本地数据不被JavaScript代码获取回来的数据污染
- 浏览器具有同源策略,当请求的传输协议、域名、端口号有任意一个不同时,浏览器会认为你在请求别人的服务器,它会阻止,显示触发’同源策略’;同源策略也叫跨域请求;
- 跨域问题的解决方案有:JSONP、CORS跨域、代理;
- JSONP是利用script不受同源策略的影响来请求数据
- CORS是让后端开启跨域资源共享来请求数据
- 代理是我常用的一种解决跨域的方式;在浏览器同源设置一个代理服务器,把本该发送给目标服务器的请求发送给代理服务器,由代理服务器发送给目标服务器,目标服务器把响应返回给代理服务器,代理服务器把响应返回给浏览器
promise
- 回调地狱是:把函数A当做参数传递到函数B中,在函数B中以形参的方式进行调用;当回调函数嵌套过多时会出现回调地狱,即没有可维护性和可读性代码;
- promise:ES6中有个内置构造函数叫promise,主要用于异步计算,每个异步事件在执行时都有三个状态:执行中(pending)、成功(resolve)、失败(rejected);是解决回调地狱的方案之一,把回调地狱写的优雅的方案之一;
async和await
- async和await是Generator函数的语法糖
- async为异步的,await为等待
- async是声明某个函数式异步的,await是等待某个操作的完成
- 语法上强制规定await只能出现在async函数中
原型和原型链
- 原型对象Prototype:每个构造函数天生自带一个成员叫做prototype;构造函数中、公共的方法存放在原型对象上;它的作用是共享方法;
- 对象原型proto:每个对象天生自带一个成员叫proto;它指向构造函数的prototype原型对象;之所以实例对象可以使用构造函数prototype原型对象的属性和方法,就是因为有proto原型的存在;
- 实例对象的proto和构造函数的prototype指向的是同一个对象空间,是等价的;
- 原型链:访问一个对象成员时,如果自己身上没有就会去proto中找,如果没有就再去构造函数的prototype的proto里找,直到找到object、prototype里没有,返回undefine;这样一层层的往上找会形成一个链式结构、称为原型链
MVP、 MVC、MVVM
- mvc:由model模型、view视图、controller控制器组成。是软件架构中最常见的一种框架。它的工作原理是当用户触发事件时,view层会发送指令到controller层,controller层去通知model更新数据,model更新完数据后直接显示在view上。缺点:耦合度太高
- mvp:作为mvc的演化,解决了不少mvc的缺点。mvp模式将cotroller改成了presenter,同时改变通信的方向。view跟model不再发生关系,取而代之的是presenter充当了桥梁的作用。用户触发事件,view发送指令到presenter,presenter通知model更新数据,model更新完数据发送给persenter,presenter再将数据显示在view上。
- mvvm:将presenter换成了viewmodel层。viewmdel和view是数据双向绑定的关系。view变动,viewmodel也会跟着变化.更新viewmodel层数据时,view也会相应变化。
BSR、SSR
- BSR客户端端渲染(前后端分离):视图和数据的组装是在客户端完成的
- SSR 服务器渲染(前后端不分离):视图和数据的组装是在服务器端完成
- BSR的优缺点:前后端分离,代码更容易维护;数据化应用,交互更加丰富;对于前端工程师而言价值更高;但是它的SEO有严重的劣势;在TOB的产品上应用更加广泛
- SSR的优缺点:前后端不分离,对后端要求更高;有利于SEO优化;对客户端压力比较小,服务器压力大;在TOC产品上应用比较广泛。
- 原理:在node环境下运行的,用的是第三方的库,把动态组件转化为HTML
SEO优化
- 搜索引擎优化,让更多用户找到你
- 优化的原则是:尽量减少js、css功能,尽肯能多地使用静态html。
- 使用h1-h6标签,尽量减少使用div,使用htm5语义化标签,加上title属性,给图片加上alt属性
- 脚手架环境中:能尽量写死的就尽量写死,meta标签中添加title属性,给图片加alt属性,减少使用div
深浅拷贝
- 浅复制:浅复制一般用于基本数据类型。基本数据类型存在栈中,直接复制即可。
- 深复制:对象层级过深时,无法自动更新,需要用到深复制。就是把数据粉碎再组装。原理:对象的地址在栈里面,内容在堆里面。直接复制时只是复制它的地址,但指向的是同一个堆。深复制不仅能复制地址还能复制堆。JSON.parse(JSON.stringify(state.goodObj))
ajax
- AJAX是异步的javascript和XML。是一种用于创建快速动态网页的技术。通过在后台与服务器进行少量的数据交换,AJAX可以使网页实现异步更新。
- 优点:异步模式、提升了用户体验;优化了浏览器和服务器之间的数据传输、减少不必要的数据往返;在客户端运行、减少了服务器的负载;
- 特点:动态不刷新(局部更新)
- 原生js,ajax请求步骤:
- 1.创建ajax对象:new XMLHttpRequest()
- 2.配置本次请求信息:ajax对象.open(请求方式,请求地址,是否异步)
- 3.发送请求: ajax对象.send()
- 4.接收后端响应: ajax对象.onload=function(){}
- ajax状态码:ajax对象.readystate
- 0:表示创建一个ajax对象成功
- 1:表示配置信息成功
- 2:响应体已经回到浏览器,但不能是使用
- 3:浏览器正在解析响应报文
- 4:浏览器把响应体分离成功,可以正常使用
axios
- axios是用于发送和接收请求。一般我工作中会对axios进行二次封装;封装出一个api.js文件,这个文件里可以放不同请求,专门用于调接口;再通过axios去处理发送接收请求等。受;的影响,需要通过vue.config.js进行代理。
es5的严格模式
- 对开发时的一些内容做了修改
- 严格模式的开启:’use strict’
- 规则:声明变量前必须有var关键字,函数的形参不可以重复,声明式函数调用时函数内部没有this,全局声明式函数调用时,函数内部的this指的是window,事件函数里面的this指向事件源。
this指向
- 每个函数的内部都有一个this关键字,this只与函数的调用方式有关。
- 全局定义函数this指向window
- 对象内部this指向调用者
- 定时器this指向window
- 事件处理函数this指向事件源
- 自调用函数this指向window
数组常用的方法:
- 1、push:在数组末尾添加一个元素;返回值是数组长度
- 2、pop:删除数组末尾的一个元素;返回值是被删除的那个元素
- 3、unshift:在数组前面添加一个元素;返回值是数组的长度
- 4、shift:删除数组前面一个元素;返回值是被删除的那个元素
- 5、splice:按照索引截取数组中的某些内容;返回值是被删除的元素集合
- 6、reverse:用来翻转数组;返回值是 原 数组
- 7、sort:排序;按照字符编码排序
- 8、concat:拼接数组;不改变原数组、返回 新 数组
- 9、join:把数组里面的每一个数据拼接起来变成字符串;返回 新 数组
- 10、index of:用来找到数组中某一项的索引;返回值:索引、找不到返回-1
- 11、lastIndex of:用来找到数组中某一项的索引、从后面开始找;返回值:索引、找不到返回-1
- 12、forEach:遍历数组;语法:数组.forEach(function(item、index){})
- 13、map:遍历数组、可以对数组中某一项进行操作,返回新数组;
- 14、filter:遍历、筛选数组;把原始数组中满足条件的筛选出来,返回一个新数组;
- 15、Sort:数组排序;升序:return a-b、降序:return b-a;返回值是排序好的数组
- 16、Array from:将类数组转成真正的数组
冒泡排序:先遍历数组、两两进行比较、若前一个比有一个大、那就把两个数据换个位置、遍历完成一遍后、最后一个数字就是最大那个;然后进行第二遍遍历、按之前规则,第二大数字就会跑到倒数第二个位置,以此类推,最后按从小到大排序
for(var j=0;j<arr.length;j++){ for(var i=0;i<arr.length-1-j;i++){ if(arr[i]>arr[i+1]){ var temp=arr[i] arr[i]=arr[i+1] arr[i+1]=temp } } }
选择排序:先假定数组中第0个就是最小数字索引,遍历数组、只要有一个数字比我小、就替换之前记录的索引、直到数组遍历结束后、找到最小的那个索引位置换到第0个位置;再来第二遍,假设第一个是最小数字的索引、再遍历一遍数组、找到那个比我小的索引、以此类推把数组排序好;
for(var j=0;j<arr.length-1;j++){ var minIndex=j for(var i=j+1;i<arr.length;i++){ if(arr[i]<arr[minIndex]){ minIndex=i } } if(minIndex!=j){ var temp=arr[minIndex]; arr[minIndex]=arr[i]; arr[j]=temp; } }
数组去重
- 1.ES6中set方法去重;set里面的元素不允许重复;var arr=[1,2,3] var s=new set(arr) arr=[…s]
2.for循环嵌套for循环,通过splice去重
var arr=[1,2,4,3,3] for(var i=0;i<arr.length;i++){ for(var j=i+1;i<arr.length;j--){ if(arr[i]==arr[j]){ arr.splice(j,1) j-- } } }
- indexof去重
var arr=[1,2,4,3,3] var arrsy=[] for(var i=0;i<arr.length;i++){ if(arrsy.indexof(arr[i])===-1){ arrsy.push(arr[i]) } }
- indexof去重
字符串常用的方法
- charAt(索引):找到字符串中指定索引位置并返回
- charCodeAt(索引):返回对应的索引unicode编码
- indexOf(字符):按照字符找到对应的索引
- lastindexOf(字符):从后面开始找
- subString(起索引,终索引):截取字符串;包前不包后;第二个参数没有表示截取到末尾
- subStr(从哪个索引开始,截取几个)
- slice:与subString类似
- repeat:重复字符串,返回新的字符串
- fromcharcode():根据传入的编码,变成编码对应的字符
- toLowerCase、toUpperCase:变大小写
- split:字符串转数组
- trim:去除首尾空格
undefine和null区别
- 类型不一样:undefined是undefined 、null是object
- 转化为值时不一样:undefined为NaN ,null为0
- console.log(nullundefined)//true
console.log(null=undefined)//false
阻塞和非阻塞
- 阻塞:阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务。函数只有在得到结果之后才会返回
- 非阻塞:非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
window和document
- window:是浏览器内置对象,包含操作浏览器的方法;可以获取浏览器的相关信息如:窗口位置、确定窗口大小、弹出对话框等等
- document对象:是浏览器内置对象,存储着用来操作元素的方法。
JS哪些操作会造成内存泄露
- 意外的全局变量引起的内存泄露
- 闭包引起的内存泄露
- 没有清理的DOM元素引用
- 被遗忘的定时器或者回调
- 子元素存在引起的内存泄露
从输入url到页面加载完成发生了什么?
- 1.浏览器的地址栏输入URL并按下回车
- 2.浏览器查找当前URL的DNS缓存记录
- 3.DNS解析URL对应的IP
- 4.根据IP建立TCP连接
- 5.HTTP发起请求
- 6.服务器处理请求,浏览器接收HTTP响应
- 7.渲染页面,构建DOM树
- 8.关闭TCP连接
模块化:
- ES6模块化:引入的外链式里使用了大量全局变量,可能会与自己写的变量冲突;希望可以引入,运行完了不要污染我的全局环境;import/export语法
- CommenJs:node应用由模块组成,采用CommenJs模块规范;每个文件就是一个模块,拥有自己独立的作用域、变量、以及方法等,对其他的模块不可见。CommonJS规范规定,每个模块内部,module变量代表当前模块。这个变量是一个对象,它的exports属性(module.exports)是对外的接口。加载某个模块其实是加载module.exports属性。require方法用于加载模块。
- CommonJs与ES6区别:前者支持动态导入、后者不支持;前者是同步导入、后者是异步导入;前者在导出时都是值拷贝,就算导出的值变了,导入的值也不会改变,所以如果想更新值,必须重新导入一次。但是后者采用实时绑定的方式,导入导出的值都指向同一个内存地址,所以导入值会跟随导出值变化
call, apply, bind:
- 共同点:都可以改变this指向
- 区别:传参方式不同;除第一个参数以外(要改变的this指向),call可以接收一个参数列表、apply只能接收一个数组;bind其他两个方法作用也是一致的,只是该方法会返回一个函数
为什么 0.1 + 0.2 != 0.3
- 因为 JS 采用 IEEE 754 双精度版本(64位),并且只要采用 IEEE 754 的语言都有该问题。
- 原生解决办法:parseFloat((0.1 + 0.2).toFixed(10))
webpack
作用:
- 是当下前端工程化环境中使用最为广泛的构建工具.它的作用是把比较新的前端技术和文件模块编译成浏览器能够识别并尽可能兼容主流浏览器的代码,它就是一个打包器;
配置文件:(webpack.config.js/react.config.js/vue.config.js)
- 项目的入口和出口都在这里运行;前端项目都运行在node.js环境中,这个配置文件是项目运行或打包时执行的;
- 使用CommonJS模块化语法
webpack-dev-serve:
- 它是使用express编写的用于创建本地node服务的第三方包。一个小型的node.js Express服务器。简单来说就是一个小型的静态文件服务器
- 它可以在pakege.json中更改命令行开启;
- 它可以在react.config.js中添加devServer对象进行配置:端口号、指定本地服务的静态资源目录、自动打开浏览器、热更新等
plugins
- 用于把打包后的js/css等资源,自动插入到public/index.html中。
clean-webpack-plugin
- 在每次执行npm run build时,自动帮我们清理dist
loaders:
- webpack 可以使用 loader 来预处理文件。这允许你打包除 JavaScript 之外的任何静态资源。指在main.js中可以引入其他文件。比如aseet/css/common.css通过loader与public/index.html关联。
HMR(Hot Module Replacement):模块热替换(热更新)
babel.js
- 把ES6语法转化成主流浏览器兼容的代码
ESlint:检测JS语法规范
区分开发环境和生产环境
- cross-env:在node.js环境进程中添加环境变量
- package.json中配置
- react.config.json中:判断进程的环境是生产环境还是开发环境,生产环境和开发环境执行的代码不同
resolve:
- 1.定义绝对路径@:通过alias; 2.定义文件后缀名省略:extensions
二、HTML、css
BFC
- 块级格式化上下文
- BFC是一块独立的布局环境,保护其中内部元素不受外部影响,也不影响外部。
- BFC的应用:自适应两栏布局、清除内部浮动、防止margin上下重叠
- 触发BFC的元素或属性:float属性不为none;position为absolute或fixed;display为inline-block;overflow不为visible
浏览器渲染页面的过程
- 1.处理HTML并构建DOM树
- 2.处理css构建cssOM树
- 3.将DOM与CSSOM合并成一个渲染树
- 4.根据渲染树来布局,计算每个节点的位置
- 5.调用 GPU 绘制,合成图层,显示在屏幕上
回流、重绘
- 回流: 根据渲染树来布局,计算每个节点的位置,进行回流
- 重绘: 根据渲染树以及回流得到的几何信息,得到节点的几何像素
- 回流一定会触发重绘、但重绘不一定会回流
伪类的用法::before ::after
- 之所以被称为伪元素,是因为他们不是真正的页面元素,html没有对应的元素,但是其所有用法和表现行为与真正的页面元素一样,可以对其使用诸如页面元素一样的css样式,表面上看上去貌似是页面的某些元素来展现,实际上是css样式展现的行为,因此被称为伪元素
- 伪元素:before和:after添加的内容默认是inline元素;这两个伪元素的content属性表示伪元素的内容,设置:before和:after时必须设置其content属性,否则伪元素就不起作用。
css有哪些选择器
- css3新增的选择器:
- 1.属性选择器->E[attr]
- 2.伪类选择器->X:first-child、X:last-child、X:nth-child(n)
- 3.目标伪类选择器->E:target
- 4.层级选择器->E>F、E+F、E~F
- 小结:常用的选择器有标签选择器、id选择器、类别选择器等;css3新增的选择器有属性选择器、伪类选择器、目标伪类选择器、层级选择器等
垂直居中的方法
- margin:0 auto;
- position:fixed;left:50%;top:50%;margin-top:-高的一半;margin-left:-宽的一半
px、em、rem
- px: PC端的尺寸单位;像素、绝对单位
- em: 相对于最近父元素的倍数
- rem:移动端尺寸单位;根元素倍数;相对于根元素html的font-size计算值的大小。简单理解为屏幕宽度百分比
xhtml和html区别
- html(超文本标记语言):以一种语法较为松散、不严格的web语言
- XHTML(可扩展的超文本标记语言):作用与HTML类似,是为了解决HTML的混乱问题而生,语法更加严格
link 和@input的区别
- 来源的区别:link属于XHTML标签,而@import属性css
- 加载顺序的区别:页面加载时,link会被同时加载,而@import在页面加载完成后才会加载引用的CSS
- 兼容性的差别:@import属于css2.1版本,只有在IE5以上才可以被识别,而link是HTML标签,不存在浏览器兼容性问题。
- 使用dom控制样式时的差别:当使用javascript控制dom去改变样式的时候,只能使用link标签,因为@import不是dom可以控制的.
浏览器内核(现代4大内核)
- 1.Trident:IE (-ms-)
- 2.Gecko: Mozilla(-moz-)
- 3.webkit:苹果&谷歌(-webkit-)
- 4.Blink:谷歌&欧鹏
清除浮动
- 1.在最后一个标签后面,添加一个空的div,给其设置clear:both;
- 给父元素添加clearfix类名:
- clearfix:after{content=” “;display:block,clear:both;fint-szie:0;visibility:hidden;overflow:hidden;}
display none 和 visibility hidden区别?
- 两者都是用于元素的隐藏
- display: none隐藏后的元素不占据任何空间;而visibility: hidden隐藏后的元素空间依旧保留
三、 vue
vue的理解:
- 是JS渐进式的框架;由浅入深、由简单到复杂;它的代码体积小,基于虚拟DOM,数据双向绑定;
- 它可以把一个页面分成多个组件,当其他页面有类似功能时可以封装组件进行复用;
v-if和v-for v-show区别
- v-show是通过display:none来实现隐藏
- v-if是通过将元素从dom移除来实现隐藏
computed与watch的区别
- computed是计算属性 而 watch是监听属性
- computed具有缓存功能 而 watch不支持缓存
- computed不支持异步 而 watch支持异步
- computed是通过多个数据来影响一个数据 而 watch是通过一个数据来影响多个数据
vue的生命周期
- vue的生命周期有11个,常用的有8个;分别是
- beforeCreate:在组件被实例化之后,事件配置之前;此时el和数据对象data都是undefined,还没有初始化;
- created:数据和方法初始化完成,但el属性还没有,没挂载到dom上
- beforeMount:模板在内存中编译完成,但还没渲染到页面上;vue实例的el和data都初始化了,但是挂载之前为虚拟的dom节点
- mounted:vue实例挂载到真实dom上
- beforeUpdate:组件更新之前,
- updated: 组件更新完成
- beforeDestory:组件销毁前
- 直接会父子组件之间断开连接、指令也会断开连接;响应式的失效;事件监听器的解绑;比如v-on
- destroyed:组件销毁了
Vue组件之间是如何通信的?
- 父组件通过prop属性向子组件传递数据
- 子组件通过自定义事件向父组件传值
- 组件间通过ref进行通信
- 组件间还可以通过事件总线的方式进行通信
vue怎么实现双向绑定(v-model)
- Vue的双向数据绑定是通过由数据劫持结合发布者订阅模式来实现的;
- 数据劫持是通过Object.defineProperty()来劫持对象数据的setter和getter操作
- 通过Observer来监听自己的model数据变化,通过解析器Compile来解析编译模板指令,最终利用观察者Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化—->视图更新
- 在初始化vue实例时,遍历data这个对象,给每个键值对利用Object.definedProperty对data的键值新增get和set方法,利用事件监听DOM的机制实现视图—>数据的改变
- 实现的步骤:1.实现一个监听这Oberver来劫持并监听所有的属性,一旦属性有变化通知订阅者;2.实现一个订阅者watcher来接受属性变化的通知并执行相应的方法,从而更新视图;3.实现一个解析器compile,可以扫描每个节点的相关指令,并根据初始化模板数据以及初始化相应的订阅者;达到数据更新—>视图更新;
NextTick 原理分析
- NextTick可以将回调延迟到下次DOM更新循环之后执行
vue的路由
+即通过vue的路由允许我们通过不同的URL访问不同的内容
动态路由
- 一般用于从一个页面到另一个页面中传递参数使用;
- 即在path属性上加/:id,可以通过$route.params接收
如何改变URL?
- 声明式路由导航:使用vue-router内置的 组件来实现。
- 编程式路由导航:使用 路由api【$router.push()/replace()/back()】来实现页面跳转。
- 普通跳转,涉及到业务逻辑的用编程式路由导航
hash模式和history模式
- hash路由:表现上有#,上线后刷新页面没有报错,底层原理与history不同
- history路由:表现上没有#,上线刷新后页面可能会报404错误,底层原理与hash不同
router 和route的区别
- $route是路由信息对象,包含了路由信息参数
- $router是路由实例对象,包括了路由的跳转方法
路由懒加载
- 是一种性能优化方案,可以理解为导入组件的一种方式
- 可以这么理解,只需要访问一个页面时,不需要将所有的组件都加载进来,可以使用路由懒加载,需要哪个页面就加载哪个页面;它的原理是:webpack代码分割功能和异步组件的特点来实现
vue状态管理
- 状态管理可以解决组件之间的数据共享、实现数据缓存
- Vuex是vue全家桶中使用最流利的状态管理工具、一个专门为Vue.js应用程序开发的状态管理模式
- 状态管理工具在vue项目架构中是可选的,但从项目长远发展角度来看,最好还是使用
vuex的五大概念
- state: 存储中心,所有需要被共享或存储的数据都在这里定义
- getters: 相当于组件的计算属性,与state相关,当它所关系的state变量发生变化时,会自动计算
- mutations:Vuex中专门用于更新state
- actions: 专门用于与后端api打交道
- mudules:分模块,将不同的业务模块区分出来,使代码更加优雅
vuex流程
- 可以简单理解为Vue component触发事件,通过Action调后端数据,将后端回传的数据通过Mutations更新state,state将数据渲染到component中
vue 是怎么识别数据改变然后操作虚拟dom改变
- 获取监听变化后生成的虚拟树节点
- 与上一次虚拟DOM节点树进行比较
- 找到差异部分,渲染到真实的DOM节点上
- 更新视图
浅谈vue 的虚拟dom
+虚拟DOM的由来:JS是解析引擎的、页面渲染是渲染引擎的、两者之间的通信是通过DOM操作进行的,这样会消耗很多性能。虚拟DOM的诞生就是为了提高页面渲染性能
- vue的虚拟DOM:Vue中有模板解析的函数、可以对html进行解析编译、从而转变成渲染函数,渲染函数执行后就变成了虚拟DOM节点树。当虚拟节点准备映射到视图的时候,为了避免额外的性能开销,会先和上一次的虚拟DOM节点树进行比较,然后只渲染不同的部分到视图中。
- 虚拟DOM保存在内存中、在creact之前生成
vue优化
- 不要在模板里面写过多表达式
- 循环调用子组件时添加key
- 频繁切换的使用v-show,不频繁切换v-if
- 尽量少用float,可以用flex
- 按需加载需要的组件
路由守卫
- 它的作用:阻止未登录用户进入需要权限的界面
- router.beforeEach((to,from,next)=>{})来实现的
{{}}一闪而过解决方法
- 可以给{{}}外层添加一个div,里面写v-clock指令
vue中如何实现多页面
- 多个页面中挂载多个根组件就可以啦;
四、React
jsx的理解
- JSX是React官方推荐的一种语法糖;在React开发中不是必选的,可以不用,但不用就比较麻烦;
- JSX实际上是变量、是对象、是React元素;JSX使用时必须要引入React;JSX中可以使用表达式,但要使用{}包裹;JSX可以嵌套;默认可以防注入攻击;可以复用
- 在React开发中,推荐使用JSX,使用JSX可以使代码更加优雅,便于维护;
在react中有几种组件创建方式
- 使用ES5API:reactCreatElement创建(奎特爱了门特)
- 使用class关键字创建类组件
- 使用ES5function函数或ES6箭头函数来创建无状态组件
无状态组件和类组件
- 类组件是使用class关键字来定义组件;它的特点是有state,有生命周期,有上下文、ref、this等特性;和无状态组件相比性能比较差
- 用function关键字或箭头函数定义的组件;由于它没有state,被称为无状态组件;没有生命周期,没有上下文,this,ref等特性;与类组件相比,性能更高;
sate、setState异步特性、虚拟DOM
- setState是React中专门用于更新vm,触发diff运算,更新视图的
- setState默认是异步的,但在定时器中却是同步的;
- 当有多个setState执行时,React会将其自动合并,只执行一次diff运算,一次视图更新
生命周期整个流程(321)
- react生命周期分为三个阶段:装载阶段、更新阶段、销毁阶段。在装载阶段常用的生命周期有三个:counstructor,render,componentDidMount;在更新阶段常用的有两个:render 和 componentDidUpdate;在销毁阶段有一个:componentWillUnmount
- 更新阶段React做了什么?:更新阶段setState触发state进行更新;首先生成一个虚拟DOM,这时候内存中有两个虚拟DOM;接着 diff 运算对这两个虚拟DOM进行遍历,找出变化最小的节点然后标记出来变成脏节点;最后patch给其他的,执行真实的DOM操作
- shouldComponentUpdate:这是一个开关,用于性能优化,我们可以精准控制某些state变量发生时不更新视图
什么是受控表单,什么是非受控表单
- 在React中表单是单向绑定的,要想让视图变化,state数据必须改变
- 受控表单指表单的 value/checked由 state 完全控·制
- 非受控表单指表单的value和checked 不受 state 完全控制
React的传值方式:
- 父组件向子组件传值是通过props属性进行传值
- 子组件向父组件是通过自定义事件来传值
- 兄弟组件之间的传值是通过状态提升,将需要共享的数据传到父组件去进行数据共享;
组件的复用是组合还是继承?
- 使用的是组合:基于props来使用,props.childen的使用,props自定义的属性
上下文是什么,解决什么问题
- React中有个API:creatContext
- 在根组件上注入数据,然后组件树上所有组件节点都可以访问
- 特点:数据只能单向传递,即从根组件向后代组件传递
- 状态管理就是借助上下文来实现数据的传递
高阶组件:如何理解,做过啥事?
- 是一种基于React组合特性而得来的一种设计模式、软件开发经验
- 它的作用是React业务逻辑复用的一种方案
- 它也被称为高阶函数、纯函数、容器组件
- 使用高阶组件做过粗细粒度的权限管理;不同用户进入同一个界面,显示的东西有所不同;
类型检查:prop-Types
- 验证Props的数据类型
- 安装的第三方包:prop-type
Hook
- 是react 16.8提供的一套API,用于解决函数式组件中缺少类组件相关特性的问题,我常用的有usesate和useEffect;
- useState:定义一个声明式变量,当变量变化时视图自动更新
- useEffect:相当于react的生命周期;第一个参数相当于componentDidMount:return相当于componentWillUnmount;第二个参数是伪数组,相当于componentDidUpdate;useEffect可以使用多次
react路由:react-router-dom
- 使用的是第三方的路由:react-router-dom,需要安装使用
- 用于编程式路由跳转,动态路由传递
- 常用的组件有:HashRouter/BrowserRouter,Route,NavLink,Redirect,Switch等
- 没有被Route组件直接包裹的React组件中,是没有路由API的。那怎么办呢?
- 在类组件中,只能使用 withRouter 来解决问题:
- 在无状态组件中,可以使用 withRouter,也可以使用 useHistory来解决问题。
- withRouter 是一个高阶组件,让那些没有被Route组件直接包裹的React组件拥有路由API
- useHistory 是ReactRouter提供的Hooks API,帮助我们在无状态组件中使用路由API
代码分割(路由懒加载)
- 代码分割是性能优化的一种解决方案。比如我们的路由系统中有100个组件,我们在react项目启动时不需要对这100个组件都进行编译,只编译当前URL对应的组件,这就可以用到代码分割的功能;
- webpack代码分割以及配合路由实现
状态管理
- 状态就是数据,状态管理工具是用来对应用程序中数据进行科学的管理;最早出现状态管理思想是Flux,Flux只是一套数据流管理的指导思想、设计模式;常用的状态管理工具有mobox和redux;
mobox (响应式状态管理库)
- mobox用于定义store、mobox-react用于把mobox和react组件连接起来;借助了react的上下文和高阶组件
redux(js状态管理器)
redux-thunk
- 解决异步actions,用于把一个异步的action转化成两个同步的action;
- 比如我们要把后端数据放在store中,在组件中先发送一次空的action,通知调接口;调接口成功后,再把后端真实数据dispath()到store
三三原则
- 第一个’三’:方法:
- createStore(combineReducers({aReducer,bReducer}),[iniiState],applyMiddleware(thunk))
- creacteStore:是创建Store,要求必须要有reducer传入
- combineReducer:用于把一个大的reducer切分成多个小的reducer
- applyMiddleware:用于扩展redux功能,比如调接口,支持异步action转同步action
- createStore(combineReducers({aReducer,bReducer}),[iniiState],applyMiddleware(thunk))
- 第二个’三’:API:
- Store:是redux的数据存储中心,他可以接收dispatch过来的action,把action分配给reducer进行处理,当store的数据再次发生变化时,视图自动更新
- Reducer:是函数、纯函数;它用于处理store分配给自己的任务,处理数据,返回新Store
- Action:是视图和store的纽带,它是被dispath到store中,action的固定格式是{type,payload}
- 第三个’三’:store的三个特点:
- Store是只读的,不能直接修改,建议使用深复制的方式生成新的store,在修改
- Store是单一数据源
- Store只能用纯函数来修饰
变量提升
- 通常,多个组件需要反映相同的变化数据,这时我们建议将共享状态提升到最近的共同父组件中去
vue和React区别
- vue是尤雨溪写的、React是Fecebook写的
- vue中的数据是双向绑定,而React是单向数据流
- vue中有很多指令,React中没有那些指令
- vue中的生命周期是固定的;而React中很多生命周期已经慢慢废弃
五、微信小程序登录流程
- 微信小程序登录涉及到三端:微信小程序端、后端、微信服务器端
- 小程序端通过wx.login()获取code,通过wx.request()发送code到后端;后端经过一系列的处理后将3rd_session返回给小程序端,小程序端将3rd_sesion存入storage中;后续用户重新进入小程序,调用wx.checksession(),检测登录状态,如失效,则重新发起登录