title: 前端知识点总结
author: 作者
top: false
toc: false
date: 2019-08-19 11:13:48
tags:
-
var let const
的比较-
let 是 块级作用域 ,其申明的变量只是在 其块级作用域中 有作用
块级作用域:可以直接理解为 只在 {} 内生效
**let 申明的 变量,用 window访问不了,var 申明的,window能访问 **
{ let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1
常见题目:
var a = []; for (var i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 10 var a = []; for (let i = 0; i < 10; i++) { a[i] = function () { console.log(i); }; } a[6](); // 6
-
-
变量提升 的区别
结论:
let const
不存在变量提升,var
有变量提升直观的讲:变量提升就是 可以先 使用变量,后申明变量(注意这里只是说的表面上看,实际上 浏览器解析的时候,会将 所有的变量 先全部 拿出来 申明,然后在执行其他使用代码 这就是 变量提升)
-
而
let const
不支持 变量提升 ,也就是说,必须 先申明 后使用// var 的情况 console.log(foo); // 输出undefined var foo = 2; // let 的情况 console.log(bar); // 报错ReferenceError let bar = 2;
-
暂时性死区
结论:只要在 块级作用域内 申明的 变量(let const),区域内部的 变量与外界完全隔离
eg:
var tmp = 123; if (true) { tmp = 'abc'; // ReferenceError let tmp; }
-
变量是否可以重复定义
结论:let的块级作用域内只能定义同样的变量一次,var 是可以定义多次的,const 是常量不可变(const也是块级作用域的)
eg1:
// 报错 function func() { let a = 10; var a = 1; } // 报错 function func() { let a = 10; let a = 1; }
eg2:
function func(arg) { let arg; } func() // 报错 function func(arg) { { let arg; } } func() // 不报错
-
块级作用域有什么用
-
避免内部变量 覆盖 替换了 外部作用域的 变量,隔离作用
匿名函数自执行,相当于起到同样的作用,现在有 {} 块级作用域就不用那么麻烦,很多框架就是这样的
-
避免 for循环时 计数的变量 泄露成全局变量,带来困恼
eg
var s = 'hello'; for (var i = 0; i < s.length; i++) { console.log(s[i]); } console.log(i); // 5
-
-
apply call bind
作用,如何实现总结:主要都是为了改变 函数执行 的 this 指向问题
-
为什么需要出现这几个 函数
js中函数 在执行过程中 this 的指向是根据 执行时候 当时的上下文环境 决定的,所有只有在执行的时候,才会知道this 到底指向的是 什么对象
而
apply call bind
最终都是为了改变 函数 执行时,this的指向问题 -
它们之间的区别
-
apply
与call
g功能用法相似,区别在于fn.apply(obj,args) // args 为数组 会将 args 全部传入 fn函数 fn.call(obj,arg1,arg2,....) // call 需要将参数 手动一个一个 传进去 fn.call(obj,...args) // 当然在 ES6 中 用 ... 的语法 同样可以解决这样的问题,功能就一样了
-
-
- `apply call` 与 `bind` 的区别
**总结:1.返回结果不一样 2.`bind` 可以实现颗粒化**
1. `apply 与 call` 直接就是调用了 函数(fn 函数立刻执行了)
2. `bind` 绑定函数,返回结果是一个新的函数(新函数是原函数的一个包装,将this 指向绑定的对象)
3. `bind` 可以实现颗粒化,绑定时可传入 多个参数,当原函数 调用的时候,会将两次的 参数合并 传入原函数
- 使用场景
1. 用来实现 js 中的 **继承**
2. 对象内置方法的跨对象调用(可以实现将一个对象的内部方法 给 任何 其他不具有此方法的对象调用)
```
Math.max.apply(null,[1,2,4,7])
Math.max.apply(Math,[1,2,4,7])
```
-
未解决的问题:
apply call bind
一起使用的时候要,如何解释... -
防抖和节流
总结:防抖和节流不是一回事
-
防抖和节流的概念的区别
防抖:在一个固定时间间隔内(比如10s),重复执行同一个函数,永远执行最后一个,并以此为时间为基础,未来10s内依旧执行最后的一次 (比喻:等公交)
节流:在一个固定时间间隔内(比如10s),重复执行同一个函数,永远执行一次(第一次),忽略其他调用 (比喻:水龙头滴水)
-
-
防抖和节流如何实现
- 利用 时间戳,每次执行的时候 对比 上次的时间戳 ,来处理是否要 执行当前的函数执行
- 利用
setTimeOut
(时间延时函数), 每次在 执行函数之前,检查 上一次的 延时函数是否还存在(也就是判断上次函数是否已经执行),然后根据自己的逻辑 处理 (可以将上次的 延时函数 重置新的,也可以不执行)
-
场景:
- 游戏领域
- input 输入的同时 实时搜索结果,多次DOM的渲染,当data 在很短的时候内 ,修改的时候,会不断的渲染 DOM
- 监听
scrollow
等事件执行函数
-
自己实现一个(一定要自己不参照情况下,手打代码)
// 节流 // 使用时间戳,比较当前时间 与 上次时间 ,如果 时间间隔 > 间隔时间,执行函数,若 < 时间间隔,什么也不做 function throttle(fn,wait=80) { let timePre = 0; return function myFunc(){ let now = + new Date(); if(now - timePre > wait){ timePre = + new Date(); // 1.一定要传入 this,看下面 obj的调用(才能展示出来) fn.apply(this,arguments) // fn(arguments) } } } function test1(x,y){ console.log('x y ....',this); } let fn1 = throttle(test1); fn1('cccc','yyyy'); // 此时内部 this 是window let obj ={x:'0000',y:'111111',func:fn1}; obj.func('1','2'); // 此时内部 this 是 obj
-
原型、原型链和继承
问题:还是没有完全懂
-
原型 与 原型链
所有对象(引用类型)都有一个
__proto__
属性 ,值即为 原型(一个普通对象而已)所有函数都有一个
prototype
属性,值即为 原型(一个普通对象而已)**对象(引用类型)的
__proto__
=== 其构造函数的prototype
**原型链的顶端是
Object.prototype.__proto__ === null
,也就是 null
-
**原型链:**当一个对象(引用类型)使用点语法的时候,首先从自己的内部寻找此属性,若没有从其原型(一个普通对象)寻找改属性,若没有,再次从该原型的原型中去寻找,直到顶层 null,若都没有,返回 `undefined`
-
继承
js的继承实际上就是改变 构造函数的 原型(将原型指向 父类的一个实例)
-
js中的继承说明:
- js是一门面向对象的语言,但是 js 中没有严格意义的 类 与 实例的说法。而是通过 一个原型 的对象 达到 “继承”的目的。
所以说 js 是比较另类的语言
-
ES6
中 开始有了class let const
等概念 - 趋势:更加接近 面向对象语言的 语法与概念 ,也更加严谨
手写一个 js 继承 TODO
-
-
模块化
根据历史知识来理解与记忆
**对全局变量的影响 **
命名的冲突与相互替换
依赖的管理
同步与异步 是否预下载,是否预执行
-
有哪些模块化,发展流程是什么(演变历史)
-
起初
js
语言很弱,逻辑主要在 后端,所以没有什么模块的概念 都是 直接 写function
污染全局的变量、变量容易被外界改变、管理不方便
匿名函数 + 闭包 典型的是 jQuery 等其他插件
-
node.js的兴起,前端可以没有 模块,但是 后端必须要有 模块 commonJs (nodejs社区创建,开始叫 serverjs)
var abc = require('xxx') // 导入 // 导出 是一个对象 module.export = { }
特点:导入是同步的,因为后端加载文件是在本地服务器,所以无所谓
问题:推广到前端的时候,需要异步,因为前端是通过 网络请求来下来模块的
-
node.js
社区 出现了 分歧,有三个分支-
第一个分支:在原有的
commonJs
的基础上 做兼容,新增Transport
规范 **Browserify
compont
、es6-module-transpiler
等 **通过工具 将现有node模块 转成 浏览器能用的模块
-
第二个分支:制定了
AMD
标准(也就是异步)requestJs
特点:预先下载、预先执行
-
第三个分支:
module2.0
,算是折中吧,融合上面两个的特点FlyScript
(推广不好,后期自己全部删除了)特点:预先下载,懒执行
-
-
基于第三个方案的基础上 又融合了很多其他的方案
CMD
国内大牛 淘宝的 玉伯开发seaJs
特点:预先下载,懒执行。其他 语法上面的区别
注意:后期发展
AMD CMD
都有相互兼容对方的优点 -
ES6
算是原生支持 模块化,但是浏览器还没有支持,期待中,目前需要 通过babel-loader
编译-
语法
// 导出 export {} //导入 import {x,y} from xx import * as model form xx
-
-
-
2. 特点:
- `Commonjs` 模块运行时加载,`ES6`模块是编译时就输出接口
- `Commonjs`输出的为 **值的浅拷贝** ;`ES6`输出的是 **值引用**
各自的 区别是什么
-
js 中 异步 (比较大的模块)
-
js 中异步的概念简述 (js 单线程)
- js 是单线程的,js 代码运行是单线程的
- 当有耗时操作就会阻碍程序,使得浏览器 假死,所以 异步就出现了,弥补js 没有多线程的缺点
- 异步基于 事件循环 eventLoop,也就是,只有当 不是异步的代码执行完了,才会 执行 异步代码
-
-
有哪些异步,简述各自的 特点(
callback Promise async wait
)-
callback
作为 js 实现异步的最基础的手段,使用简单,将函数作为参数传递给另外一个函数,在之后的某个条件下才会触发传入的函数,实现异步缺点:会出现回调地狱
Promise
为了解决 cb 的 回调地狱问题,链式操作,结构明了-
async wait
在Promise
的基础上更加简单,将异步代码 写成 同步的逻辑,更加符合 人的阅读与理解基于genertor 与 Promise实现
xx
-
-
定时器函数(
setTimeut setinterval requestAnimationFrame
)属于原生Js的内置函数,直接实现异步
callback
Promise (手写一个
Primise
)Generator
async awit
-
Event Loop (由 js 异步 延展到 js的 Event Loop)
- node 与 浏览器中的 Event Loop 不是一样的,差异在哪里
-
浏览器——基础知识
BOM 操作
-
DOM 操作
增删改查
事件(事件绑定与代理)
Ajax
-
跨域问题
-
什么是跨域
同源策略:只允许 同一个 协议 域名 端口相同的网页 请求后端数据(请求已经发出,只是reponse被浏览器拦截)
为什么:确保安全 (预防CSRF攻击,想象钓鱼网站)
-
如何解决
-
jsonP
利用
<script>
标签没有跨域的限制缺点:只允许get 请求
<script> function jsonp(data) { console.log(data) } </script>
-
-
2. CORS
**主要后端设置 http请求的配置即可 允许 指定域名 访问接口**
`Access-Controll-Allow-origin`
3. postMessaege
**用于iframe 嵌套的页面之间相互通信**
-
存储问题
-
cookie
生命周期:一般由 服务端 设置 过期时间,当前 也可以前端js 也可以清除
存储大小:4k
说明:主要用于 客户端与服务端通信的,识别用户身份,不建议作为存储使用
-
安全参数设置:可以设置不同的参数控制cookie
- value:尽量用密文 并加密
- http-only:只允许服务端修改,不能通过js修改,安全
- secure: 只能在https 协议的请求中 携带
- same-site:浏览器不能在跨域中携带 cookie
-
- localStrong
1. 生命周期:一直在,除非手动删除
2. 存储大小:4M
- sessionStrong
1. 生命周期:页面关闭 就 消除
2. 存储大小:4M
- indexDB
1. 生命周期:一直在,除非手动删除
2. 存储大小:很大很大
3. 说明:就是客户端的一个小型数据库
- service worker
service worker 是运行在 浏览器后台的 **独立线程** **必须是https请求**
主要是为了 **缓存 网络请求**
-
缓存问题
-
缓存位置的优先级(从前到后获取数据)
service worker (上面已经讲过)
-
Memory cache (内存缓存)
速度快,持续时间短,随时就没有了
-
Disk cache
速度慢,持续时间长,随着进程而释放
-
Push cache
http2 的内容,了解即可 缓存时间短,会话结束就没有了
-
网络请求
没有缓存,就自能网络请求
-
缓存策略 注意:都是通过 HTTP header来设置的
-
强缓存
- Expires:Wed, 22 Oct 2018 08:41:00 GMT(xx之后过期)
- cache-control:max-age=30(30秒之后过期)
-
协议缓存
当缓存过期,便发送数据的最后获取时间给服务端,服务端判断之后告诉服务器,数据没有变,304,便再次使用之前的缓存
- Last-modified
- Etag
-
场景使用
-
频繁变化的文件
cache-control:no-cache
配合Last-modified
每次校验是否需要跟新 -
html 代码
cache-control:max-age100000
(html代码一般很少修改,只有当html 文件改了,即hash值变了再发起请求,否则很长时间都是用的缓存)
-
-
-
-
浏览器——安全问题
-
XSS
-
说明:注入可执行代码 并执行
- 持久性:代码被发送到 后端,后端执行了代码,不小心被 混入执行的 Mysql 的代码,可能影响到数据库
- 非持久性:代码发送到网页中并执行,影响程序,评论中写入js函数代码提交
-
防御:
转义,将一些敏感的 字符等转义
-
CSP:也就是白名单通
-
过http header 设置
Content-Security-Policy
//只允许加载本站资源 Content-Security-Policy: default-src ‘self’ //只允许加载 HTTPS 协议图片 Content-Security-Policy: img-src https://* //允许加载任何来源框架 Content-Security-Policy: child-src 'none'
-
-
-
- meta 标签设置`<meta http-equiv="Content-Security-Policy">`
- CSRF
- 说明:
**跨站请求攻击**也就是钓鱼网站
- 防御:
1. 设置第三方网站 得不到 cookie `SameSite`
2. 封掉第三方网络请求
3. 每个请求 token 验证
4. referce 表示请求是从哪个地方发过来的
- 点击劫持
- 说明
**把目标页面嵌入firame,隐藏部分内容,引导点击**
- 防御 **http header 设置参数限制 X-Frame-options**
1. 值为 DENY:页面不允许 以 iframe 的方式展示
2. 值为 SAMEORIGIN: 相同域名下 可以展示 iframe
3. 值为ALLOW-FROM:允许指定 来源的网页 可以展示 iframe
- 中间人劫持
- 说明:
**一般用公共的Wifi,有可能被劫持**
- 防御:尽量用 HTTPS
-
浏览器——渲染机制
a. 渲染由浏览器的渲染引擎完成,浏览器还有JS引擎,属于两个线程
b.火狐是 Gekco 引擎 chorm sarfor 是 Webkit 引擎
-
DOM 渲染
- 浏览器将 html 代码 (其实就是一堆字符串)词法分析 打标记
- 根据标记 转换成 node节点
- 根据 node 节点 组成 DOM 树
-
CSSOM 渲染
- 浏览器根据 Css 代码 转换成 CSSOM 树
-
渲染树
- 将 DOM树 与 CSSOM 树 结合起来,生成 渲染树
- 根据渲染树 调用 GPU 进行 布局(layout) 显示
-
影响渲染的因素与解决办法
- script 的位置,若在 body 之前,那么当 解析到 JS 代码,渲染便会 暂停 下载 JS 代码
- 如何避免:
- 将 JS 代码 放在 body 之后加载
- 将 JS 代码延时 或者 异步加载 defer(下载完立即执行) 和 async(下载完不立即执行)
-
重绘与回流
重绘:当改变 DOM 的样式 布局,DOM 会重绘
回流:当改变 DOM 的样式,DOM 会回流(改变了布局)
-
显然:
- 发生回流一定会触发重绘,发生重绘不一定触发回流
- 回流比重绘 消耗的资源 更大
-
6. 如何尽量避免 回流
- css 层级 **扁平化**(**渲染会从标签由内往外寻找,嵌套层级越少越好**)
- 尽量 合并多次操作 为 一次 操作 DOM 结构(**减少操作DOM的次数**)
- **少用table**
- **达到同样的效果,尽量减少影响布局的属性**,( visibity 代替 diapaly:none)
-
性能优化(浏览器+js )
-
图片加载优化(加载优化)
- 格式: 大图尽量用 jpeg,小图尽量用 png(base64 压缩)
- 小图尽量用 css svg代替
- 采用雪碧图
- 用CDN ,按需请求所需尺寸的图片(移动端一般用小图,大图浪费)
-
DNS 预解析 dns-prefetch
<link rel='dns-prefetch' href='xx.com'>
-
预加载
<link rel='preload' href='xx.com'>
-
预渲染
<link rel='prerender' href='xx.com'>
懒加载
-
懒执行
图片懒加载(先用占位图片)
-
CDN
静态资源尽量使用CDN
-
节流
水龙头,比方说3分钟一次,一段时间内,只允许一次事件的发生
实现:
- 使用
setTimeout
,若时间未到,则清除之前的 setTimeout - 使用时间戳,时间戳相减,大于间隔时间才执行事件
- 使用
-
防抖
从上次事件发生开始算,一段时间时间内,只允许一次事件发生(注意区别)
-
-
webpack
性能优化尽量使用高版本(版本高,框架内部做了很多优化),打包 node = production ,内部也有很多优化
- 缩短打包时间
-
loader
的优化 减少打包的范围 -
并行打包
happyPack
(js是单线程,将内部任务转换成 并行) -
DllPlugin
将特定的库提前单独打成包,此包一般情况行下,很长时间不会变(eg,将Vue 提前打成包)
-
- 缩小打包后的体积
- 压缩代码,也算节省时间的方式
- 按需加载,将不同路由 打包成 几个包,需要用到那个就加载哪个(对首页加载的速度有好处)
- scope Hosting 分析依赖关系,尽量合并模块到一个函数中
- Tree Sharing 分析 并去除 没有用到的代码
- 缩短打包时间
HTTP 协议
设计模式
-
框架 Vue
-
生命周期
- beforeCreated 无法获取到 props 与 data 的数据
- created 能够获取到 props 与 data的数据
- beforeMounted 创建VDOM(虚拟DOM)
- mounted 将VDOM 转换成 真实的DOM
- beforeUpdate 组件中数据更新前调用
- update 组件中数据更新后调用
- beforeDestroyed 组件销毁前 销毁事件 定时器等操作(否则有内存泄漏问题)
- destroyed 组件全部销毁
-
组件之间通信
-
props
与emit
父子组件通信 -
v-model
父子间通信 -
$parent
与$children
父子通信,多层通信 -
provide
与inject
父子通信 ,多层通信 -
eventBus
Vuex
任何通信
-
-
Vue 底层实现的原理
definedProperty 对每个属性 进行 set get方法监听,对应的修改DOM结构
缺点:Vue3.0 为何改成 proxy
- 无法监听数组,Vue内部自己实现了 Array的几种方法
-
- Vue 底层是如何编译的
- 响应式:根据 data 的变化 改变页面
- 模板引擎:模板如何被解析(**render函数 vdom**)
**模板就是字符串->js函数(render函数)->返回vnode(虚拟节点,也就是Vdom)**
- 渲染:
**根据vnode 渲染成 真实的节点,用的是专门的库**
- 其余知识点
1. `computed` 和 `watch` 的异同点
`computed` **:有缓存,只要依赖的属性如果不变,不会触发**
`watch`:**只要watch发生变化就执行**
2. `keep-live` 的使用
**当组件在页面消失,此组件仍然缓存着,会有两个钩子方法,隐藏于出现**
3. `data`的值为何 返回 是个函数
**保证每次创建的组件 数据都是 初始化的值,否则同一个组件创建出来的 公用一个data**
4. `v-if` 与 `v-show` 的区别
`v-if`:**false,页面不渲染,DOM不存在**
`v-show`:**false,页面DOM结构还在,只是隐了而已**
5. `nextTick` 是什么原理
**Vue所有的数据变化,最终相应到页面的变化,但内部有一个 事件循环的,在一定事件内才会执行一次,所以当数据发生变化,瞬间又要获取对应的变化DOM是报错的,nextTick事件是所有数据变化对应的DOM 渲染都完成的时候的一个回调函数**
6. xxx
- Vuex
1. 概念:核心就是**store(仓库)**,存放应用中的**很多状态(state)**,跟全局变量不一样
- **响应式**,当store 中数据发生变化,那么会相应的很多组件发生变化
- **commit(mutation)才能修改数据**,这样就能跟踪数据的变化
2. state(仓库),可以想象成 一个**全局的 data**,注意是**响应式**的,可放在 组件的 computed 里面
3. getter,**想象成对应的computed(计算属性,针对 state中的属性)**
4. mutation: 改变state 状态的 **唯一方法**,必须是**同步**
5. action:类似于 mutation的作用
- 不是直接改变数据,而是 调用 mutation 改变数据
- action 可以是异步的
6. module:**模块化**,当state 数据太多时,可以做分割,每个模块 就是有单独的 store state getter mutation action 等
-
框架 React
-
React 的生命周期
- componentWillMount 组件将要渲染(第一次)
- componentDidMount 组件已经渲染(首次)
- componentWillReceiveProps 接受到父类 props,在调用另一个 渲染器之前
- shouldComponentUpdate 返回 true false,组件是否要渲染
- componentWillUpdate 组件即将跟新 ,Dom 渲染之前调用
- componentDidupdate 组件已经跟新 ,Dom 渲染之后调用
- componentWillUnmount DOM销毁后,用于清除内存 等
-
shouldComponentUpdate 有什么用,有什么重要的 场景
根据自己的实际需求 去 决定 是否需要 重新 渲染(因为重新渲染 是比较耗费资源的)
-
setState 的方法,是异步还是同步,如何在异步之后 做些其他的操作
异步操作,
this.setState({},()=>{页面渲染之后调用})
-
this.state 和 props 有何异同点
- props 是从父组件 传递下来的,不可以修改
- 而state 是组件自身的,可以修改
-
Virtual DOM 了解吗?在React 中是如何工作的,流程
- 虚拟DOM,不是真实的DOM。而是一个 js 对象,树状的数据结构,用于描述 真实的DOM节点
- 如何工作:如果state有改变,那么 先改 虚拟DOM,等到一定的时间,统一 根据 虚拟DOM 与 真实DOM 的对比,只更新 不一样的地方
-
React 中箭头函数 怎么用
允许函数绑定上下文,改变函数的this 的对象
this.onChange.bind(this)
-
HOC 高阶组件了解吗?
类似于高阶函数
将组建作为参数 传入函数,返回一个新的组件,在内部可以对 原始的组件 有很多的 特殊处理
-
refs 是什么
返回一个组件的对象,父组件可以拿到 子组件的实例,实现数据交互
-
keys 有什么作用
给组件标号,再次渲染的时候,可根据标号,从新排序,而不需要重新渲染
-
redux 与 VueX
-
-
xxx