vue
双向绑定原理
简答:
Vue内部通过Object.defineProperty方法属性拦截的方式,把data对象里每个数据的读写转化成getter/setter,当数据变化时通知视图更新。
具体说一下Object.defineProperty:
Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
Object.defineProperty(obj, prop, descriptor) obj:要在其上定义属性的对象。 prop:要定义或修改的属性的名称。 descriptor:将被定义或修改的属性描述符。
进一步:
Object.defineProperty()具体实现:
//这段代码太重要了,请记住! let hr={ skill:'', experience:'' } Object.defineProperty(hr, 'skill', { get(){ console.log('必备技能:') return '不放鸽子' }, set(newVal){ console.log('经验要求:') } }) //读: console.log(hr.skill) //写: hr.skill='五年起步'
控制台打印 必备技能: 不放鸽子 经验要求: "五年起步"
发布订阅模式
现在已经可以检测到数据的读和写,然后就需要通知视图的更新了.
这里是典型的发布订阅模式,在这个模式下:数据是发布者(Observer),依赖对象是订阅者(Watcher),他们需要一个中间人来传递,那就是订阅器(Dep)。
总结:实现数据的双向绑定,首先要对数据进行劫持监听,所以我们需要设置一个监听器Observer,用来监听所有属性。如果属性发生变化了,就需要告诉订阅者Watcher看是否需要更新。因为订阅者Watcher是有很多个,所以我们需要有一个消息订阅器Dep来专门收集这些订阅者,然后在监听器Observer和订阅者Watcher之间进行统一管理。
附:从这张生命周期图看数据和视图在何时双向更新
参考链接:
推荐阅读:
v-for key
简答:
- 在写v-for的时候,都需要给元素加上一个key属性
- key的主要作用就是用来提高渲染性能的!
- key属性可以避免数据混乱的情况出现 (如果元素中包含了有临时数据的元素,如果不用key就会产生数据混乱)
特注:
当 v-if 与 v-for 一起使用时,v-for 具有比 v-if 更高的优先级,这意味着 v-if 将分别重复运行于每个 v-for 循环中。 所以,不推荐v-if和v-for同时使用!
$nextTick
$nextTick 是在下次 DOM 更新循环结束之后执行延迟回调用,在修改数据之后使用nextTick,则可以在回调中获取更新后的
怎么理解:看下面这个例子就豁然开朗
DOM:
初始化数据:点击事件:
触发changeMsg后:
可以看到,msg已经变成了Hello world,在changeMsg()方法中,先修改msg的值成为‘Hello world’,然后通过拿到dom的值再依次修改msg1、msg2、msg3的值,此时修改得到的msg1依然是‘hello vue’,this.$nextTick中修改得到的msg2则是‘hello world’,msg3依然是‘hello vue’,也就是说,在changeMsg()方法触发后,修改了msg的值,但是此时再通过dom取到的值还未改变,所以可以知道:
vue响应式的改变一个值以后,此时的dom并不会立即更新,如果需要在数据改变以后立即通过dom做一些操作,可以使用$nextTick获得更新后的dom。
参考链接:
虚拟DOM
简答:
虚拟 DOM 的实现原理主要包括以下 3 部分:
用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象; diff 算法 — 比较两棵虚拟 DOM 树的差异; pach 算法 — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树。
推荐阅读
浏览器
浏览器缓存
简答:
浏览器的缓存是为了性能的优化,通过重复调用本地缓存,减少Http请求这样的方式,达到减少延迟、减少带宽、降低网络负荷的作用。
- 过程:浏览器发请求,访问缓存,无缓存结果,发起HTTP请求,返回结果和缓存,存放缓存
- 缓存类型有:cookie、LocalStorage、sessionStorage
进一步:
- CDN 缓存
客户端直接从源站点获取数据,当服务器访问量大时会影响访问速度,进而影响用户体验,且无法保证客户端与源站点间的距离足够短,适合传输数据。
CDN解决的正是如何将数据快速可靠地从源站点传递到客户端,通过CDN对数据的分发,用户可以从一个距离较近的服务器获取数据,而不是源站点,从而达到快速访问、且能减少源站点负载压力的目的。
参考链接:
从输入URL到页面加载发生了什么
简答:
1.DNS解析 2.TCP连接 3.发送HTTP请求 4.服务器处理请求并返回HTTP报文 5.浏览器解析渲染页面 6.连接结束
性能优化
简答:
优化方法,结合雅虎军规35条标准,可以大致分为这么6类(非严格,有按自己的理解整理):
分类名 | 内容 |
网络 | 1.减少请求大小和次数;2.减少DNS查找,避免重定向;3.是异步请求可缓存;4.预加载、延迟加载、按需加载;5.减少Dom数量等; |
服务 | 1.使用CDN;2.Gzip组件压缩;3.配置Etag;4.尽早刷新Buffer等; |
缓存 | 1.减小Cookie;2.CDN缓存; |
CSS/JavaScript | 1.Css放上面,Js放下面,避免阻塞;2.压缩Css、Js;3.减少Dom访问操作;4.减少重绘,避免回流; |
图片 | 1.压缩图片;2.用iconfont;3.用雪碧图; |
其它 | 1.控制组件大小;2.使用预编译语言,打包成模块,按需加载; |
参考链接:
前端安全
简答:
xss: 跨站脚本攻击(Cross Site Scripting)是最常见和基本的攻击 WEB 网站方法,攻击者通过注入非法的 html 标签或者 javascript 代码,从而当用户浏览该网页时,控制用户浏览器。
csrf:跨站点请求伪造(Cross-Site Request Forgeries),也被称为 one-click attack 或者 session riding。冒充用户发起请求(在用户不知情的情况下), 完成一些违背用户意愿的事情(如修改用户信息,删初评论等)。
防范:同源检测、双重cookie检测等。
Css布局
布局方式
简答:
名称 | 内容 |
静态布局(static layout) | 不管浏览器尺寸具体是多少,网页布局始终按照最初写代码时的布局来显示。 |
流式布局(Liquid Layout) | 栅栏系统(网格系统):代表:bootstrap |
自适应布局(Adaptive Layout) | 屏幕分辨率变化时,页面里面元素的位置会变化而大小不会变化。 |
响应式布局(Responsive Layout) | 每个屏幕分辨率下面会有一个布局样式,即元素位置和大小都会变。 |
弹性布局(rem/em布局) | rem/em区别:rem是相对于html元素的font-size大小而言的,而em是相对于其父元素。 |
进一步: rem与px的转换
假设设计稿宽度为750px,查看750px宽度的页面对应的html{font-size:XXXpx}.
假设页面宽750px,html{font-size:100px},即100px=1rem。此时想要设置一个按钮的宽度,在设计稿中按钮为200px90px,那么转换之后的按钮即为2rem.9rem
html{//750的屏幕 font-size=10px; /*font-size=62.5% //这里就是10/16x100%=62.5% 也就是默认10px的字号*/ } @media screen and (min-width: 640px){ html{ font-size: ?; } } 问号里的值是多少? 解: 750/640=10/x 复制代码
布局实例
需求: 只用css实现,一个div分上下两部分,上部分高度不固定,下面部分自动填满剩余高度
方法一:用flex 布局
.wrapper{ display:flex; flex-direction: column; //竖轴方向 } .body{ flex:auto; //自动铺满剩余空间 }
方法二:用绝对定位,然后在dom中增加一块高度占位的盒子
节流防抖
推荐阅读:
算法
手写二分法
要求手写!
function binary_search(arr,target) { let min=0 let max=arr.length-1 while(min<=max){ let mid=Math.ceil((min+max)/2) if(arr[mid]==target){ return mid }else if(arr[mid]>target){ max=mid-1 }else if(arr[mid]<target){ min=mid+1 } } return "null" } console.log(binary_search([1,5,7,19,88],19))//3
冒泡排序
var arr=[10,20,50,100,40,200]; for(var i=0;i<arr.length-1;i++){ for(var j=0;j<arr.length-1-i;j++){ if(arr[j]>arr[j+1]){ var temp=arr[j] arr[j]=arr[j+1] arr[j+1]=temp } } } console.log(arr)
去重
1.不考虑Set()
2.不考虑双层for循环,性能太差
利用对象的属性不重复:
function distinct(arr) { let result = [] let obj = {} for (let i of arr) { if (!obj[i]) { result.push(i) obj[i] = 1 } } return result }