盒模型
盒模型的组成大家肯定都懂,由里向外content,padding,border,margin.
盒模型是有两种标准的,一个是标准模型,一个是IE模型。
- 在标准模型中,盒模型的宽高 = 内容(content)的宽高,
- IE模型中盒模型的宽高 = 内容(content)+填充(padding)+边框(border)的总宽高
- css如何设置两种模型:
/* 标准模型 */ box-sizing:content-box; /*IE模型*/ box-sizing:border-box;
- js获取宽高
dom.offsetWidth/offsetHeight //最常用的,也是兼容最好的
- 边距重叠
边距重叠解决方案BFC(块级格式化上下文)
//原理
- 内部的box会在垂直方向,一个接一个的放置
- 每个元素的margin box的左边,与包含块border box的左边相接触(对于从左往右的格式化,否则相反)
- box垂直方向的距离由margin决定,属于同一个bfc的两个相邻box的margin会发生重叠
- bfc的区域不会与浮动区域的box重叠
- bfc是一个页面上的独立的容器,外面的元素不会影响bfc里的元素,反过来,里面的也不会影响外面的
- 计算bfc高度的时候,浮动元素也会参与计算
- 创建BFC
- float属性不为none(脱离文档流)
- position为absolute或fixed
- display为inline-block,table-cell,table-caption,flex,inine-flex
- overflow不为visible
- 根元素
- 应用场景
- 自适应两栏布局
- 清除内部浮动
- 防止垂直margin重叠
清除浮动
.clearfloat:after{display:block;clear:both;content:"";visibility:hidden;height:0} .clearfloat{zoom:1}//zoom(IE转有属性)可解决ie6,ie7浮动问题
.clearfloat{clear:both}//添加一个空div,利用css提高的clear:both清除浮动,让父级div能自动获取到高度
父级div手动定义height,就解决了父级div无法自动获取到高度的问题
必须定义width或zoom:1,同时不能定义height,使用overflow:hidden时,浏览器会自动检查浮动区域的高度
必须定义width或zoom:1,同时不能定义height,使用overflow:auto时,浏览器会自动检查浮动区域的高度
所有代码一起浮动,就变成了一个整体,会产生新的浮动问题。
Position
https://segmentfault.com/a/1190000013683068
inline-block中间会有空隙
内联块元素具有了内联元素以及块级元素的特性:(1)元素之间可以水平排列 (2)可以当做一个块级元素来设置各种的属性,例如:width、height、padding等
间隙是由换行或者回车导致的。只要把标签写成一行或者标签直接没有空格,就不会出现间隙。但是这种方式是不太可靠。在父容器上使用font-size:0;可以消除间隙(把空格隐藏/去除),对于Chrome, 其默认有最小字体大小限制,考虑到兼容性,需要取消字体大小限制。
.demo {font-size: 0;-webkit-text-size-adjust:none;}
层叠优先级
浏览器默认的样式 < 网页制作者样式 < 用户自己设置的样式<!important
按照权重取最大(取权重最大值显示)去确定最后样式:
!importrant >内联>ID派生选择器(#id h1)> id(100)> class(10)>标签(1)>继承(0.5)
怎样覆盖 !important
很简单,只需再添加一条 带 !important
的CSS规则,再给这个给选择器更高的优先级(添加一个标签,ID或类);或是添加一样选择器,把它的位置放在原有声明的后面,总之,最后定义一条规则比胜)。
或者使用相同的选择器,但是置于已有的样式之后;
或干脆改写原来的规则,以避免使用 !important
。
HTTP:地址栏输入url到显示页面的步骤
基本流程:
a. 域名解析
b. 发起TCP的3次握手(TCP连接理论上不会自动断开)
c. 建立TCP连接后发起http请求
d. 服务器端响应http请求,浏览器得到html代码
e. 浏览器解析html代码,并请求html代码中的资源
f. 浏览器对页面进行渲染呈现给用户
- 在浏览器地址栏输入URL
- 浏览器查看缓存,如果请求资源在缓存中并且新鲜,跳转到转码步骤
- 如果资源未缓存,发起新请求
- 如果已缓存,检验是否足够新鲜,足够新鲜直接提供给客户端,否则与服务器进行验证。
- 检验新鲜通常有两个HTTP头进行控制Expires和Cache-Control:
- HTTP1.0提供Expires,值为一个绝对时间表示缓存新鲜日期
- HTTP1.1增加了Cache-Control: max-age=,值为以秒为单位的最大新鲜时间
- 浏览器解析URL获取协议,主机,端口,path
- 浏览器组装一个HTTP(GET)请求报文
- 浏览器获取主机ip地址,过程如下:
- 浏览器缓存
- 本机缓存
- hosts文件
- 路由器缓存
- ISP DNS缓存
- DNS递归查询(可能存在负载均衡导致每次IP不一样)
- 端口建立TCP链接,三次握手
- TCP链接建立后发送HTTP请求
- 服务器接受请求并解析,将请求转发到服务程序,如虚拟主机使用HTTP Host头部判断请求的服务程序
- 服务器检查HTTP请求头是否包含缓存验证信息如果验证缓存新鲜,返回304等对应状态码
- 处理程序读取完整请求并准备HTTP响应,可能需要查询数据库等操作
- 服务器将响应报文通过TCP连接发送回浏览器
- 浏览器接收HTTP响应,然后根据情况选择**关闭TCP连接或者保留重用,关闭TCP连接的四次握手
- 浏览器检查响应状态吗:是否为1XX,3XX, 4XX, 5XX,这些情况处理与2XX不同
- 如果资源可缓存,进行缓存
- 对响应进行解码(例如gzip压缩)
- 根据资源类型决定如何处理(假设资源为HTML文档)
- 解析HTML文档,构件DOM树,下载资源,构造CSSOM树,执行js脚本,这些操作没有严格的先后顺序,以下分别解释
- 构建DOM树:
- 解析过程中遇到图片、样式表、js文件,启动下载
- 构建CSSOM树:
- 根据DOM树和CSSOM树构建渲染树
- js解析
- 显示页面
数据类型
- 基本类型:数字(number)、字符串(string)、布尔值(boolean)、null、undefined、Symbol
- 引用(对象)类型:function、array、object 对象是可变的,即值是可以修改的;对象的比较并非值得比较
- undefined表示系统级的、出乎意料的或类似错误的值的空缺;表示缺少值,此处应该有值,但没有定义
- null表示程序级的、正常的或在意料之中的值的空缺; 一般多使用null。
null表示没有对象,即该处不应该有值
1) 作为函数的参数,表示该函数的参数不是对象
2) 作为对象原型链的终点
undefined表示缺少值,即此处应该有值,但没有定义
1)定义了形参,没有传实参,显示undefined
2)对象属性名不存在时,显示undefined
3)函数没有写返回值,即没有写return,拿到的是undefined
4)写了return,但没有赋值,拿到的是undefined
null和undefined转换成number数据类型
null 默认转成 0
undefined 默认转成 NaN
typeof null // object (因为一些以前的原因而不是'null') typeof undefined // undefined null === undefined // false null == undefined // true null === null // true null == null // true !null //true isNaN(1 + null) // false isNaN(1 + undefined) // true
- Symbol:它的功能类似于一种标识唯一性的ID。通常情况下,我们可以通过调用
Symbol()
函数来创建一个Symbol实例:
let s1 = Symbol()
- 每个Symbol实例都是唯一的。因此,当你比较两个Symbol实例的时候,将总会返回
false
.应用场景:
- 使用Symbol来作为对象属性名(key)
注意:Symbol类型的key是不能通过Object.keys()
或者for...in
来枚举的,它未被包含在对象自身的属性名集合(property names)之中,所以,利用该特性,我们可以**把一些不需要对外操作和访问的属性使用Symbol来定义。**当使用JSON.stringify()
将对象转换成JSON字符串的时候,Symbol属性也会被排除在输出内容之外 - 使用Symbol来替代常量
const TYPE_AUDIO = Symbol() const TYPE_VIDEO = Symbol() const TYPE_IMAGE = Symbol()
- 使用Symbol定义类的私有属性/方法:私有化内部属性/方法
- 注册和获取全局Symbol
通常情况下,我们在一个浏览器窗口中(window),使用Symbol()
函数来定义和Symbol实例就足够了。但是,如果你的应用涉及到多个window(最典型的就是页面中使用了<iframe>
),并需要这些window中使用的某些Symbol是同一个,那就不能使用Symbol()
函数了,因为用它在不同window中创建的Symbol实例总是唯一的,而我们需要的是在所有这些window环境下保持一个共享的Symbol。这种情况下,我们就需要使用另一个API来创建或获取Symbol,那就是Symbol.for()
,它可以注册或获取一个window间全局的Symbol实例:
let gs1 = Symbol.for('global_symbol_1') //注册一个全局Symbol let gs2 = Symbol.for('global_symbol_1') //获取全局Symbol gs1 === gs2 // true
实现深复制的三种方法
//使用递归的方式实现数组、对象的深拷贝 function deepClone1(obj) { //判断拷贝的要进行深拷贝的是数组还是对象,是数组的话进行数组拷贝,对象的话进行对象拷贝 var objClone = Array.isArray(obj) ? [] : {}; //进行深拷贝的不能为空,并且是对象或者是 if (obj && typeof obj === "object") { for (key in obj) { if (obj.hasOwnProperty(key)) { if (obj[key] && typeof obj[key] === "object") { objClone[key] = deepClone1(obj[key]); } else { objClone[key] = obj[key]; } } } } return objClone; }
//通过js的内置对象JSON来进行数组对象的深拷贝 function deepClone2(obj) { var _obj = JSON.stringify(obj), objClone = JSON.parse(_obj); return objClone; }
var array = [1,2,3,4]; var newArray = $.extend(true,[],array);
lodash.cloneDeep()实现深拷贝
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
JQuery 获取ID元素与JS获取的区别
- KaTeX parse error: Expected 'EOF', got '#' at position 3: ("#̲id")获取的对象其实是一个数…(“#id”)[0],这样两个就相等了。
vue中组件通信方式
- 父组件向子组件传值:
父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed - 子组件向父组件传值: 通过事件形式$emit: 子组件通过events给父组件发送消息,实际上就是子组件把自己的数据发送到父组件
- 通过一个空的Vue实例作为中央事件总线(事件中心),用它来触发事件和监听事件,巧妙而轻量地实现了任何组件间的通信,包括父子、兄弟、跨级
- Vuex: Vuex实现了一个单向数据流,在全局拥有一个State存放数据,当组件要更改State中的数据时,必须通过Mutation进行,Mutation同时提供了订阅者模式供外部插件调用获取State数据的更新。而当所有异步操作(常见于调用后端接口异步获取更新数据)或批量的同步操作需要走Action,但Action也是无法直接修改State的,还是需要通过Mutation来修改State的数据。最后,根据State的变化,渲染到视图上。
vuex 是 vue 的状态管理器,存储的数据是响应式的。但是并不会保存起来,刷新之后就回到了初始状态,具体做法应该在vuex里数据改变的时候把数据拷贝一份保存到localStorage里面,刷新之后,如果localStorage里有保存的数据,取出来再替换store里的state。
总结
- 父子通信:
父向子传递数据是通过 props,子向父是通过 events**(
$emit
)**;通过父链 / 子链也可以通信($parent
/$children
);ref 也可以访问组件实例;provide / inject API;$attrs/$listeners
- 兄弟通信:Bus;Vuex
- 跨级通信:Bus;Vuex;provide / inject API、
$attrs/$listeners
同源策略
如果两个页面的协议,端口(如果有指定)和主机都相同,则两个页面具有相同的源。我们也可以把它称为“协议/主机/端口
跨域的解决方法
https://www.cnblogs.com/laixiangran/p/9064769.html
- CORS(跨域资源共享): 是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
- 简单请求:浏览器直接发出CORS请求,在头信息中添加一个Origin字段,用来说明请求来自哪个源,服务器根据这个值,决定是否同意这次请求。
- 如果服务器不许可,则返回的信息中不会包含Access-Control-Allow-Origin字段,这个错误需要onerror捕获,返回的状态码可能为200;
如果服务器许可,则服务器返回的响应中会多出Access-Control-字段;
CORS默认不发送cookie,需要发送cookies,则需要服务器指定Access-Control-Allow-Credentials字段,需要在ajax请求中打开withCredentials属性;
- 非简单请求/复杂请求:请求方法是PUT或DELETE,Content-Type字段类型是application/json。
- **会在正式通信前,增加一次OPTIONS查询请求,预检请求(目的就是为了判断实际发送的请求是否是安全的)****。**询问服务器,网页所在域名是否在服务器的许可名单中,以及可以使用那些HTTP动词和头信息字段,只有得到肯定答复,浏览器才会发出正式XMLHTTPRequest请求,否则会报错
服务器通过预检请求,以后每次浏览器正常CORS请求,都会和简单请求一样,会有一个Origin字段,服务器的回应也会有yieldAccess-Control-Allow-Origin头信息字段 - JSONP 跨域: 借助script标签能跨域的原理。流量器告诉服务端一个回调函数的名称,服务端在返回的script里面调用这个回调函数,同时传进客户端需要的数据,这个返回的代码就能在浏览器上执行了。
JSONP和CORS比较,缺点是支持是get类型。优点是兼容老版本浏览器。 - 图像 Ping 跨域
- 服务器代理
- document.domain =“父域”:子域跨父域
- window.name 跨域
- location.hash 跨域
- postMessage 跨域:父窗口向子iframe传消息
进程线程
- 进程:是执行中一段程序,即一旦程序被载入到内存中并准备执行,它就是一个进程。进程是表示资源分配的的基本概念,又是调度运行的基本单位,是系统中的并发执行的单位。
- 线程:单个进程中执行中每个任务就是一个线程。
- 一个线程只能属于一个进程,但是一个进程可以拥有多个线程。多线程处理就是允许一个进程中在同一时刻执行多个任务
- 线程没有地址空间,线程包含在进程的地址空间中
- 父和子进程使用进程间通信机制
- 进程内的任何线程都被看做是同位体,且处于相同的级别。不管是哪个线程创建了哪一个线程,进程内的任何线程都可以销毁、挂起、恢复和更改其它线程的优先权。
- 子进程不对任何其他子进程施加控制,进程的线程可以对同一进程的其它线程施加控制。
状态码
HTTP状态码共分为5种类型:
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
常见的HTTP状态码:
- 200 - 请求成功
- 301 - 资源(网页等)被永久转移到其它URL
- 302- 资源只是临时被移动。客户端应继续使用原有URI
- 304- 未修改。所请求的资源未修改,服务器返回此状态码时,不会返回任何资源。
- 404 - 请求的资源(网页等)不存在
- 500 - 内部服务器错误
- 502- 作为网关或者代理工作的服务器尝试执行请求时,从远程服务器接收到了一个无效的响应
前端缓存
cookie是浏览器提供的一种机制,它将document 对象的cookie属性提供给JavaScript。可以由JavaScript对其进行控制,而并不是JavaScript本身的性质。cookie是存于用户硬盘的一个文件,这个文件通常对应于一个域名,当浏览器再次访问这个域名时,便使这个cookie可用。
cookie的缺点主要集中于安全性和隐私保护。
localStorage中一般浏览器支持的是5M大小,这个在不同的浏览器中localStorage会有所不同
localStorage会可以将第一次请求的数据直接存储到本地,这个相当于一个5M大小的针对于前端页面的数据库,相比于cookie可以节约带宽
localStorage本质上是对字符串的读取,如果存储内容多的话会消耗内存空间,会导致页面变卡
localStorage与sessionStorage的唯一一点区别就是localStorage属于永久性存储,而sessionStorage属于当会话结束的时候,sessionStorage中的键值对会被清空
sessionStorage用于本地存储一个会话(session)中的数据,这些数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁。因此sessionStorage不是一种持久化的本地存储,仅仅是会话级别的存储。
白屏之前的步骤优化
发生的原因基本可以归结为网速&静态资源
1、css文件加载需要一些时间,在加载的过程中页面是空白的。 解决:可以考虑将css代码前置和内联。
2、首屏无实际的数据内容,等待异步加载数据再渲染页面导致白屏。 解决:在首屏直接同步渲染html,后续的滚屏等再采用异步请求数据和渲染html。
3、首屏内联js的执行会阻塞页面的渲染。 解决:尽量不在首屏html代码中放置内联脚本。
根本原因是客户端渲染的无力,因此最简单的方法是在服务器端,使用模板引擎渲染所有页面。同时:
1减少文件加载体积,如html压缩,js压缩
2加快js执行速度 比如常见的无限滚动的页面,可以使用js先渲染一个屏幕范围内的东西
3提供一些友好的交互,比如提供一些假的滚动条
4使用本地存储处理静态文件。
vue首屏性能优化,解决页面加载时间过长(白屏)方法
import ShowBlogs from '@/components/ShowBlogs' routes:[ path: 'Blogs', name: 'ShowBlogs', component: ShowBlogs ]
- 改为:
routes:[ path: 'Blogs', name: 'ShowBlogs', component: () => import('./components/ShowBlogs.vue') ]
- 如果是在 vuecli 3中,我们还需要多做一步工作
因为 vuecli 3默认开启 prefetch(预先加载模块),提前获取用户未来可能会访问的内容
在首屏会把这十几个路由文件,都一口气下载了
所以我们要关闭这个功能,在 vue.config.js中设置: - ui框架按需加载
在 .babelrc / babel.config.js文件中添加( vue-cli 3要先安装 babel-plugin-component):
plugins: [ [ "component", { "libraryName": "element-ui", "styleLibraryName": "theme-chalk" } ] ]
cnpm i compression-webpack-plugin -D
在 vue.congig.js中引入并修改 webpack配置:
const CompressionPlugin = require('compression-webpack-plugin') configureWebpack: (config) => { if (process.env.NODE_ENV === 'production') { // 为生产环境修改配置... config.mode = 'production' return { plugins: [new CompressionPlugin({ test: /\.js$|\.html$|\.css/, //匹配文件名 threshold: 10240, //对超过10k的数据进行压缩 deleteOriginalAssets: false //是否删除原文件 })] } }
在服务器我们也要做相应的配置
如果发送请求的浏览器支持 gzip,就发送给它 gzip格式的文件。
https://segmentfault.com/a/1190000020383064
https://segmentfault.com/a/1190000019499007
Vue 响应式原理
数据劫持
数据劫持: vue.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
vue中通过observe
方法实现所有的数据属性的劫持.
- vue在实例化的时候会将data数据中的属性都做数据劫持。
- 如果是对象,也会迭代本身属性将全部属性都实现数据劫持
- 当赋值的时候,如果是
newVal
是对象,也会去迭代newVal
的属性实现全部属性的数据劫持
Array对象
是没有办法通过上述方法实现数据劫持的:
vue中实现的方法实际是对数组的属性重写,重写过后的方法不仅能实现原有的功能,还能发布消息给订阅者。
如果要更新 Array
某个索引对应的值得时候,要用Vue.set方式实现
Vue.set是对数据进行拦截,实际就是数据劫持处理,并发布一次消息
手写bind
//context为需要被绑定上的对象,arguments是参数 Function.prototype.bind = function(context){ var self = this; //this => Function return function(){ return self.apply(context,arguments) } }
http与https区别
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
HTTPS 连接过程
服务器发送它的证书给浏览器,浏览器确认证书正确,并检查证书中对应的主机名是否正确,如果正确则双方加密数据后发给对方,对方再进行加密,保证数据是不透明的。
非对称加密算法:加密用密钥,解密用公钥,公钥是公开的,密钥是不会传播的。常见的算法如:RSA。
SSL原理
es6之扩展/剩余运算符 三个点(…)
- 对象中的扩展运算符(…)用于取出参数对象中的所有可遍历属性,拷贝到当前对象之中
前端跨脚本攻击攻击xss
XSS也称为跨脚本攻击,是一种恶意脚本,可以获取用户得cookie、token、session.
分为存储性(持久型)、反射型(非持久型)、基于DOM
- 尽量少使用
appenChid
、innerHTML
、outerHTML
等标签,而使用innerText
、textContent
、setAttribute
- 前端过滤:url: 可以使用
encodeURIComponent
进行转义 - 通过 Content-Security-PolicyHTTP头来开启CSP:
- 通过JavaScript的 Document.cookie API无法访问带有 HttpOnly 标记的Cookie,它们只应该发送给服务端。如果 Cookie 不想被客户端 JavaScript 脚本调用,那么就应该为其设置 HttpOnly 标记。
CSRF跨站请求伪造
CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器.
由于同源策略,跨域的Ajax请求不会带上Cookie,然而script/iframe/img等标签却是支持跨域的。所以在请求的时候是会带上cookie的。
- Get 请求不对数据进行修改/写
- 不让第三方网站访问到用户Cookie
- 阻止第三方网站请求接口
- 请求时附带验证信息,如验证码或Token,可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token。
- XSS是利用用户对指定网站的信任
- CSRF是利用网站对用户的信任
call apply bind区别
- call、apply、bind的作用是改变函数运行时this的指向
- call 方法第一个参数是要绑定给this的值,后面传入的是一个参数列表。当第一个参数为null、undefined的时候,默认指向window。
- apply接受两个参数,第一个参数是要绑定给this的值,第二个参数是一个参数数组。当第一个参数为null、undefined的时候,默认指向window。
- bind和call很相似,第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用。bind返回对应函数, 便于稍后调用; apply, call则是立即调用。
- 箭头函数体内的 this 对象, 就是定义时所在的对象, 而不是使用时所在的对象
++1 和i++哪个效率高
++i的效率高些,++i在运算过程中不产生临时对象,返回的就是i,是个左值,类似++i=1这样的表达式是合法的,而i++在运算的过程中会产生临时对象,返回的是零时对象的值,是个右值,像i++=1这样的表达式是非法的.
对于内置类型,单独的i++和++i语句,现在的编译器基本上都会优化成++i,所以就没什么区别了
webpack热更新 HMR
为 Webpack 开发环境开启热更新,要做两件事:
- 使用
HotModuleReplacementPlugin
插件 - 打开
webpack-dev-server
的热更新开关
每次 compiler 的 ‘done’ 钩子函数被调用的时候就会要求客户端去检查模块更新,如果客户端不支持 HMR,那么就会全局加载。通过 webpack-dev-server 提供的 websocket 服务端代码通知 websocket 客户端发送的 ok 和 warning 信息的时候会要求更新。如果支持 HMR 的情况下就会要求检查更新,同时发送过来的还有服务器端本次编译的 compilation 的 hash 值。如果不支持 HMR,那么要求刷新页面。如果 ok 则调用reloadApp方法,而 reloadApp 方法 判断如果开启了 HMR 模式, 通过hotEmitter 执行webpackHotUpdate方法,如果不是 Hotupdate 那么直接 reload刷新网页。所以"webpack/hot/only-dev-server"的文件内容就是检查哪些模块更新了(通过 webpackHotUpdate 事件完成,而该事件依赖于compilation的 hash 值),其中哪些模块更新成功,而哪些模块由于某种原因没有更新成功。
sass less
事件流,冒泡捕获
从页面中接收事件的顺序称为事件流.
IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
Netscape Communicator团队提出的另一种事件流叫做事件捕获(event capturing)。事件捕获是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预期目标之前捕获它。
“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。
首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出响应。
先捕获,后冒泡
事件流比较典型应用是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理一类型的所有事件。
强缓存,协商缓存
- 强缓存:强缓存是利用http的返回头中的
Expires
或者Cache-Control
两个字段来控制的,用来表示资源的缓存时间。
Cache-Control与Expires可以在服务端配置同时启用,同时启用的时候Cache-Control优先级高。 - 协商缓存:协商缓存就是由服务器来确定缓存资源是否可用,所以客户端与服务器端要通过某种标识来进行通信,从而让服务器判断请求资源是否可以缓存访问。
这主要涉及到下面两组header字段,这两组搭档都是成对
出现的,即第一次请求的响应头带上某个字段**(Last-Modified
或者Etag
)**,则后续请求则会带上对应的请求字段(If-Modified-Since
或者If-None-Match
),若响应头没有Last-Modified或者Etag字段,则请求头也不会有对应的字段。Etag/If-None-Match返回的是一个校验码。ETag可以保证每一个资源是唯一的,资源变化都会导致ETag变化。与Last-Modified不一样的是,当服务器返回304 Not Modified的响应时,由于ETag重新生成过,response header中还会把这个ETag返回,即使这个ETag跟之前的没有变化。
装饰者模式
装饰模式指的是在不必改变原类文件和使用继承的情况下,**动态地扩展一个对象的功能。**它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
适用场景:当遇到新的功能或需求需要对原来的操作做出更改时,若原来的操作比较复杂,可以把原来的操作原封不动地放在装饰者中,然后再添加新功能。
function Person() { } Person.prototype.sayHello = function() { console.log('Hello, Alice!'); }; function Decorator(param) { this.person = param; } Decorator.prototype.sayHello = function() { this.person.sayHello(); console.log('Hello, Bruce!'); }; new Decorator(new Person()).sayHello();
WebView调用Android本地组件
webview有两个方法:setWebChromeClient 和 setWebClient
setWebClient:主要处理解析,渲染网页等浏览器做的事情
setWebChromeClient:辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等
WebViewClient就是帮助WebView处理各种通知、请求事件的。
响应式布局
普通函数和箭头函数区别
- 箭头函数相当于匿名函数,并且简化了函数定义。箭头函数是匿名函数,不能作为构造函数,不能使用new
- 箭头函数不绑定arguments,取而代之用rest参数…解决
- 箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值
- 箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响。
- 箭头函数没有原型属性
- 箭头函数不能当做Generator函数,不能使用yield关键字
箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
普通函数的this指向调用它的那个对象
原型与原型链
原型prototype
每个函数都有一个 prototype 属性,每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。
- proto:每一个JavaScript对象(除了 null )都具有的一个属性,叫proto,这个属性会指向该对象的原型。
- constructor:每个原型都有一个 constructor 属性指向关联的构造函数,实例原型指向构造函数
使用原型的好处就是,可以让所有对象实例共享它包含的属性和方法。即不用在构造函数中定义对象实例的属性和方法,而是直接把这些信息添加到原型对象上面。
使用hasOwnProperty()方法可以检查一个属性是存在于实例中,还是存在原型中?只在给定属性存在于对象实例中时,才会返回true。
原型链
JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。
MVVM
Model–View–ViewModel(MVVM) 是一个软件架构设计模式,由微软 WPF 和 Silverlight 的架构师 Ken Cooper 和 Ted Peters 开发。MVVM 源自于经典的 Model–View–Controller(MVC)模式,MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。
iframe优缺点
- 优点
1.iframe能够原封不动的把嵌入的网页展现出来。
2.如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决 - 缺点
很多的移动设备(PDA 手机)无法完全显示框架,设备兼容性差。
iframe框架页面会增加服务器的http请求,对于大型网站是不可取的
JS数组slice()和splice()的区别
- **slice()定义:从已有的数组中返回你选择的某段数组元素;:**start可以为负数,此时它规定从数组尾部开始算起的位置。也就是-1 ,指最后一个元素,
- slice()方法不会修改数组本身,而是返回所选取范围的数组元素
- 如果想删除数组中的某一个元素,需要使用splice()。splice()定义:从数组中添加或删除元素,然后返回被删除的数组元素。splice()方法会改变原始数组
- splice()语法:arrayObject.splice(index,howmany,item1,…,itemX).howmany表示删除的元素数量,如果为0,则表示不删除数组元素
defineproperty 与 proxy的区别
- Object.defineProperty() 无法监控到数组下标的变化
- proxy可以劫持整个对象,并返回一个新对象,有13种劫持操作,Proxy是es6提供的,兼容性不好,无法用polyfill磨平
- proxy在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写,我们可以这样认为,Proxy是
Object.defineProperty
的全方位加强版.
懒加载和预加载
- 懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式
- 懒加载原理:首先将页面上的图片的 src 属性设为空字符串,而图片的真实路径则设置在data-original属性中,
当页面滚动的时候需要去监听scroll事件,在scroll事件的回调中,判断我们的懒加载的图片是否进入可视区域,如果图片在可视区内将图片的 src 属性设置为data-original 的值,这样就可以实现延迟加载。 - 预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。
两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。