持续更新ing~
- 前端基础github地址。
README.md可以下载到typora中打开,会有整个大纲目录显示(github中markdown目录快捷生成方式不现实,之后可能会想办法生成贴过来,暂时不做相关处理) - 前端基础gitbook地址。
README.md中会实时更新进度内容。gitbook中考虑整个学完整理完成之后,再去统一处理发布,敬请期待!gitbook版本可建议后期碎片化时间进行复习使用。 - 前端基础csdn地址。
CSDN博客专栏前端自我修养进阶中,也会一篇一篇实时更新相关知识点。 - 前端基础一掘金地址、前端基础二掘金地址
⭐️就是最好的鼓励哦wink~💗
JS Web API
- JS基础知识,规定语法(ECMA 262标准)
- JS WEB API,网页操作API(W3C标准)
- 前者是后者的基础,两者结合才能真正的在实际中应用
JS WEB API范围
- DOM操作
- BOM操作(浏览器上的事情:浏览器导航、浏览器url地址、浏览器跳转、浏览器宽高)
- 事件绑定
- ajax
- 存储
前言
- Vue和React框架应用广泛、封装了DOM操作
- 但是DOM操作一直都是前端工程师的基础必备知识
- 只会框架不会dom操作的程序员不会长久
5.17
1、DOM操作(Document Object Model文档对象模型的集合)
题目
-
DOM属于哪种数据结构
- 基于树形结构
-
DOM操作的常用API
-
attr(attribute)和property的区别
- property:修改对象的属性,不会体现在html结构中(不会对节点有什么影响)
- attr:直接修改html属性,会改变html的结构(改变标签结构)
- 两者都可能引起dom重新渲染(尽量用property去进行操作,因为设置property一定会重新渲染,attribute不一定。重新dom渲染是一件比较耗费性能的事情)
-
一次性插入多个dom节点,考虑性能
- dom节点缓存
- 创建片段,一次性插入createFragment
知识点
- DOM本质
- 从html解析出来的树
html实际上也是一种特殊的xml
-
DOM节点的操作
- 获取节点
- getElementById
- getElementByClassName
- getElementByTagName
- document.querySelectorAll
- attribute:直接修改dom结构,直接对标签有影响
const pList = ducument.querySelectorAll('p') const p = pList[0] p.getAttribute('data-name') p.setAttribute('data-name','smileyqp') p.getAttribute('style') p.setAttribute('style','font-size:30px')- property:修改js变量的属性,设置不会对标签有什么影响
- 用js的属性操作的一种形式
const pList = ducument.querySelectorAll('p') const p = pList[0] console.log(p.style) console.log(p.style.width) console.log(p.style.className) console.log(p.nodeName) //nodeName节点的名称 console.log(p.nodeType) //nodeType节点的类型 - 获取节点
-
DOM结构的操作
- 新增/插入操作
- 获取子元素列表,获取父元素
- 删除子节点
const div1 = document.getElementById('div1')
const div2 = document.getElementById('div2')
//新建节点
const newP = document.createElement('newP')
newP.innerHTML = 'this is newP'
//插入节点
div1.appendChild(newP)
//移动节点
div2.appendChild(p1) //将一个已经存在于dom中的元素append到另外一个中去,那么就是将节点移动过去的
//获取父元素
console.log(p1.parentNode)
//获取子元素列表;类似乎组转化成数组Array.prototype.slice.call,然后过滤类型为1,即p的元素节点
div1.childNodes();
const div1childNodesP = Array.prototype.slice.call(div1.childNodes()).filter((child)=>{
if(child.nodeType === 1){
return true;
}
})
//删除子节点
div1.removeChild(div1childNodesP[0])
-
DOM性能
- dom查询做缓存(减少dom查询。将dom缓存,dom查询改成变量查询)
//不缓存dom查询结果 for(let i = 0;i<document.getElementByTagName('p').length;i++){ //每次查询都会重新去计算length,频繁进行dom查询 } //缓存dom查询的结果 const plist = document.getElementByTagName('p') const plength = plist.length; for(let i = 0;i<plength;i++){ //缓存dom查询,只需要进行一次dom查询 }- 将频繁操作改成一次操作
- 创建文件片段,然后再一次插入(createFragment)
const listNode = document.getElementById('list') //创建一个文档片段,此时还没有插入dom const frag = document.createDocumentFragent(); //执行插入 for(let x = 0;<=10;x++){ const li = document.createElement('li'); i.innerHTML = 'list item'+x; frag.appendChild(li) } //都完成之后再插入dom树中 listNode.appendChild(frag)
2、BOM操作(Browser Object Model)
- 如何识别浏览器类型
- 分析拆解url的各个部分
知识点
- navigator:浏览器信息
- screen:屏幕信息
- location:地址信息
- history:前行后退信息
navigator和screen
//navigator
const ua = navigator.userAgent; //获取当前浏览器的信息
const isChrome = ua.indexOf('Chrome')
console.log(isChrome)
//screen
onsole.log(screen.width)
cobsole.log(screen.height)
location和history
//location
console.log(location.href)
console.log(location.protocol)
console.log(location.pathname)
console.log(location.search) //获取url传的参数
console.log(location.hash) //获取哈希,也就是#后面的内容
//history
history.back();
history.forward()
3、事件
题目:
- 编写一个通用的事件监听函数
- 描述事件冒泡的流程
- 基于dom树形结构
- 事件会顺着触发元素往上冒泡
- 应用场景:事件代理
- 无限下拉图片列表,如何监听每个图片的点击
- 事件代理
- 通过
e.target来获取触发元素 - 用matches来判断是否触发元素
知识点
- 事件绑定(addEventListener)
const btn = document.getElementById('btn1')
btn.addEventListener('click',event=>{
console.log('click')
})
//普通绑定:简易通用的事件绑定函数;详细通用事件绑定函数在下面将会提到
function bindEvent(elem,type,fn){
elem.addEventListener(type,fn)
}
const a = document.getElementById('link1')
bindEvent(a,'click',e=>{
e.preventDefault(); //阻止默认行为;比如组织链接的点击跳转
console.log(e.target); //获取点击的元素
alert('this is aaa')
})
- 事件冒泡:顺着dom结构往上上冒泡
- 例如:在body上添加事件,如果点击它子元素,那么都会冒泡到body上去
stopPropagation可以阻止冒泡
- 事件代理
- 事件代理: 不好挨个去绑定事件,就绑定事件到它父标签上。
- 事件代理是基于事件冒泡来做的,有了事件冒泡的机制才能在这个机制上去实现代理。
- 事件代理的场景:一般是通过某种形式,比如图片列表的无限下拉加载。可能并不能知道容器里面到底有多少个图片标签,也没法一个个去绑定事件。这个时候我们就可以通过冒泡去获取事件,我们就可以通过一些方式去拿到这个点击的图片
事件绑定函数(考虑代理)
- 综合以上两种(加上冒泡的情况)
//代理绑定
function bindEvent(elem,type,selector,fn){ //selector要筛选的触发元素选择器
if(fn == null){ //说明传的是三个参数;也就是知识普通绑定,第三个参数就是fn
fn = selector;
selector = null;
}
elem.addEventListener(type,event=>{
//event.preventDefault();
const target = event.target;
if(selector){ //有selector也就是代理绑定(存在冒泡情况)
if(target.matches(selector)){ //判断当前元素是否符合我们传入的这个选择器
fn.call(target,event)
}
}else{ //没有selector,普通绑定情况
fn.call(target,event) //因为需要fn的this指向这个元素,所以要call绑定一下当前触发的元素
}
})
}
//代理绑定
const div3 = document.getElementById('div3')
bindEvent(div3,'click','a',function(event){ //注意:这里不能用箭头函数,因为里面this指向
event.preventDefault();
alert(this.innerHTML)
})
5.18
4、ajax
题目
- 手写一个简易的ajax
function ajax(url){
const p = new Promise((resolve,reject)=>{
const xhr = new XMLHttpRequest();
xhr.open('GET','data/test.json',true); //true的意思是异步请求
xhr.onreadystatechange = function(){
if(xhr.readystate === 4){
if(xhr.status === 200){
resolve(JSON.parse(xhr.responseText))
}else if(xhr.status === 404){
reject(new Error('404 not found!'))
}
}
}
});
xhr.send(null)
return p;
}
const url = '/data/test.json'
ajax(url).then(res=>{
console.log(res)
}).catch(err=>{
console.log(err)
})
- 跨域常用的实现方式
知识点
- XMLHttpRequest
//手写简易的ajax
//get请求;post请求差不多
const xhr = new XMLHttpRequest();
xhr.open('GET','data/test.json',true); //true的意思是异步请求
xhr.onreadystatechange = function(){
if(xhr.readystate === 4){
if(xhr.status === 200){
alert(xhr.responseText)
}else if(xhr.status === 404){
console.log('404 not found ')
}
}
}
xhr.send(null)
- 状态码
- 跨域:同源策略跨域解决方案
- 什么是跨域(同源策略)
- JSONP
- CORS(服务端支持)
同源策略
-
ajax请求时,浏览器要求当前网页和server必须同源(安全)
-
同源:协议、域名、端口三者必须一致
-
加载图片、css、js可以无视同源策略
<img src=""/>(注意:有的图片可能做了防盗链)<link src=""/><script src=""></script><img src=""/>可以做统计打点,可使用第三方统计服务<link src=""/>和<script src=""></script>可以使用CDN,CDN一般都是外域<script src=""></script>可以实现JSONP
跨域
- 所有的跨域都必须经过serve端允许和配合
- 未经serve端允许就实现跨域,说明浏览器有漏洞,危险信号
JSONP
<script></script>可以绕过跨域限制- 服务器可以任意动态拼接数据返回
- 所以,
<script></script>可以获得跨域数据,只要服务端愿意返回
CORS 服务器设置http header
- 服务器允许跨域
ajax的常用插件
- jquery
- fetch
- axios
5、存储
题目
- 描述cookie、localstorage、sessionStorage的区别
- 容量
- API易用性
- 是否跟随http 请求发出去
知识点
- cookie
- localstorage和sessionstorage
cookie
- 本身用于浏览器和server通信
- 被"借用"来本地存储
- 可用
document.cookie=...来修改 - 存储大小,最大4kb
- http请求时候需要发送到服务端,增加请求数据量
- 只能用
document.cookie=…来修改,太过简陋
localstorage和sessionstorage
- html5专门为存储而设计,最大可以存储5M
- API简洁易用,用setItem和getItem
- 不会随着http请求被发出去
localstorage和sessionstorage区别
- localstorage数据会永久存储,除非代码或者手动删除
- sessionstorage只会存在于当前会话浏览器关闭则清空
- 一般用localstorage多一些
6、开发环境
- git
- 调试工具
- 抓包
- webpack babel
- linux常用命令
git
- 最常用的代码版本管理工具
- 大型项目多人协作,必须使用git
chrome调试工具
- elements
- console
- debugger
- network
- application
抓包
- 移动端h5页,查看网络请求
- win一般用fiddler
- mac一般用charles
- 抓包过程:
- 手机电脑连同一个局域网
- 手机代理到电脑上
- 手机浏览网页即可抓包
- 查看网址请求
- 网址代理
- https
webpack和babel
- ES6模块化,浏览器暂不支持
- ES6语法,浏览器不完全支持
- 压缩代码、整合代码,让网页加载更快
linux
- 公司上线的服务器一般是linux
- 测试机也一致,linux
- linux基础命令
运行环境介绍
- 运行环境即浏览器(server 端有nodejs)
- 下载网页代码,渲染出页面,期间执行若干js
- 要保证在浏览器中:稳定且高效
运行环境涉及前端内容
- 网页加载过程
- 性能优化(体验优化)
- 安全
7、页面加载和渲染过程
题目
- 从输入url到渲染出页面的整个过程(见下:资源形式、加载过程、渲染过程)
- 下载资源:各个资源类型、下载过程
- 渲染页面:结合html、css、js图片等
window.onload和DOMContentLoad的区别- window.onload页面全部加载完成包括图片
- DOMContentLoaded是dom渲染完成即可,此时图片视频可能还没有加载完
document.addEventListener('load',()=>{
console.log('window loaded')
})
document.addEventListener('DOMContentLoaded',()=>{
console.log('dom loaded')
})
知识点
- 加载资源的形式
- 加载资源的过程
- 渲染页面的过程
资源形式
- html代码
- 媒体文件,如图片视频等
- js、css代码
加载过程
- DNS解析:域名=>IP地址
- 浏览器更具IP地址向服务器发起http请求
- 服务器处理http请求,并返回给浏览器
渲染过程
- 根据html生成dom树
- 根据css生成cssom(css对象模型)
- 将dom树和cssom整合形成render tree(渲染树:像是dom树中挂了css属性)
- 根据render tree渲染页面
- 遇到
<script>则暂停渲染,优先加载并执行js代码完成再继续(js进程和渲染进程共一个线程。script中可能有代码改了之前执行的结果,所以遇到script先暂停渲染)
为何建议把css放head中?
- 防止重复渲染(本来按照没有css的默认样式渲染,完成之后,又发现有样式又重新结合这个cssom进行重新生成render tree重新渲染。并且网速慢的时候对用户可能会出现两种样式切换)
为何建议把script放到最后?
- js没有放到最后就会导致页面渲染的过程比较长。因为js会暂停渲染。我们是期望先渲染完成再修改
图片渲染
- 图片渲染并不会阻塞dom渲染,只不过可能先空着等图片加载完成之后显示
8、性能优化
性能优化原则
- 多使用内存、缓存或者其他方法
- 减少CPU计算量、减少网络加载耗时
- (适用于所有编程性能优化、空间换时间)
从哪些方面入手
- 加载更快
- 减少资源体积:压缩代码
- 减少访问次数:合并代码(js、css、雪碧图)、ssr服务端渲染(数据一起给前端)、缓存
- 使用更快的网络:CDN(根据地域做静态文件访问服务)
- 渲染更快
- css放进head中,js放到body最下面
- 尽早执行js,用DOMContentLoad去触发
- 懒加载(图片懒加载、上滑加载更多)
- 对dom查询进行缓存
- 频繁dom操作合并到一起插入都没结构
- 节流throttle和防抖debounce (渲染更加流畅)
示例
- 资源合并
- 缓存
- 静态资源加hash后缀,根据文件内容计算哈希
- 文件内容不变、则哈希不变,那么url不变
- url和文件不变,则会自动触发http缓存机制返回304(减少了资源请求)

-
SSR(server side render)
- 服务端渲染:将网页和数据一起加载一起渲染
- 非SSR(前后端分离):先加载网页、再加载数据、再渲染数据
- 早先的JSP、PHP、APS都属于ssr,现在的react vue ssr
-
懒加载
- 缓存dom查询
- 多个dom操作合并一起插入dom结构
- 尽早开始js执行
- 在dom渲染结束之后就可以开始js执行没必要等到图片、视频等多媒体资源都加载完成之后再去执行
5.19
9、函数节流&防抖
- 函数节流:函数执行一次后,只有大于执行周期之后才会执行第二次(规定时间内只触发第一次生效)
//fn:要截流的函数;delay规定的时间
function throttle(fn,delay){
//记录上一次触发的时间
var lastTime = 0;
return function(){
var curTime = Date.now();
if(curTime-lastTime>delay){
fn.call(this); //修正this指向问题
lastTime = curTime; //闭包方式保存上次变量值lastTime
}
}
}
- 防抖函数:频繁触发的函数,规定时间内,只触发最后一次
function debounce(fn,delay){
var timer = null; //记录延时器
return function(){
if(timer){clearTimeout(timer)} //清除上一次延时器
timer = setTimeout(function(){
fn.apply(this)
},delay)
}
}
防抖debounce
- 场景:监听一个输入框的文字变化后触发change事件
- 直接用keyup事件会频繁触发change事件
- 防抖:知道用户输入结束或者暂停之后才会触发change事件
function debounce(fn,delay=500){ //debounce是对函数的封装,最糊返回的是一个函数
var timer = null;
return function(){
if (timer){clearTimeout(timer);}
timer = setTimeout(function(){
fn.apply(this,arguments);
timer = null;
},delay)
}
}
//使用
input1.addEventListener('keyup',debounce(function(){
console.log('使用防抖函数:'+this.value)
}),1000)
节流throttle
- 场景:拖拽一个元素时候要随时拿到这个元素的位置
- 如果直接用drag事件那么会频繁触发,十分容易导致卡顿
- 保持一个频率连续触发
function throttle(fn,delay=500){
let timer = null;
return function(){
if(timer){return;}
setTimeout(()=>{
fn.apply(this,arguments); //apply:绑定this,绑定参数
timer = null;
},delay)
}
}
//使用
div1.addEventListener(throttle(function(e){
console.log(e.offsetX)
console.log(e.offsetY)
},100))
10、安全
问题:常见的web前端攻击方式有哪些
- XSS跨站请求攻击
- XSRF跨站请求伪造
XSS跨站请求攻击
- 博客前端界面嵌入script脚本
- 脚本内容:获取cookie发送到服务器(服务器配合跨域)
- 发布博客,有人查看,可以轻松获取查看人的cookie信息
XSS预防
- 替换特殊字符。例如:
<变成&It;>变成>,那么script就不会作为脚本执行 - 可以使用
https://www.npmjs.com/package/xss的xss工具
XSRF跨站请求伪造(类似于钓鱼链接)
- 比如:攻击者想要购买一件商品,知道了购买的请求url等
- 然后用发邮件形式,发送一个图片隐藏的链接
<img src='xxx.com/pay?id=100'/>。图片可以跨域。 - 如果收到的人已经登陆过这个购物网站,收到的人点击打开链接,此时就会将用户信息带过去,就会发送用点击链接的那个人的用户信息去购买
XSRF预防
-
使用POST接口,因为使用POST接口跨域是需要serve端进行支持的
-
增加验证,比如:密码验证码、指纹等