⭐️ 本文首发自 前端修罗场(点击加入),是
一个由 资深开发者 独立运行 的专业技术社区
,我专注Web 技术、Web3、区块链、答疑解惑、面试辅导以及职业发展
。博主创作的 《前端面试复习笔记》(点击订阅),广受好评,已帮助多人提升实力、拿到 offer。现在订阅,私聊我即可获取一次免费的模拟面试机会
,帮你评估知识点的掌握程度,获得更全面的学习指导意见!
盒模型的组成大家肯定都懂,由里向外content,padding,border,margin.
盒模型是有两种标准的,一个是标准模型,一个是IE模型。
在标准模型中,盒模型的宽高 = 内容(content)的宽高,
IE模型中盒模型的宽高 = 内容(content)+填充(padding)+边框(border)的总宽高
css如何设置两种模型:
/* 标准模型 */
box-sizing:content-box;
/*IE模型*/
box-sizing:border-box;
js获取宽高
dom.offsetWidth/offsetHeight //最常用的,也是兼容最好的
边距重叠
//原理
.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时,浏览器会自动检查浮动区域的高度
所有代码一起浮动,就变成了一个整体,会产生新的浮动问题。
https://segmentfault.com/a/1190000013683068
内联块元素具有了内联元素以及块级元素的特性:(1)元素之间可以水平排列 (2)可以当做一个块级元素来设置各种的属性,例如:width、height、padding等
间隙是由换行或者回车导致的。只要把标签写成一行或者标签直接没有空格,就不会出现间隙。但是这种方式是不太可靠。在父容器上使用font-size:0;可以消除间隙(把空格隐藏/去除),对于Chrome, 其默认有最小字体大小限制,考虑到兼容性,需要取消字体大小限制。
.demo {font-size: 0;-webkit-text-size-adjust:none;}
浏览器默认的样式 < 网页制作者样式 < 用户自己设置的样式
按照权重取最大(取权重最大值显示)去确定最后样式:
!importrant >内联>ID派生选择器(#id h1)> id(100)> class(10)>标签(1)>继承(0.5)
!important
很简单,只需再添加一条 带 !important
的CSS规则,再给这个给选择器更高的优先级(添加一个标签,ID或类);或是添加一样选择器,把它的位置放在原有声明的后面,总之,最后定义一条规则比胜)。
或者使用相同的选择器,但是置于已有的样式之后;
或干脆改写原来的规则,以避免使用 !important
。
a. 域名解析
b. 发起TCP的3次握手(TCP连接理论上不会自动断开)
c. 建立TCP连接后发起http请求
d. 服务器端响应http请求,浏览器得到html代码
e. 浏览器解析html代码,并请求html代码中的资源
f. 浏览器对页面进行渲染呈现给用户
基本类型:数字(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是不能通过Object.keys()
或者for...in
来枚举的,它未被包含在对象自身的属性名集合(property names)之中,所以,利用该特性,我们可以**把一些不需要对外操作和访问的属性使用Symbol来定义。**当使用JSON.stringify()
将对象转换成JSON字符串的时候,Symbol属性也会被排除在输出内容之外
const TYPE_AUDIO = Symbol()
const TYPE_VIDEO = Symbol()
const TYPE_IMAGE = Symbol()
通常情况下,我们在一个浏览器窗口中(window),使用Symbol()
函数来定义和Symbol实例就足够了。但是,如果你的应用涉及到多个window(最典型的就是页面中使用了),并需要这些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()实现深拷贝
当对象中只有一级属性,没有二级属性的时候,此方法为深拷贝,但是对象中有对象的时候,此方法,在二级属性以后就是浅拷贝。
父组件通过props向下传递数据给子组件。注:组件中的数据共有三种形式:data、props、computed
通过一个空的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
如果两个页面的协议,端口(如果有指定)和主机都相同,则两个页面具有相同的源。我们也可以把它称为“协议/主机/端口
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
如果服务器不许可,则返回的信息中不会包含Access-Control-Allow-Origin字段,这个错误需要onerror捕获,返回的状态码可能为200;
如果服务器许可,则服务器返回的响应中会多出Access-Control-字段;
CORS默认不发送cookie,需要发送cookies,则需要服务器指定Access-Control-Allow-Credentials字段,需要在ajax请求中打开withCredentials属性;
**会在正式通信前,增加一次OPTIONS查询请求,预检请求(目的就是为了判断实际发送的请求是否是安全的)****。**询问服务器,网页所在域名是否在服务器的许可名单中,以及可以使用那些HTTP动词和头信息字段,只有得到肯定答复,浏览器才会发出正式XMLHTTPRequest请求,否则会报错
服务器通过预检请求,以后每次浏览器正常CORS请求,都会和简单请求一样,会有一个Origin字段,服务器的回应也会有yieldAccess-Control-Allow-Origin头信息字段
JSONP和CORS比较,缺点是支持是get类型。优点是兼容老版本浏览器。
HTTP状态码共分为5种类型:
1** | 信息,服务器收到请求,需要请求者继续执行操作 |
---|---|
2** | 成功,操作被成功接收并处理 |
3** | 重定向,需要进一步的操作以完成请求 |
4** | 客户端错误,请求包含语法错误或无法完成请求 |
5** | 服务器错误,服务器在处理请求的过程中发生了错误 |
常见的HTTP状态码:
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使用本地存储处理静态文件。
在 router.js文件中,原来的静态引用方式,如:
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中设置:
在 .babelrc / babel.config.js文件中添加( vue-cli 3要先安装 babel-plugin-component):
plugins: [
[
"component",
{
"libraryName": "element-ui",
"styleLibraryName": "theme-chalk"
}
]
]
安装 compression-webpack-plugin
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.js 则是采用数据劫持结合发布者-订阅者模式的方式,通过Object.defineProperty()来劫持各个属性的setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调。Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象。
vue中通过observe
方法实现所有的数据属性的劫持.
newVal
是对象,也会去迭代newVal
的属性实现全部属性的数据劫持Array对象
是没有办法通过上述方法实现数据劫持的:
vue中实现的方法实际是对数组的属性重写,重写过后的方法不仅能实现原有的功能,还能发布消息给订阅者。
如果要更新 Array
某个索引对应的值得时候,要用Vue.set方式实现
Vue.set是对数据进行拦截,实际就是数据劫持处理,并发布一次消息
//context为需要被绑定上的对象,arguments是参数
Function.prototype.bind = function(context){
var self = this; //this => Function
return function(){
return self.apply(context,arguments)
}
}
服务器发送它的证书给浏览器,浏览器确认证书正确,并检查证书中对应的主机名是否正确,如果正确则双方加密数据后发给对方,对方再进行加密,保证数据是不透明的。
非对称加密算法:加密用密钥,解密用公钥,公钥是公开的,密钥是不会传播的。常见的算法如:RSA。
XSS也称为跨脚本攻击,是一种恶意脚本,可以获取用户得cookie、token、session.
分为存储性(持久型)、反射型(非持久型)、基于DOM
appenChid
、innerHTML
、outerHTML
等标签,而使用innerText
、textContent
、setAttribute
encodeURIComponent
进行转义CSRF 攻击是攻击者借助受害者的 Cookie 骗取服务器的信任,可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击服务器.
由于同源策略,跨域的Ajax请求不会带上Cookie,然而script/iframe/img等标签却是支持跨域的。所以在请求的时候是会带上cookie的。
Get 请求不对数据进行修改/写
不让第三方网站访问到用户Cookie
阻止第三方网站请求接口
请求时附带验证信息,如验证码或Token,可以在 HTTP 请求中以参数的形式加入一个随机产生的 token,并在服务器端建立一个拦截器来验证这个 token。
XSS是利用用户对指定网站的信任
CSRF是利用网站对用户的信任
++i的效率高些,++i在运算过程中不产生临时对象,返回的就是i,是个左值,类似++i=1这样的表达式是合法的,而i++在运算的过程中会产生临时对象,返回的是零时对象的值,是个右值,像i++=1这样的表达式是非法的.
对于内置类型,单独的i++和++i语句,现在的编译器基本上都会优化成++i,所以就没什么区别了
为 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 值),其中哪些模块更新成功,而哪些模块由于某种原因没有更新成功。
从页面中接收事件的顺序称为事件流.
IE的事件流叫做事件冒泡(event bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。
Netscape Communicator团队提出的另一种事件流叫做事件捕获(event capturing)。事件捕获是不太具体的节点应该更早接收到事件,而最具体的节点应该最后接收到事件。事件捕获的用意在于在事件到达预期目标之前捕获它。
“DOM2级事件”规定的事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。
首先发生的是事件捕获,为截获事件提供了机会。然后是实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件作出响应。
先捕获,后冒泡
事件流比较典型应用是事件委托。事件委托利用了事件冒泡,只指定一个事件处理程序,就可以管理一类型的所有事件。
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有两个方法:setWebChromeClient 和 setWebClient
setWebClient:主要处理解析,渲染网页等浏览器做的事情
setWebChromeClient:辅助WebView处理Javascript的对话框,网站图标,网站title,加载进度等
WebViewClient就是帮助WebView处理各种通知、请求事件的。
箭头函数相当于匿名函数,并且简化了函数定义。箭头函数是匿名函数,不能作为构造函数,不能使用new
箭头函数的 this 永远指向其上下文的 this ,任何方法都改变不了其指向,如 call() , bind() , apply()
普通函数的this指向调用它的那个对象
每个函数都有一个 prototype 属性,每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。
proto:每一个JavaScript对象(除了 null )都具有的一个属性,叫proto,这个属性会指向该对象的原型。
constructor:每个原型都有一个 constructor 属性指向关联的构造函数,实例原型指向构造函数
使用原型的好处就是,可以让所有对象实例共享它包含的属性和方法。即不用在构造函数中定义对象实例的属性和方法,而是直接把这些信息添加到原型对象上面。
使用hasOwnProperty()方法可以检查一个属性是存在于实例中,还是存在原型中?只在给定属性存在于对象实例中时,才会返回true。
JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些。
Model–View–ViewModel(MVVM) 是一个软件架构设计模式,由微软 WPF 和 Silverlight 的架构师 Ken Cooper 和 Ted Peters 开发。MVVM 源自于经典的 Model–View–Controller(MVC)模式,MVVM 的核心是 ViewModel 层,它就像是一个中转站(value converter),负责转换 Model 中的数据对象来让数据变得更容易管理和使用,该层向上与视图层进行双向数据绑定,向下与 Model 层通过接口请求进行数据交互,起呈上启下作用。
优点
1.iframe能够原封不动的把嵌入的网页展现出来。
2.如果遇到加载缓慢的第三方内容如图标和广告,这些问题可以由iframe来解决
缺点
很多的移动设备(PDA 手机)无法完全显示框架,设备兼容性差。
iframe框架页面会增加服务器的http请求,对于大型网站是不可取的
Object.defineProperty
的全方位加强版.懒加载也叫延迟加载,指的是在长网页中延迟加载图像,是一种很好优化网页性能的方式
懒加载原理:首先将页面上的图片的 src 属性设为空字符串,而图片的真实路径则设置在data-original属性中,
当页面滚动的时候需要去监听scroll事件,在scroll事件的回调中,判断我们的懒加载的图片是否进入可视区域,如果图片在可视区内将图片的 src 属性设置为data-original 的值,这样就可以实现延迟加载。
预加载简单来说就是将所有所需的资源提前请求加载到本地,这样后面在需要用到时就直接从缓存取资源。
两者主要区别是一个是提前加载,一个是迟缓甚至不加载。懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。
在setInterval和setTimeout中传入函数时,函数中的this会指向window对象。
推荐用下面两种写法:
将bind换成call,apply也会导致立即执行,延迟效果会失效
window.setTimeout(this.declare.bind(this), 2000);
使用es6中的箭头函数,因为在箭头函数中this是固定的.箭头函数可以让setTimeout里面的this,绑定定义时所在的作用域
互联网媒体类型,在HTTP协议消息头中,使用Content-Type来表示请求和响应中的媒体类型信息。它用来告诉服务端如何处理请求的数据,以及告诉客户端(一般是浏览器)如何解析响应的数据,比如显示图片,解析并展示html等等。
HTTP会将请求参数用key1=val1&key2=val2的方式进行组织,并放到请求实体里面,注意如果是中文或特殊字符如"/“、”,“、“:” 等会自动进行URL转码。不支持文件,一般用于表单提交。
与application/x-www-form-urlencoded不同,这是一个多部分多媒体类型。首先生成了一个 boundary 用于分割不同的字段,在请求实体里每个参数以------boundary开始,然后是附加信息和参数名,然后是空行,最后是参数内容。多个参数将会有多个boundary块。如果参数是文件会有特别的文件域。最后以------boundary–为结束标识。multipart/form-data支持文件上传的格式,一般需要上传文件的表单则用该类型。
以“键-值”对的方式组织的数据。这个使用这个类型,需要参数本身就是json格式的数据,参数会被直接放到请求实体里,不进行任何处理。服务端/客户端会按json格式解析数据(约定好的情况下)。
与application/json类似,这里用的是xml格式的数据,text/xml的话,将忽略xml数据里的编码格式。
beforeEach
(前置守卫)和aftrEach
(后置钩子),一般用来判断权限,**以及以及页面丢失时候需要执行的操作beforeRouteEnter
和beforeRouteUpdate
,beforeRouteLeave
,这几个钩子是路由导航守卫,都是写在组件里面Vuex:可以理解为Vue的状态管理模式,它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
闭包可以理解为“定义在一个函数内部的函数”,本质上,闭包是将函数内部和外部连接起来的一座桥梁。
父函数内部定义的子函数,如果没有引用父函数作用域中的变量,那么这个子函数不是闭包。也就是说,闭包是由函数和它所在的环境构成的,缺一不可。
闭包会让函数中的变量都被保存在内存中,内存消耗大,所以不能滥用闭包,可以在不使用该变量的时候将其delete
1、主要用于异步计算
2、可以将异步操作队列化,按照期望的顺序执行,返回符合预期的结果
3、可以在对象之间传递和操作promise,帮助我们处理队列
在JavaScript的世界中,所有代码都是**单线程执行的。**由于这个“缺陷”,导致JavaScript的所有网络操作,浏览器事件,都必须是异步执行。异步执行可以用回调函数实现.异步操作会在将来的某个时间点触发一个函数调用.
避免 回调地域问题(嵌套层次深)。
promise是一个对象,对象和函数的区别就是对象可以保存状态,函数不可以(闭包除外)
Promise最大的好处是在异步执行的流程中,把执行代码和处理结果的代码清晰地分离了.
promise有三个状态:
1、pending[待定]初始状态
2、fulfilled[实现]操作成功
3、rejected[被否决]操作失败
Promise对象的状态改变,只有两种可能:
从pending变为fulfilled
从pending变为rejected。
这两种情况只要发生,状态就凝固了,不会再变了。
Promise还可以做更多的事情,比如,有若干个异步任务,需要先做任务1,如果成功后再做任务2,任何任务失败则不再继续并执行错误处理函数。
job1.then(job2).then(job3).catch(handleError);//其中,job1、job2和job3都是Promise对象。
Object构造函数
本身没有toString
方法。
依照原型链关系,Object构造函数
的上游原型链是Function.prototype
。调用Object.toString.call(param)
本质上是调用Function.prototype.toString.call(param)
,
原型链终端Object.prototype对象上的toString()确实可以被继承下来,可以用来判断数据类型, 但是并不能满足所有的需求,作为子代的包装类和数组就重写了自己的toString(), 因此当我们调用toString()时,会调用自身原型上重写的toString(),重写后的toString()可以把对象转换成字符串,还可以把number类型的数值转换成不同进制的数。当我们需要知道一个变量或值是什么类型的话就可以通/过调用Object.prototype.toString() 来实现 需要用到call().
var obj = {};
Object.toString(obj);//"function Object() { [native code] }"
Object.prototype.toString.call(obj);//"[object Object]"
为什么Array、String、Number、Boolean等不能直接调用toString()
因为Array、String、Number、Boolean、RegExp、Date等类型都重写了toString(),如果直接调用则因为自身的原型对象上已有toString()方法,就不会调用到Object原型对象上的toString()方法了。
播放时,设置其translateX
和transform
。
暂停时,把当前的位置写为translateX
,transform
为0,这个时候弹幕就保持在那个位置不动了。
再次播放时,重新设置translateX和transform,当然,transform-duration肯定是依据弹幕长度,当前位置和终点位置(播放器宽度)计算出来的。
播放和暂停的逻辑全都由js处理。
弹幕到位了以后,dom会被移除。
再加上will-change
的GPU加速
B站另外还做了一个操作就是复用dom,弹幕走到头以后不会移除,而是在有下一个新弹幕的时候把原来的dom节点复用,修改style,使其重新播放一次,这个也是性能提高的一个处理办法
https://blog.csdn.net/qq2712193/article/details/51725705
var str=[
{name:"a",age:50},
{name:"b",age:20},
{name:"c",age:40},
{name:"d",age:30},
];
function compare(key){
return function(value1,value2){
var val1=value1[key];
var val2=value2[key];
return val1-val2;
}
}
str.sort(compare('age'));
console.log(str);
通过html属性style实现
在style标签中写css样式,在body中引用
1.一般都使用这种方式,在桌面上新建一个css文件:test.css,内容为一个css样式
@import(url(demo.css))
1.基本不使用,因为页面会先加载html,然后再去加载css,这样就会造成页面样式的延迟。
递归
//使用递归实现深拷贝函数
function deepClone(obj) {
var objClone = Array.isArray(obj) ? [] : {}
if (obj && typeof obj === 'object') {
for (key in obj) {
if (obj.hasOwnProperty(key)) {
//判断obj的子元素是否为object对象,如果是则就递归拷贝
if (obj[key] && typeof obj[key] === 'object') {
objClone[key] = deepClone(obj[key])
} else {
//如果不为对象就直接拷贝
objClone[key] = obj[key]
}}}}
return objClone
}
obj1 = JSON.stringify(obj) + JSON.parse(obj1)
Jquery: $.extend(true,[],object)
第三方函数库 lodsh
不同:链表是链式的存储结构;数组是顺序的存储结构。
链表通过指针来连接元素与元素,数组则是把所有元素按次序依次存储。
链表的插入删除元素相对数组较为简单,不需要移动元素,且较为容易实现长度扩充,但是寻找某个元素较为困难;
数组寻找某个元素较为简单,但插入与删除比较复杂,由于最大长度需要再编程一开始时指定,故当达到最大长度时,扩充长度不如链表方便。
(1) 从逻辑结构角度来看
(2) 从内存存储角度来看
(静态)数组从栈中分配空间, 对于程序员方便快速,但自由度小。
链表从堆中分配空间, 自由度大但申请管理比较麻烦.
逐个复制元素
修改数组长度
function ArrayPush () {
var n = TO_UNIT32(this.length);
var m = %_ArgumentsLength();
for (var i = 0; i < m; i++) { // 逐个复制元素
this[i + n ] = %_Arguments(i);
}
this.length = n + m; // 修改数组的length
return this.length;
}
public static void findSumNum(int[] a,int sum){
Arrays.sort(a);
int i=0,j=a.length-1;
while(i<=j){
if(a[i]+a[j]<sum) i++;
else if(a[i]+a[j]>sum) j--;
else {
System.out.println(a[i]+","+a[j]);
i++;
}
}
}
if (!Array.prototype.unique) {
Array.prototype.unique = function () {
var hash = {}, result = [], type = '', item;
for (var i = 0; i < this.length; i++) {
item = this[i];
type = Object.prototype.toString.call(item);
if ( !hash[item + type] ) {
hash[item + type] = true;
result.push(item);
}
}
return result;
};
}
p em
h1 > strong
h1+p
session机制。session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构(也可能就是使用散列表)来保存信息。
当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了一个session标识------------称为session id,如果已包含则说明以前已经为此客户端创建过session,服务器就按照session id把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含session id,则为此客户端创建一个session并且生成一个与此session相关联的session id,session id的值应该是一个既不会重复,又不容易被找到规律以仿造的字符串,这个session id将被在本次响应中返回给客户端保存。
保存这个session id的方式可以采用cookie,这样在交互过程中浏览器可以自动的按照规则把这个标识发挥给服务器。一般这个cookie的名字都是类似于SEEESIONID。但cookie可以被人为的禁止,则必须有其他机制以便在cookie被禁止时仍然能够把session id传递回服务器。
经常被使用的一种技术叫做URL重写,就是把session id直接附加在URL路径的后面。还有一种技术叫做表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。
当你不再需要该表时, 用 drop;
当你仍要保留该表,但要删除所有记录时, 用 truncate;
当你要删除部分记录时(always with a WHERE clause), 用 delete.
https://www.cnblogs.com/HCJJ/p/6408363.html
em:是一种相对单位,它相对于父元素的字体大小。浏览器默认的字体大小是16px,因此 1em 也就等于 16px。
rem是一种相对单位,它相对于根元素 html
的字体大小。
REM会让页面根据不同的显示设备进行适配缩放,那么必然就会有一个 标准页面尺寸,就目前而言,整个前端开发界使用最多的标准页面尺寸则是根据iphone4或者 iPhone5为依据的 640px*1366px
,也有以iphone6为基准的750px。这个标准的页面尺寸,我们可以将其定义为1,如果当前的显示设备尺寸小于标准页面尺寸(640px或者750px)那么便让页面尺寸缩小,使其小于1。而当显示设备尺寸大于标准页面尺寸,我们即可以做一些其它的适配,也可以将页面整个居中显示在显示设备中然后不进行任何缩放操作。
实际上rem布局与px布局并没有什么本质的区别,这个我们可以代入实例去理解,比如现在 html
的 font-size
的大小是100px,即 1rem = 100px,如果现在页面中要放入一个200*200的盒子,那么按照等比关系:
div{
width:2rem;
height:2rem;
background:gray;
}
REM 实现的页面缩放适配原理, rem 是依据 html
标记的 font-size
大小的相对单位,对于使用rem为单位的页面,在被载入到显示设备显示的时候,会根据显示设备的尺寸,然后对应的修改html标签的font-size值,这样便可以一处修改,整个页面内容都会发生改变,即实现根据设备尺寸进行缩放的效果。
REM方式进行移动端布局的原理都是相同的,但是不同的在与对于设备尺寸的检测上,就目前而言分为两种,一种是通过CSS meida查询,另一种则是通过JS检测。
CSS Media
@media screen and (min-width:320px) and (max-width:359px) {
html {
font-size: 50px;
}
}
@media screen and (min-width:360px) and (max-width:374px) {
html {
font-size: 56.25px;
}
}
@media screen and (min-width:375px) and (max-width:383px) {
html {
font-size: 58.59375px;
}
}
@media screen and (min-width:384px) and (max-width:399px) {
html {
font-size: 60px;
}
}
@media screen and (min-width:400px) and (max-width:413px) {
html {
font-size: 62.5px;
}
}
@media screen and (min-width:414px) and (max-width:431px) {
html {
font-size: 64.6875px;
}
}
@media screen and (min-width:432px) and (max-width:479px) {
html {
font-size: 67.5px;
}
}
@media screen and (min-width:480px) and (max-width:539px) {
html {
font-size: 75px;
}
}
@media screen and (min-width:540px) and (max-width:639px) {
html {
font-size: 84.375px;
}
}
@media screen and (min-width:640px) {
html {
font-size: 100px;
}
body {
max-width: 640px !important;
margin: 0px auto !important;
}
}
响应式REM布局的优点在于可以根据设计稿的特点,自定义的对某些设备进行单独适配,而缺点是检测规则固定不可变,这一点相比于“JS自动换算”更为明显。
JS检测
(function(win,doc){
var timer = null,
html = doc.documentElement,
baseWidth = html.dataset.basewidth*1 || 640,
metaEl = document.querySelector('meta[name="viewport"]'),
event = 'onorientationchange' in win ? 'onorientationchange' : 'resize';
if(!metaEl){
metaEl = document.createElement('meta');
metaEl.setAttribute('name','viewport');
metaEl.setAttribute('content','initial-scale=1,maximum-scale=1,minimum-scale=1,user-scalable=0');
html.firstElementChild.appendChild(metaEl);
}
function layoutCalc(){
var width = html.getBoundingClientRect().width,
ratio = width / baseWidth * 100,
devicePixelRatio = window.devicePixelRatio,
rem = ratio < 100 ? ratio < 50 ? 50 : ratio : 100;
if(!/\.\d+/.test(devicePixelRatio.toString())){
html.dataset.dpr = devicePixelRatio;
}
html.style.fontSize = rem + 'px';
}
win.addEventListener(event,function(){
clearTimeout(timer);
timer = setTimeout(layoutCalc,300);
},false);
win.addEventListener('pageShow',function(e){
if(e.persisted){
clearTimeout(timer);
timer = setTimeout(layoutCalc,300);
}
},false);
layoutCalc();
}(window,document));
自定义基准页面尺寸:通过为 html 标签添加 data-basewidth
属性来自定义指定基准页面的尺寸。
<html data-basewidth="750" >
html>
定义页面内容的字体大小:对于一些符合标准的dpr(设备像素比https://blog.csdn.net/a419419/article/details/79295799)值(只要是整数,例如:1,2,3),都会为 html
标签再附加一个 data-dpr
属性,然后开发者便可以根据这个属性为条件,实现在不同dpr情况下,对内容字体的大小的调整
html[data-dpr="1"] .dpr-text{
font-size:12px;
}
html[data-dpr="2"] .dpr-text{
font-size:24px;
}
html[data-dpr="3"] .dpr-text{
font-size:36px;
}
<p class="dpr-text">测试文字p>
相比“响应式方式”JS自动换算无需添加规则,适合于各类型的显示设备。
vh/vw都是相对于视口的单位,浏览器视口的区域就是通过 window.innerWidth
以及 window.innerHeigth
度量得到的范围。浏览器会将整个视口的宽度或者高度划分为100等份,因此1vw或者1wh就是相对视口宽度或者高度的1%。例如浏览器视口的宽度是1920,那么 1920/100 每等份即19.2px。
computed:计算属性将被混入到 Vue 实例中。所有 getter 和 setter 的 this 上下文自动地绑定为 Vue 实例。
注意如果你为一个计算属性使用了箭头函数,则 this
不会指向这个组件的实例,不过你仍然可以将其实例作为函数的第一个参数来访问。计算属性的结果会被缓存,除非依赖的响应式属性变化才会重新计算。注意,如果某个依赖 (比如非响应式属性) 在该实例范畴之外,则计算属性是不会被更新的。
methods: methods 将被混入到 Vue 实例中。可以直接通过 VM 实例访问这些方法,或者在指令表达式中使用。方法中的 this
自动绑定为 Vue 实例。注意,不应该使用箭头函数来定义 method 函数 (例如 plus: () => this.a++
)。理由是箭头函数绑定了父级作用域的上下文,所以 this
将不会按照期望指向 Vue 实例,this.a
将是 undefined。
watch: 一个对象,键是需要观察的表达式,值是对应回调函数。值也可以是方法名,或者包含选项的对象。Vue 实例将会在实例化时调用 $watch()
,遍历 watch 对象的每一个属性。注意,不应该使用箭头函数来定义 watcher 函数 (例如 searchQuery: newValue => this.updateAutocomplete(newValue)
)。理由是箭头函数绑定了父级作用域的上下文,所以 this
将不会按照期望指向 Vue 实例,this.updateAutocomplete
将是 undefined。
能使用watch属性的场景基本上都可以使用computed属性,而且computed属性开销小,性能高,因此能使用computed就尽量使用computed属性.当执行异步操作的时候你可能就必须用watch而不是computed了
function findNum(a){
var result = [0,0];
for (var i = 0; i < a.length; i++) {
for (var j = 0,count = 0; j < a.length; j++) {
if (a[i]==a[j]) {
++count;
};
};
if(count>result[0]) {
result[0] = count;
result[1] = a[i];
}else if(count==result[0]&&result[1]<a[i]) {
result[1] = a[i];
}
}
alert("数"+result[1]+"重复了最多次,为"+result[0]);
}
var arr = [2,2,3,3,3,4,4,4,4,4,4,4,4,43,3];
findNum(arr);
在HTTP/1.0中默认使用短连接。也就是说,客户端和服务器每进行一次HTTP操作,就建立一次连接,任务结束就中断连接。当客户端浏览器访问的某个HTML或其他类型的Web页中包含有其他的Web资源(如JavaScript文件、图像文件、CSS文件等),每遇到这样一个Web资源,浏览器就会重新建立一个HTTP会话。
而从HTTP/1.1起,默认使用长连接,用以保持连接特性。使用长连接的HTTP协议,会在响应头加入这行代码:
Connection:keep-alive
在使用长连接的情况下,当一个网页打开完成后,客户端和服务器之间用于传输HTTP数据的TCP连接不会关闭,客户端再次访问这个服务器时,会继续使用这一条已经建立的连接。Keep-Alive不会永久保持连接,它有一个保持时间,可以在不同的服务器软件(如Apache)中设定这个时间。实现长连接需要客户端和服务端都支持长连接。
HTTP协议的长连接和短连接,实质上是TCP协议的长连接和短连接。
https://www.cnblogs.com/blogtech/p/10981606.html
允许服务端主动向客户端推送数据。在 WebSocket API 中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。
现在,很多网站为了实现推送技术,所用的技术都是 Ajax 轮询。轮询是在特定的的时间间隔(如每1秒),由浏览器对服务器发出HTTP请求,然后由服务器返回最新的数据给客户端的浏览器。这种传统的模式带来很明显的缺点,即浏览器需要不断的向服务器发出请求,然而HTTP请求可能包含较长的头部,其中真正有效的数据可能只是很小的一部分,显然这样会浪费很多的带宽等资源。
浏览器通过 JavaScript 向服务器发出建立 WebSocket 连接的请求,连接建立以后,客户端和服务器端就可以通过 TCP 连接直接交换数据。
当你获取 Web Socket 连接后,你可以通过 send() 方法来向服务器发送数据,并通过 onmessage 事件来接收服务器返回的数据。
var Socket = new WebSocket(url, [protocol] );
ETag是HTTP1.1中才加入的一个属性,用来帮助服务器控制Web端的缓存验证。
的原理是这样的,当浏览器请求服务器的某项资源(A)时, 服务器根据A算出一个哈希值(3f80f-1b6-3e1cb03b)并通过 ETag 返回给浏览器,浏览器把"3f80f-1b6-3e1cb03b" 和 A 同时缓存在本地,当下次再次向服务器请求A时,会通过类似 If-None-Match: "3f80f-1b6-3e1cb03b"
的请求头把ETag发送给服务器,服务器再次计算A的哈希值并和浏览器返回的值做比较,如果发现A发生了变化就把A返回给浏览器(200),如果发现A没有变化就给浏览器返回一个304未修改。这样通过控制浏览器端的缓存,可以节省服务器的带宽,因为服务器不需要每次都把全量数据返回给客户端。
ETag`HTTP响应头是资源的特定版本的标识符。这可以让缓存更高效,并节省带宽,因为如果内容没有改变,Web服务器不需要发送完整的响应。而如果内容发生了变化,使用ETag有助于防止资源的同时更新相互覆盖(“空中碰撞”)。
如果给定URL中的资源更改,则一定要生成新的Etag值。 因此Etags类似于指纹,也可能被某些服务器用于跟踪。 比较etags能快速确定此资源是否变化,但也可能被跟踪服务器永久存留。
transform:描述了元素的静态样式,本身不会呈现动画效果,可以对元素进行 旋转rotate、扭曲skew、缩放scale和移动translate以及矩阵变形matrix.
transform常常配合transition和animation使用
transition样式过渡,从一种效果逐渐改变为另一种效果。transition是一个合写属性:
transition:transition-property transition-duration transition-timing-function transition-delay//从左到右分别是:css属性、过渡效果花费时间、速度曲线、过渡开始的延迟时间
animation动画 由@keyframes来描述每一帧的样式
div{
animation:myAnimation 5s infinite
}
@keyframes myAnimation {
0%{left:0;transform:rotate(0);}
100%{left:200px;transform:rotate(180deg);}
}
(1)transform仅描述元素的静态样式,常常配合transition和animation使用
(2)transition通常和hover等事件配合使用,animation是自发的,立即播放
(3)animation可设置循环次数
(4)animation可设置每一帧的样式和时间,transition只能设置头尾
(5)transition可与js配合使用,js设定要变化的样式,transition负责动画效果
/*css:*/
div{
width:100px;
height:100px;
transition:all 1s;
}
//js
divEle.onclick = function(){
divEle.style.width = "200px";
divEle.style.height = "200px";
}
https://blog.csdn.net/weixin_38536027/article/details/79375411
使用typeof()或者typeof进行基本数据类型检测,null是Null类型,属于基本类型,但是typeof null 返回的是字符串’object’;
console.log(typeof undefined);//未定义undefined
console.log(typeof null);//空值,对象类型
引用类型只能使用 instanceof,基本数据类型无法使用instanceof 进行检测数据类型,因为基本数据类型使用instanceof进行检测,结果都是返回false
将-webkit-font-smoothing设置为antialiased,变得非常平滑,效果非常不错。
其默认可以支持6个值(如图),暂时我能看到效果的就是三个:
none(用于小像素文本) | subpixel-antialiased(默认) | antialiased(反锯齿)
在`非严格模式`下,函数中的this指向window对象,因为此时函数fn是window的一个属性,所以运行fn时,fn中的this指向window。其实this的指向就是指向函数的`运行时`环境。
在`严格模式`下,若不使用window调用函数,函数中的this指向undefined;使用window调用时,指向的时window对象。
var fn = function () {
'use strict'
console.log(this);
console.log(this === window)
}
fn();
//undfined
//false
window.fn();
//Window对象
//true
在`严格模式`下有一种例外的情况,就是在定时器中的this,此时无论使用window调用还是不使用window调用,this都指向window。
定义时
环境中的this指向一致var fun = () => {
console.log(this);
console.log(this === window);
}
fun();
//Window对象
//true
//定义箭头函数时,就是这个过程:()=>{...}所在的环境是window,所以运行fun()时,箭头函数内部的this指向window
var obj = {
name:'Jay',
age:25,
fn:()=>{console.log(this)},
fun:function(){
console.log(this)
}
};
//在定义fn时,fn内部this的指向就是定义obj对象时所在的环境,obj所在的环境是window,所以调用obj.fn()时,返回的this就是Window对象
obj.fn(); //Window对象
obj.fun();//{name: "Jay", age: 25, fn: ƒ, fun: ƒ}
DOM事件处理函数中this的指向是触发该事件的对象
<div id='app'>App</div>
<script>
var $id = document.querySelector('#app');
$id.onclick = function () {
console.log(this);
}
</script>
//当点击App时,console.log(this),打印出来的值时 App
构造函数中的this的指向是通过构造函数所创建出的对象实例
function Person (){
this.name = 'Jay',
this.age = 25;
console.log(this);
}
var p1 = new Person();
//Person {name: "Jay", age: 25}
可以使用call()、apply()、bind()改变函数内部this的指向(ES6中的箭头函数除外)。其中call()和apply()在传入要绑定的this指向时,立即执行。bind()在传入要绑定的this指向时,并不执行,需要再次调用才会执行。
使用bind()改变this的指向
var obj = {
name:'Jay',
age:25
};
function fn(){
console.log(this===obj);
console.log(this);
}
//fn.bind(obj);不会立即执行,需要再次调用才会执行。
var fn1 = fn.bind(obj);
fn1();
//true
//{name: "Jay", age: 25}
需要注意的是,当使用call()、apply()、bind()改变函数内部this的指向时,如果传入的不是一个对象,会调用相对的构造函数,进行隐式类型装换。
function fn(){
console.log(typeof this === 'object');
console.log(this);
}
fn.apply('I am a string');
//true
//String{"I am a string"}
HTML可以将元素分类方式分为行内元素、块状元素和行内块状元素三种。首先需要说明的是,这三者是可以互相转换的,使用display属性能够将三者任意转换:
(1)display:inline;转换为行内元素
(2)display:block;转换为块状元素
(3)display:inline-block;转换为行内块状元素
行内元素特征:
(1)设置宽高无效
(2)对margin仅设置左右方向有效,上下无效;padding设置上下左右都有效,即会撑大空间
(3)不会自动进行换行
块状元素特征:
(1)能够识别宽高
(2)margin和padding的上下左右均对其有效
(3)可以自动换行
(4)多个块状元素标签写在一起,默认排列方式为从上至下
行内块状元素特征:
(1)不自动换行
(2)能够识别宽高
(3)默认排列方式为从左到右
HTML标签可以分为有语义的标签,和无语义的标签。比如table表示表格,form表示表单,a标签表示超链接,strong标签表强调。无语义标签典型的有div,span等。