原始数据类型主要分为:
number,string,Boolean,null,undefind
null是对象css
基础类型按值储存在栈内存中
对象类型(引用类型)储存在堆内存中。以指针方式去使用
函数参数和复制操做:
基础数据类型在从新建立一份新值。改变其中任何一个,另外一个不受影响
引用数据类型。变量对象也会为其开辟空间,但复制的是指针,都指向内存的值,一个改变,另外一个也回受影响html
typeof 与 instanceof都是判断数据类型的。区别以下:
typeof判断基础数据类型。当判断null的时候将返回objcet
instanceof判断引用数据类型,原理根据原型链追踪去实现前端
null=》0
undefined=》NaN
Boolean
true =》1
false=》0
Sting
数字=》数字
字母=》NaN
空字符串=》0
数组
空数组=》0
一个元素且为数字=》数字
其余=》NaN
引用类型
NaNnode
underfind=》‘underfind’
null=》‘null’
Number
'数字'
Boolean
‘true’
‘false’
数组
‘【12.43,323】’=>12.43,323
对象
[object Object]
function
function(){console.log(212)}es6
null
false
underfind
false
Number
0,-0,NaN=>false
其余=>true
String
''=>false
其余=>true
引用类型
trueweb
转字符串类型直接调用toString()
转其余类型先转valueOf()面试
运算中其中一方是字符串,另外一个方也将转换成字符串
若是一方不是字符串数字。那么会将它转成数字或者字符串
除了加减运算以外。一方为数字,另外一方转为数字算法
若是是对象,就经过 toPrimitive 转换对象
若是是字符串,就经过 unicode 字符索引来比较chrome
window数据库
对象调用,则指向这个对象
独立调用,指向window
apply.call,bind动态this
指向当前实例化后的对象。
调用箭头函数外层第一个普通函数的this
先判断数据类型是否相同,一致判断值大小
类型不一样,进行类型转换
先判断是不是null和underfind的比较,是返回true
判断是不是string和number的比较,是先将字符串转成对应的数字进行比较
判断一方是否为布尔值,是则把布尔值换成number进行比较
判断一方是否为object,且另一方为string,number,是则把object转成基础类型进行判断
不会尽享类型转换,直接对比值的大小
在函数执行上下A
在执行上下文A中的函数B
调用了A中的变量。闭包产生
在js中,函数上下文执行完以后,生命周期结束后。垃圾回收机制就会回收内部不被使用的变量,也就是内存中失去引用的变量,对其进行回收。闭包会阻止此过程
js中具备自动垃圾回收机制,对于函数内部的变量失去引用以后,很快会被回收,可是处于全局的变量,js不会回收,除非引用完及时释放,尽可能少使用全局变量
基础类型值的拷贝
引用类型拷贝的引用地址(指针)
一个改变另外一个必受影响
Object.assign()和...都是浅拷贝
深拷贝
从新开辟内存空间,互相不影响
function deepClone(obj) { function isObject(o) { return (typeof o == 'object' || typeof o == 'function') && o !== null } if (!isObject(obj)) { throw new Error('this is not objcet') } let isArray = Array.isArray(obj) let newObj = isArray ? [...obj] : { ...obj } Reflect.ownKeys(newObj).forEach(key => { newObj[key] = isObject(obj[key]) ? deepClone(obj[key]) : obj[key] }) return newObj }
对象的 __proto__ 属性指向原型, __proto__ 将对象和原型链接起来组成了原型链
当控制器执行到可执行的代码的时候,js就会建立执行上下文
执行上下文的建立阶段会建立变量对象。此时
此时会先建立arguments对象
检查函数,以函数声明并建立属性
检查var声明的变量,复制underfind
其实这个就是所谓的变量提高阶段
区别:
var存在变量提高
能够重复声明
能够用window去调用
const、let
不存在变量提高
不可重复声明
拥有块级做用域
不可经过window去调用
const赋值不可更改
当变量未声明以前。去调用此变量,被叫作暂时性死区
原型继承
构造函数继承经过
call改变this指向去继承上面的方法和属性
原型上的继承
将子类的原型指向父级的实例话对象
构造函数继承一样使用call改变指向进行继承
原型继承则经过Object.create()进行继承
class 实现继承的核心在于使用 extends 代表继承自哪一个父类
而且在子类构造函数中必须调用 super,由于这段代码能够当作 Parent.call(this, value)
class 的本质就是函数。
解决命名冲突
实现复用
提升代码的可维护程度
避免变量全局污染
不支持动态引入
对象的代理
代理,但是实现数据的双向绑定
let handler = { get(target, property, receiver) { getLogger(target, property) return Reflect.get(target, property, receiver) }, set(target, property, value, receiver) { setBind(value, property) return Reflect.set(target, property, value) } } return new Proxy(obj, handler) } let p = onWatch( obj, (v, property) => { console.log(`监听到属性${property}改变为${v}`) }, (target, property) => { console.log(`'${property}' = ${target[property]}`) } ) p.a = 2 // 监听到属性a改变 console.log(p.a)
返回一个新数组。能够在这个函数中加逻辑处理返回
接受三个参数
当前的元素
index
愿数组
返回一个新数组。对符合条件元素进行返回
接受三个参数
当前的元素
index
愿数组
数组的计算
接受两个参数,分别是回调函数和初始值
隐藏了这个复杂的过程,只须要一句代码调用就能实现功能。
隐藏了这个复杂的过程,只须要一句代码调用就能实现功能。
适配器用来解决两个接口不兼容的状况,不须要改变已有的接口,经过包装一层的方式实现两个接口的正常协做。
class Man { getName() { return '港版插头' } } class Son { constructor() { this.proxy = new Man() } getName() { return this.proxy.getName() + 'hahahahh' } static create(name) { console.log(name) } } let s = new Son() console.log(s.getName())
代理是为了控制对对象的访问,不让外部直接访问到对象。在现实生活中,也有不少代理的场景。好比事件代理
发布-订阅模式也叫作观察者模式。经过一对一或者一对多的依赖关系,当对象发生改变时,订阅方都会收到通知。
并发是一段时间相继完成,好比A和B,一段时间内切换完成相似早上起床前。洗漱,吃饭,出门。一段时间完成的一些事
并行是同时进行,好比边看手机边吃饭
当咱们异步请求成功时会在回调函数中写咱们的逻辑。固然这里的逻辑还涉及到进一步的请求,不断嵌套就会出现回调地狱
回调函数缺点:
嵌套过深,耦合度高,不易维护
难以捕捉错误
不能使用try。。catch
使用Generator和promise以及async均可以
自然的迭代器,能够是遍历停下来
可控制迭代器的函数,能够暂停,也能够选择任什么时候候恢复
使用场景:
抽奖
小游戏
斐波那契数列
特色:
Promise三个状态,padding,resolve和reject。状态不可逆,一旦确认,没法改变
Promise链:
经过then方法去传递执行,执行then方法以后会返回一个promise对象,来完成链式操做
构造函数和then函数执行有哪些区别?
构造函数内的内容当即执行。
then的函数当状态改变在进行执行
优化了promise链式调用,以同步的写法去操做异步代码
原理实际上是promise的语法糖,await 内部经过promise静态方法Promise.resove()返回一个新的promise
Function.prototype.myApply = function (context, arr) { if (typeof this !== 'function') { throw new Error('error') } context = context || window context.fn = this let reslut; if (arr) { reslut = context.fn(...arr) } else { reslut = context.fn() } delete context.fn return reslut }
Function.prototype.myCall = function (context) { if (typeof this !== 'function') { throw new Error('error') } context = context || window context.fn = this let args = [...arguments].slice(1) let reslut = context.fn(...args) delete context.fn return reslut }
Function.prototype.myApply = function (context, arr) { if (typeof this !== 'function') { throw new Error('error') } context = context || window context.fn = this let reslut; reslut = arr ? context.fn(...arr) : context.fn() delete context.fn return reslut }
function news() { let obj = new Object() let Constructor = [...arguments].shift() obj.__proto__ = Constructor.prototype let res = constructor.apply(obj, arguments) return typeof res === 'object' ? ret : obj }
function instanceofs(left, right) { let prototype = right.prototype left = left.__proto__ while (1) { if (left == null || left == undefined) { return false } if (left == prototype) { return true } left = left.__proto__ } }
v8实现了精确式GC,GC算法采用分代垃圾回收机制,所以。v8将内存(堆)分为新生代和老生代两部分
新生代算法
对象存活时间较短,使用 Scavenge GC 算法
在新生代内存空间分为2部分,分别是from空间和to空间,在这2个空间其中必然有一个是空闲的。新分配的对象会放到from空间,当from空间被占满的时候,新生代GC就会启动,算法会检查from空间的存活对象,将他们复制到to空间,其中失去存活的对象就会被销毁,将复制完,from和to空间互换,
老生代算法
某一个空间没有分块时
空间中被对象超过一段限制时
空间不能保证新生代对象转到老生代中
这个时候遍历堆中全部活的对象,在标记完成后,销毁那些没有标记的对象。
清除对象后会形成堆内存出现碎片的状况
当碎片超过必定限制的时,会启动压缩算法。在压缩过程当中,将活的对象像一端移动,直到全部对象都移动完成而后清理掉不须要的内存。
新生代中的对象是否已经经历过Scavenge算法。若是经历过,会将新生代空间转到老生代空间中
当to空间的对象占空间大小的25%,这样状况下。为了避免影响内存分配。会将对象重新生代的空间转老生代空间中
浏览器出与安全考虑。有同源策略。也就是当协议。域名。端口号任何一个不一样就是跨域。Ajax就会请求失败
其实主要是用来防止 CSRF 攻击的。简单点说,CSRF 攻击是利用用户的登陆态发起恶意请求。
jsonp
cors
document.domain
postMessage
对于复杂请求来讲,首先会发起一个预检请求,该请求是 option 方法的,经过该请求来知道服务端是否容许跨域请求。
事件处理程序
增长和和删除事件:
element.attachEvent('on'+事件类型,处理函数)
element.detachEvent(‘on’+事件类型,处理函数)
element.addEventListener('click',处理函数,是否冒泡)
false(默认冒泡)
true(捕获)
element.removeEventListener('click',处理程序,是否冒泡)
同添加事件一致
事件对象
cancelBubble =》默认值为false,但设置true就能够取消事件冒泡
returnValue =》默认true,设置为false,,就能够取消事件的默认行为
srcElement =>事件目标
type=>事件类型
stopPropagation =》取消事件冒泡
preventDefault =》取消事件的默认行为
target =>事件目标
type=>事件类型
若是一个节点中子节点是动态生成的,那么子节点须要注册事件的化应该注册在父节点上
好处:
节省内存空间
不须要给子节点注销事件
事件的触发过程是怎么样的?知道什么是事件代理嘛?
事件触发有三个阶段:
window往事件触发传播。遇到注册的捕获事件会触发
传播到事件触发时触发注册事件
从事件触发之处向window传播。遇到注册的冒泡会触发
从捕获到目标阶段再到冒泡的过程
从上向下执行的一个过程
Document=》html=》body=》div
从当前事件触发向上查找过程
div=>body=>html=>document
cookie已经不建议存储了,若是没有大量数据存储须要,使用localStorage和sessionStorage
对于不怎么改变的数据存使用localStorage。不然使用sessionStorage
cookie
做用:主要用于储存用户的登录信息,
生命周期:通常有服务器生成,能够设置过时时间
数据储存大小:4k
与服务端通讯:每次都会携带在headr中,对于请求性能影响
属性 | 做用 |
---|---|
value | 若是用于保存登录状态,应加密,不能使用明文的用户标示 |
http-only | 不能经过js访问cookie,减小xss的攻击 |
secure | 只能在协议为https的请求中携带 |
same-site | 规定浏览器不能在跨域请求中携带cookie,减小CSRE攻击 |
生命周期:除非被清理,不然一直存在
数据存储大小:5M
与服务端通讯:不参与
数据生命周期:页面关闭就清理
数据存储大小:5M
与服务端通讯:不参与
数据生命周期:除非被清理,不然一直存在
数据存储大小:无限
是否与服务端通讯:不参与
service worker是一段脚本,与web worker同样,也在后台运行,做为一个独立的线程。运行环境和普通脚本不一样,因此不能直接参与web交互行为。native app能够作到离线使用,消息推送。后台自启动,service worker的出现为了是web app 也有相似的能力
使用场景
离线缓存
性能优化领域
缓存能够说是性能优化中最简单高效的一种方式了。他以最高减小网络传输所带来的损耗
数据请求:
网络请求
后端处理
浏览器响应
直接使用缓存,而不发请求
或发起请求后端存储的数据和前端一致,那么就不必将数据回传过来,这样能够减小响应数据
优势:
它的缓存和其余内建的缓存机制不一样。它能够由咱们自定缓存那些文件,如何匹配缓存,如何读取缓存,而且缓存是持久性的
Memory Cache
优势:
内存中的缓存。读取内存中的数据比磁盘要快不少
访问过页面以后,再次刷新页面,能够发现以前不少数据都来自内存缓存
缺点:
持续性短,随着进程的释放而释放
大文件通常都是不会储存内存中,反之优先
优势:
储存在硬盘中。覆盖率基本是最大的,什么均可以存入
跟内存相比。容量和储存时效性超级好
储存在会话中,一旦会话结束就会被释放
强缓存
是HTTP/1的产物,表示资源的过时时间,并受限与本地时间。若是修改了时间,缓存失效
出现于HTTP/1.1的产物,优先级比Expires要高
该属性能够调整设置时间
Cache-control能够在请求头或者响应中设置,而且能够组合多种指令
private=>响应能够被客户端缓存
pablic=》能够同被客户端和代理服务器缓存
no-cache=》资源会被缓存,但当即失效。下次发起请求会验证是否过时
协议缓存
若是缓存过时了。就须要发起请求验证资源是否更新,协议缓存能够经过2个http-header实现:Last-Modified+ETag
当浏览器发起请求验证资源时,若是资源没有作出改变,那么服务器会返回304状态吗。而且更新缓存有效期
若是资源有所改变,更新资源
表示本地文件最后更改的日期。If-Modified-Since会将last-Modified的值发送给服务器,询问服务器在该日期更新后资源是否有变更,有更新,返回更新后的信息,反之,返回状态码
弊端:
若是是本地打开缓存文件,即便没有对文件进行修改,但仍是会形成last-Modified的修改。服务端不能命中缓存致使发送相同的资源
由于last-Modified只能以秒计时。若是在不可感知的时间你内完成了这个文件,那么会形成服务端认为资源被秒中,不会返回正确值
相似指纹,If-None-Match会将ETag发送给你服务器,询问服务器资源ETag是否改变,若有改变,将更新的资源返回来,ETag比Last-Modified的优先级高
首先浏览器打开一个网页的时候,首先会解析他对应的html,在网络传输中咱们平时所写的js+css+html都都是以子节数据(0-1)进行传输
转子节转为字符串。
字符串经过词法解析为标记(token),这一过程也被称为标记法。
将结束标记以后,将会把标记转为node
根据node以前的联系转成dom
首先这一过程是很是耗性能的,由于浏览器会肯定每个节点样式分别是什么,须要递归匹配到数据的变化
子节数据
字符串
标记(token)
node
cssom
当咱们生成dom树和cssom树的时候,就须要将这2个树和成渲染树
在这一过程当中,将包括须要的节点和这些节点的样式去渲染出来
当浏览器生成渲染树以后,浏览器根据渲染树布局,而后GPU绘制。合成图层
由于dom属于渲染引擎,js属于js引擎,面对两个线程以前的通讯,操做dom次数一多,也就等同于进行线程以前的切换,而且操做dom可能带来回流。
渲染的前提是生成渲染树,全部html和css确定会堵塞渲染
下降一开始须要渲染的文件大小
而且扁平化。优化选择器
当浏览器在执行到script标签时,就会暂时dom,完成后从暂停处继续执行,
首评加载的越快,就不应在首评加载js。建议将script放到body下面的缘由
async(适合没有依赖的文件)
js文件下载和解析不会阻塞渲染
defer
并行下载,会等到html执行完毕以后在进行执行
回流必定会引发重绘
但重绘不必定会引发回流
当改变节点的样的时候。不会改变布局的时候,好比修改color样式。
通常布局修改,dom操纵通常会触发回流
使用 transform 替代 top
使用 visibility 替换 display: none ,由于前者只会引发重绘,后者会引起回流(改变了布局)
不要把节点的属性值放在一个循环里当成循环里的变量
不要使用 table 布局,可能很小的一个小改动会形成整个 table 的从新布局
动画实现的速度的选择,动画速度越快,回流次数越多,也能够选择使用 requestAnimationFrame
CSS 选择符从右往左匹配查找,避免节点层级过多
从文件大小
从script标签上使用来考虑
从html和css代码书写上来考虑
从须要下载的内容是否须要在首屏使用上来考虑
想尽一切办法将可执行的代码注入网页中
攻击的代码被服务器写日数据库,这种危害会很大,若是网站访问量大的话,会致使正常访问页面的用户都收到攻击
通常会以评论方式去注入
通常以修改URL参数的方式进行攻击
诱导用户访问连接从而实现攻击
对于用户输入的东西永远不要相信,最普通的作法是对用户输入的内容进行转译。
引号。尖括号。斜杠等进行转译‘
或者使用白名单也能够,js-xss来实现
跨站伪造请求,攻击者构造出一个向后端请求的地址,诱导用户点击或者经过某种途径自动发起请求,若是用户是在登录的状况下,后端觉得是用户操做,从而进行诱导。
经常使用方式:
加入网站中有个get请求提交表单的接口。那么攻击者会在钓鱼网站加入一个图片,图片的地址就是这个评论的接口
防护:
get请求不对数据进行修改
不让第三方访问到用户的cookie(some-site)
阻止第三方网站请求接口(验证refrer)
请求是附带验证信息,好比token或者验证码,进行判断
攻击者经过将要攻击的网站经过iframe的方式放入本身的网站中,并将iframe设为透明,诱导用户点击
防护:
js判断,删除页面中的iframe
是指攻击方同时将服务端和客户端同时进行链接。并让对方认为都是安全的,但实际上整个过程当中,都是被控制了,攻击者能够同时修改用户的信息和数据库中的内容
防护:
尽可能避免在公众场合使用Wi-Fi。避免被攻击
XMind: ZEN - Trial Version