首先html5为了更好的实践web语义化,增加了header,footer,nav,aside,section等语义化标签,在表单方面,为了增强表单,为input增加了color,emial,data ,range等类型,在存储方面,提供了sessionStorage,localStorage,和离线存储,通过这些存储方式方便数据在客户端的存储和获取,在多媒体方面规定了音频和视频元素audio和vedio,另外还有地理定位,canvas画布,拖放,多线程编程的web worker和websocket协议
静态布局
宽高固定
自适应布局:
布局特点:不同分辨率下,页面元素位置变化,大小不变
实现方法:针对不同分辨率创建对应的样式表,使用 @media 媒体查询给不同尺寸的设备切换不同的样式
缺点:IE8及以下不支持媒体查询;只能兼容主流分辨率
流式布局(百分比布局):
布局特点:不同的分辨率下显示相同的排版;高度固定,宽度自适应
实现方法:网页中主要区域的尺寸使用百分比;
缺点:大屏幕上元素被拉长,但是文字,高度还是固定大小,不协调
经典流式布局:左侧固定,右侧自适应;两侧固定,中间自适应
弹性布局(rem/em布局):
布局特点:页面元素宽度,高度,字体大小会跟着屏幕大小缩放
实现方法:使用js监听当前屏幕大小,设置html的字体大小
缺点:IE678不兼容;需要计算;
响应式布局:
布局特点:每个屏幕分辨率下面会有一个布局样式,即元素位置和大小都会变,响应式设计的目标是确保一个页面在所有终端上(各种尺寸的PC、手机、手表等等)都能显示出令人满意的效果
实现方法:媒体查询+流式布局
优点:适应pc和移动端
缺点:要匹配足够多的屏幕大小,工作量大,设计也需要多个版本
1.过渡 transition 2.动画 animation 3.形状转换 transform 4.阴影 box-shadow 5.滤镜 Filter 6.颜色 rgba 7.栅格布局 gird 8.弹性布局 flex
1)伪类(pseudo-classes)
其核⼼就是⽤来选择DOM树之外的信息,不能够被普通选择器选择的⽂档之外的元素,⽤来添加⼀些选择器的特殊效果。
⽐如:hover :active :visited :link :visited :first-child :focus :lang等
由于状态的变化是⾮静态的,所以元素达到⼀个特定状态时,它可能得到⼀个伪类的样式;当状态改变时,它⼜会失去这个样式。
由此可以看出,它的功能和class有些类似,但它是基于⽂档之外的抽象,所以叫 伪类。
2)伪元素(Pseudo-elements)
DOM树没有定义的虚拟元素
核⼼就是需要创建通常不存在于⽂档中的元素,
⽐如::before ::after 它选择的是元素指定内容,表示选择元素内容的之前内容或之后内容。
伪元素控制的内容和元素是没有差别的,但是它本身只是基于元素的抽象,并不存在于⽂档中,所以称为伪元素。⽤于将特殊的效果添加到某些选择器
2)伪类与伪元素的区别
表示⽅法
CSS2 中伪类、伪元素都是以单冒号:表示,
CSS2.1 后规定伪类⽤单冒号表示,伪元素⽤双冒号::表示,
浏览器同样接受 CSS2 时代已经存在的伪元素(:before, :after, :first�line, :first-letter 等)的单冒号写法。
CSS2 之后所有新增的伪元素(如::selection),应该采⽤双冒号的写法。
CSS3中,伪类与伪元素在语法上也有所区别,伪元素修改为以::开头。浏览器对以:开头的伪元素也继续⽀持,但建议规范书写为::开头
定义不同
伪类即假的类,可以添加类来达到效果
伪元素即假元素,需要通过添加元素才能达到效果
总结:
伪类和伪元素都是⽤来表示⽂档树以外的"元素"。
伪类和伪元素分别⽤单冒号:和双冒号::来表示。
伪类和伪元素的区别,关键点在于如果没有伪元素(或伪类),
是否需要添加元素才能达到效果,如果是则是伪元素,反之则是伪类。
4)相同之处:
伪类和伪元素都不出现在源⽂件和DOM树中。也就是说在html源⽂件中是看不到伪类和伪元素的。 不同之处:
伪类其实就是基于普通DOM元素⽽产⽣的不同状态,他是DOM元素的某⼀特征。
伪元素能够创建在DOM树中不存在的抽象对象,⽽且这些抽象对象是能够访问到的。
使用position + transform
使用flex
使用position
使用伪类
.parent{ font-size: 0; text-align: center; } .parent::before { content: ""; display: inline-block; width: 0; height: 100%; vertical-align: middle; } .child{ display: inline-block; vertical-align: middle; }
(1)link属于XHTML标签,除了加载CSS外,还能用于定义RSS, 定义rel连接属性等作用;而@import是CSS提供的,只能用于加载CSS;
(2)页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;
(3)import是CSS2.1 提出的,只在IE5以上才能被识别,而link是XHTML标签,无兼容问题;
Array
Array.concat( ) 合并数组
Array.join( ) 将数组元素连接起来以构建一个字符串
Array.length 数组的大小
Array.pop( ) 删除最后一项,返回所删除的值
Array.shift( ) 删除第一项,返回所删除的值
Array.push( ) 往数组最后插入数据,返回数组的长度
Array.unshift( ) 在数组头部插入数据,返回数组的长度
Array.reverse( ) 倒叙
Array.slice( ) 截取子数组,返回新值
Array.sort( ) 对数组元素进行排序
Array.splice( ) 插入、删除或替换数组的元素
Array.toLocaleString( ) 把数组转换成局部字符串
Array.toString( ) 将数组转换成一个字符串
Array.indexof( ) 检测数据中是否含有某个数据
Array.forEach( ) 循环数组
Object
Object.hasOwnProperty( ) 检查属性是否被继承
Object.isPrototypeOf( ) 一个对象是否是另一个对象的原型
Object.propertyIsEnumerable( ) 是否可以通过for/in循环看到属性
Object.toLocaleString( ) 返回对象的本地字符串表示
Object.toString( ) 定义一个对象的字符串表示
Object.valueOf( ) 指定对象的原始值
ES6
Array.from() 将类数组对象或可迭代对象转化为数组。
Array.of() 形成新数组,
map() 遍历数组,返回一个新数组,不改变原数组
filter() 过滤掉数组中不满足条件的值,返回一个新数组,不改变原数组。
reduce() 让数组的前后两项进行某种计算,然后返回其值,并继续计算,不改变原数组,返回计算的最终结果。
some() 用于遍历数组每一项,有一项返回true,则停止遍历,结果返回true。不改变原数组
every() 用于遍历数组每一项,每一项返回true,最终结果为true.有一项返回false,停止遍历,结果返回为false。不改变原数组。
find() 方法找到第一个符合条件的成员,没有符合的则返回 undefined
findIndex 方法的用法与 find方法非常类似,返回第一个符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1。
fill() 方法使用给定值, 填充一个数组,fill 方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置
copyWithin() 将一定范围索引的数组元素修改为此数组另一指定范围索引的元素
includes() 数组是否包含指定值,返回布尔值
entries(),keys()和 values()——用于遍历数组,可以用 for...of 循环进行遍历,唯一的区别是 keys(是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历 foreach() 用于遍历数组,无返回值,不改变原数组,仅仅只是遍历,常用于注册组件、指令等等
内存泄露
指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。内存泄漏并非指内情人q存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费
排查
一)是否App中的类中和引用变量过多使用了Static修饰 如public staitc Student s;在类中的属性中使用 static修饰的最好只用基本类型或字符串。如public static int i = 0; //public static String str;
二)是否App中使用了大量的递归或无限递归(递归中用到了大量的建新的对象)
三)是否App中使用了大量循环或死循环(循环中用到了大量的新建的对象)
四)检查App中是否使用了向数据库查询所有记录的方法。即一次性全部查询的方法,如果数据量超过10万多条了,就可能会造成内存溢出。所以在查询时应采用“分页查询”。
五)检查是否有数组,List,Map中存放的是对象的引用而不是对象,因为这些引用会让对应的对象不能被释放。会大量存储在内存中。
六)检查是否使用了“非字面量字符串进行+”的操作。因为String类的内容是不可变的,每次运行"+"就会产生新的对象,如果过多会造成新String对象过多,从而导致JVM没有及时回收而出现内存溢出。
内存溢出
内存溢出是由于没被引用的对象(垃圾)过多造成JVM没有及时回收,造成的内存溢出
引起内存溢出的原因
内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
代码中存在死循环或循环产生过多重复的对象实体;
使用的第三方软件中的BUG;
启动参数内存值设定的过小
不要在同一行声明多个变量。
请使用 ===/!==来比较true/false或者数值
使用对象字面量替代new Array这种形式
不要使用全局函数。
Switch语句必须带有default分支
函数不应该有时候有返回值,有时候没有返回值。
For循环必须使用大括号
If语句必须使用大括号
for-in循环中的变量 应该使用var关键字明确限定作用域,从而避免作用域污染。
基本类型:Number、Boolean、String、null、undefined、symbol(ES6 新增的),BigInt(ES2020) 引用类型:Object,对象子类型(Array,Function)
浅拷贝:一般指的是把对象的第一层拷贝到一个新对象上去
深拷贝:一般需要借助递归实现,如果对象的值还是个对象,要进一步的深入拷贝,完全替换掉每一个复杂类型的引用。
浅拷贝:浅拷贝通过ES6新特性Object.assign()或者通过扩展运算法...来达到浅拷贝的目的,浅拷贝修改 副本,不会影响原数据,但缺点是浅拷贝只能拷贝第一层的数据,且都是值类型数据,如果有引用型数据,修改 副本会影响原数据。
深拷贝:通过利用JSON.parse(JSON.stringify())来实现深拷贝的目的,但利用JSON拷贝也是有缺点的, 当要拷贝的数据中含有undefined/function/symbol类型是无法进行拷贝的,当然我们想项目开发中需要 深拷贝的数据一般不会含有以上三种类型,如有需要可以自己在封装一个函数来实现。
addEventListener()方法,用于向指定元素添加事件句柄,它可以更简单的控制事件,语法为
element.addEventListener(event, function, useCapture);
第一个参数是事件的类型(如 "click" 或 "mousedown").
第二个参数是事件触发后调用的函数。
第三个参数是个布尔值用于描述事件是冒泡还是捕获。该参数是可选的。
事件传递有两种方式,冒泡和捕获
事件传递定义了元素事件触发的顺序,如果你将P元素插入到div元素中,用户点击P元素,
在冒泡中,内部元素先被触发,然后再触发外部元素,
捕获中,外部元素先被触发,在触发内部元素,
事件委托是利用冒泡阶段的运行机制来实现的,就是把一个元素响应事件的函数委托到另一个元素,一般是把一组元素的事件委托到他的父元素上,委托的优点是
减少内存消耗,节约效率
动态绑定事件
事件冒泡,就是元素自身的事件被触发后,如果父元素有相同的事件,如onclick事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到document/window,冒泡过程结束。
事件捕获(event capturing): 当鼠标点击或者触发dom事件时(被触发dom事件的这个元素被叫作事件源),浏览器会从根节点到事件源(由外到内)进行事件传播。
事件冒泡(dubbed bubbling):事件冒泡刚好相反,事件源到根节点(由内到外)进行事件传播。
无论是事件捕获还是事件冒泡,它们都有一个共同的行为,就是事件传播。dom标准事件流的触发的先后顺序为:先捕获再冒泡。即当触发dom事件时,会先进行事件捕获,捕获到事件源之后通过事件传播进行事件冒泡。
在我们平常用的addEventListener
方法中,一般只会用到两个参数,一个是需要绑定的事件,另一个是触发事件后要执行的函数,然而,addEventListener
还可以传入第三个参数,第三个参数默认值是false,表示在事件冒泡阶段调用事件处理函数;如果参数为true,则表示在事件捕获阶段调用处理函数。
一、为什么要垃圾回收
如果没有垃圾回收机制,适时清理不被引用的值并释放相应的内存空间,JavaScript 解释器将会消耗完系统中所有可用内存,造成系统崩溃。
二、垃圾回收的核心思路
所谓垃圾回收的核心思想就是清理掉内存中不再被引用的值,通俗的说,就是清理掉内存中没用的值,那么如何判断有没有用?如果是局部变量,在函数调用结束后即是无用的,可以被回收掉;而全局变量在浏览器卸载页面的时候才会消失。由于这个过程消耗较大,所以解释器会按照固定时间周期性的执行回收。
三、垃圾回收的两种方式
1.标记清除(JS最常用)
标记清除法主要有以下三个步骤:
1)给所有变量增加一个标记,如果是进入执行环境(比如申明变量),则标记为“进入环境”,如果是结束执行环境(比如执行完相关函数),则标记为“离开环境”;
2)去掉“进入环境”的变量标记以及被该变量所引用的变量标记(比如闭包);
3)还存在标记的变量即是需要被清理的变量。
2.引用计数
引用计数法主要有以下三个步骤:
1)申明了一个变量,并且将一个引用类型的值赋值给这个变量,那么这变量的引用就加1;
2)如果这个变量的值又指向另外一个值,或者说这个变量被重新赋值了,那么以上的引用类型的值的引用次数就减1;
3)如此一来,该引用类型的值的引用次数即为0,垃圾回收器会在运行的时候清理掉引用次数为0的值并释放相应的内存空间;
4)特别注意:引用计数在代码中存在循环引用时会出现问题
Object.prototype.toString.call()、instanceof、Array.isArray()以及typeof
面向对象的三大特性:继承/多态/封装
封装
封装最好理解了。封装是面向对象的特征之一,是对象和类概念的主要特性。封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。
继承
继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。
要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。
多态性
多态性(polymorphisn)是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
实现多态,有两种方式,覆盖和重载。覆盖和重载的区别在于,覆盖在运行时决定,重载是在编译时决定。并且覆盖和重载的机制不同,例如在 Java 中,重载方法的签名必须不同于原先方法的,但对于覆盖签名必须相同。
全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。 当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找, 直至全局函数,这种组织形式就是作用域链。
原型
每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。
什么是原型链?
当对象查找一个属性的时候,如果没有在自身找到,那么就会查找自身的原型,如果原型还没有找到,那么会继续查找原型的原型,直到找到 Object.prototype 的原型时,此时原型为 null,查找停止。这种通过 通过原型链接的逐级向上的查找链被称为原型链
什么是原型继承
一个对象可以使用另外一个对象的属性或者方法称之为继承。具体是通过将这个对象的原型设置为另外一个对象,这样根据原型链的规则,如果查找一个对象属性且在自身不存在时,就会查找另外一个对象,相当于一个对象可以使用另外一个对象的属性和方法了。 关系:instance.constructor.prototype = instance.proto
特点: JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。
防抖
原理:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。
适用场景:
按钮提交场景:防止多次提交按钮,只执行最后提交的一次
搜索框联想场景:防止联想发送请求,只发送最后一次输入
节流
原理:规定在一个单位时间内,只能触发一次函数。如果这个单位时间内触发多次函数,只有一次生效。
适用场景
拖拽场景:固定时间内只执行一次,防止超高频次触发位置变动
缩放场景:监控浏览器resize
当渲染树中的一部分(或全部)因为元素的规模尺寸,布局,隐藏等改变而需要重新构建的过程叫回流(改变大小、布局)。
会导致回流的操作:
页面首次渲染
浏览器窗口大小发生改变
元素尺寸或位置发生改变
元素内容变化(文字数量或图片大小等等)
元素字体大小变化
添加或者删除可见的DOM
元素
激活CSS
伪类(例如::hover
)
查询某些属性或调用某些方法
当渲染树中的一部分元素需要更新属性,如改变元素的外观、风格,而不影响布局的重新渲染的过程叫重绘(改变样式)
重绘发生条件
元素的属性或样式发生改变,如background-color改变等。
注意:
每个页面至少需要一次回流+重绘;
回流必将引起重绘,而重绘不一定会引起回流;
如何避免
CSS
避免使用table
布局。
尽可能在DOM
树的最末端改变class
。
避免设置多层内联样式。
将动画效果应用到position
属性为absolute
或fixed
的元素上。
避免使用CSS
表达式(例如:calc()
)。
JavaScript
避免频繁操作样式,最好一次性重写style
属性,或者将样式列表定义为class
并一次性更改class
属性。
避免频繁操作DOM
,创建一个documentFragment
,在它上面应用所有DOM操作
,最后再把它添加到文档中。
也可以先为元素设置display: none
,操作结束后再把它显示出来。因为在display
属性为none
的元素上进行的DOM
操作不会引发回流和重绘。
避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来。
对具有复杂动画的元素使用绝对定位,使它脱离文档流,否则会引起父元素及后续元素频繁回流。
事件循环机制从整体上告诉了我们 JavaScript 代码的执行顺序Event Loop
即事件循环,是指浏览器或Node
的一种解决javaScript
单线程运行时不会阻塞的一种机制,也就是我们经常使用异步的原理。
先执行 Script 脚本,然后清空微任务队列,然后开始下一轮事件循环,继续先执行宏任务,再清空微任务队列,如此往复。
JavaScript的任务分为两种同步
和异步
,它们的处理方式也各自不同,同步任务是直接放在主线程上排队依次执行,异步任务会放在任务队列中,若有多个异步任务则需要在任务队列中排队等待,任务队列类似于缓冲区,任务下一步会被移到调用栈然后主线程执行调用栈的任务。
调用栈:调用栈是一个栈结构,函数调用会形成一个栈帧,帧中包含了当前执行函数的参数和局部变量等上下文信息,函数执行完后,它的执行上下文会从栈中弹出。
JavaScript是单线程
的,单线程是指 js引擎中解析和执行js代码的线程只有一个(主线程),每次只能做一件事情,然而ajax
请求中,主线程在等待响应的过程中回去做其他事情,浏览器先在事件表注册ajax的回调函数,响应回来后回调函数被添加到任务队列中等待执行,不会造成线程阻塞,所以说js处理ajax请求的方式是异步的。
宏任务微任务
宏任务指执行栈中待执行的任务,setTimeout、setInterval、script,http回调都是宏任务。
微任务指执行栈清空后立即执行的任务,Promise和 MutationObserver,nextTick都是微任务。
ES5 中只存在两种作用域:全局作用域和函数作用域。在 JavaScript 中,我们将作用域定义为一套规则,这套规则用来管理引擎如何在当前作用域以及嵌套子作用域中根据标识符名称进行变量(变量名或者函数名)查找
作用域链,当访问一个变量时,编译器在执行这段代码时,会首先从当前的作用域中查找是否有这个标识符,如果没有找到,就会去父作用域查找,如果父作用域还没找到继续向上查找,直到全局作用域为止,,而作用域链,就是有当前作用域与上层作用域的一系列变量对象组成,它保证了当前执行的作用域对符合访问权限的变量和函数的有序访问
什么是闭包
函数执行后返回结果是一个内部函数,并被外部变量所引用,如果内部函数持有被执行函数作用域的变量,即形成了闭包。
可以在内部函数访问到外部函数作用域。使用闭包,一可以读取函数中的变量,二可以将函数中的变量存储在内存中,保护变量不被污染。而正因闭包会把函数中的变量值存储在内存中,会对内存有消耗,所以不能滥用闭包,否则会影响网页性能,造成内存泄漏。当不需要使用闭包时,要及时释放内存,可将内层函数对象的变量赋值为null。
优点
可以从内部函数访问外部函数的作用域中的变量,且访问到的变量长期驻扎在内存中,可供之后使用
避免变量污染全局
把变量存到独立的作用域,作为私有成员存在
缺点
对内存消耗有负面影响。因内部函数保存了对外部变量的引用,导致无法被垃圾回收,增大内存使用量,所以使用不当会导致内存泄漏
对处理速度具有负面影响。闭包的层级决定了引用的外部变量在查找时经过的作用域链长度
可能获取到意外的值(captured value)
应用场景
应用场景一: 典型应用是模块封装,在各模块规范出现之前,都是用这样的方式防止变量污染全局。
应用场景二: 在循环中创建闭包,防止取到意外的值。
如何产生闭包
返回函数
函数当做参数传递
1、构造继承 2、原型继承 3、实例继承 4、拷贝继承
原型prototype机制或apply和call方法去实现较简单,建议使用构造函数与原型混合方式。
function Parent(){ this.name = 'wang'; }
function Child(){ this.age = 28; } Child.prototype = new Parent();//继承了Parent,通过原型 var demo = new Child(); alert(demo.age); alert(demo.name);//得到被继承的属性
}
javascript创建对象简单的说,无非就是使用内置对象或各种自定义对象,当然还可以用JSON;但写法有很多种,也能混合使用。
1、对象字面量的方式
person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
2、用function来模拟无参的构造函数
function Person(){} var person=new Person();//定义一个function,如果使用new"实例化",该function可以看作是一个Class person.name="Mark"; person.age="25"; person.work=function(){ alert(person.name+" hello..."); } person.work();
3、用function来模拟参构造函数来实现(用this关键字定义构造的上下文属性)
function Pet(name,age,hobby){ this.name=name;//this作用域:当前对象 this.age=age; this.hobby=hobby; this.eat=function(){ alert("我叫"+this.name+",我喜欢"+this.hobby+",是个程序员"); } } var maidou =new Pet("麦兜",25,"coding");//实例化、创建对象 maidou.eat();//调用eat方法
4、用工厂方式来创建(内置对象)
var wcDog =new Object(); wcDog.name="旺财"; wcDog.age=3; wcDog.work=function(){ alert("我是"+wcDog.name+",汪汪汪......"); } wcDog.work();
5、用原型方式来创建
function Dog(){ } Dog.prototype.name="旺财"; Dog.prototype.eat=function(){ alert(this.name+"是个吃货"); } var wangcai =new Dog(); wangcai.eat();
6、用混合方式来创建
function Car(name,price){ this.name=name; this.price=price; } Car.prototype.sell=function(){ alert("我是"+this.name+",我现在卖"+this.price+"万元"); } var camry =new Car("凯美瑞",27); camry.sell();
Virtual DOM 可以理解为一个简单的JS对象,并且最少包含标签名( tag)、属性(attrs)和子元素对象( children)三个属性。
优势:
1、具备跨平台的优势-由于 Virtual DOM 是以 JavaScript 对象为基础而不依赖真实平台环境,所以使它具有了跨平台的能力,比如说浏览器平台、Weex、Node 等。
2、提升渲染性能-Virtual DOM的优势不在于单次的操作,而是在大量、频繁的数据更新下,能够对视图进行合理、高效的更新。 为了实现高效的DOM操作,一套高效的虚拟DOM diff算法显得很有必要。通过找出本次DOM需要更新的节点来更新,其他的不更新。 3、是一个js对象,存储在内存中。
如果依赖其他脚本和 DOM 结果,使用 defer
如果与 DOM 和其他脚本依赖不强时,使用 async
主要分成两部分:渲染引擎(layout engineer或Rendering Engine)和JS引擎。
渲染引擎:负责取得网页的内容(HTML、XML、图像等等)、整理讯息(例如加入CSS等),以及计算网页的显示方式,然后会输出至显示器或打印机。浏览器的内核的不同对于网页的语法解释会有不同,所以渲染的效果也不相同。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要内核。
JS引擎则:解析和执行javascript来实现网页的动态效果。
最开始渲染引擎和JS引擎并没有区分的很明确,后来JS引擎越来越独立,内核就倾向于只指渲染引擎。
常见的浏览器内核有哪些?
Trident内核:IE,MaxThon,TT,The World,360,搜狗浏览器等。[又称MSHTML] Gecko内核:Netscape6及以上版本,FF,MozillaSuite/SeaMonkey等 Presto内核:Opera7及以上。 [Opera内核原为:Presto,现为:Blink;] Webkit内核:Safari,Chrome等。 [ Chrome的:Blink(WebKit的分支)]
ES6中新增加了两个重要的 JavaScript 关键字: let 和 const
let 声明的变量只在 let 命令所在的代码块内有效
const 声明一个只读的常量,一旦声明,常量的值就不能改变
var,let,const区别
let
let 是在代码块内有效,var 是在全局范围内有效
let 只能声明一次 var 可以声明多次
let 不存在变量提升,var 会变量提升
const 声明一个只读变量,声明之后不允许改变。意味着,一旦声明必须初始化,否则会报错。
暂时性死区
ES6规定,let/const
命令会使区块形成封闭的作用域。若在声明之前使用变量,就会报错。总之,在代码块内,使用 let
命令声明变量之前,该变量都是不可用的。 这在语法上,称为 “暂时性死区”
this指向
this指向实例场景
全局环境
普通函数调用
由call/apply/bind函数调用
对象属性方法调用
构造函数调用
箭头函数
指向
在全局环境中无论是否是严格模式,this 均指向全局对象,例如浏览器端的 window
当普通的函数,直接调用的时候,一般来说分两种情况:
严格模式绑定到 undefined
非严格模式绑定到全局对象 window
call/apply 这两个函数对象到方法能立即执行某个函数,并且讲函数中的this绑定到你提供到对象上去
bind 方法永久的绑定函数中的this到指定对象上,并返回一个新函数,将来这个函数无论怎么调用都可以
作为对象属性方法调用,都指向前面调用函数都那个对象
构造函数作为JavaScript创建对象的构造函数,这种方式调用this指向的是你new出来的那个对象实例本身
箭头函数体内的this对象,就是定义时所在的对象,而不是使用时所在的对象。
new 操作符调用构造函数,具体做了什么?
创建一个新的对象;
将构造函数的 this 指向这个新对象;
为这个对象添加属性、方法等;
最终返回新对象。
bind,call,apply
apply、call、bind三者的区别在于:
三者都可以改变函数的this对象指向 三者第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或null,则默认指向全局window 三者都可以传参,但是apply是数组,而call是参数列表,且apply和call是一次性传入参数,而bind可以分为多次传入 bind是返回绑定this之后的函数,apply、call 则是立即执行
ES6 之前用来展开数组调用, foo.appy(null, [])
,ES6 之后使用 ... 操作符
注意事项
call和apply功能几乎一致,唯一的区别就是传参的方式!!
call和apply的第一个参数如果为null或者undefined,那么this指向window
call和apply的第一个参数如果为值类型的数据,那么会将这个值类型的数据,转换成其对应的引用类型的数据,然后再将this指向这个引用类型的数据
call和apply立即执行这个函数,bind方法可以让对应的函数想什么时候调就什么时候调用,并且可以将参数在执行的时候添加,这是它们的区别,根据自己的实际情况来选择使用。
当参数的个数确定的情况下可以使用call;当参数的个数不确定的情况下可以使用apply
WeakMap和Map之间的区别?
WeakMap只能以复杂数据类型作为key,并且key值是弱引用,对于垃圾回收更加友好
Set:
成员唯一、无序且不重复。
[value, value],键值与键名是一致的(或者说只有键值,没有键名)。
可以遍历,方法有:add、delete、has。
WeakSet:
成员都是对象。
成员都是弱引用,可以被垃圾回收机制回收,可以用来保存DOM节点,不容易造成内存泄漏。
不能遍历,方法有add、delete、has。
Map:
本质上是键值对的集合,类似集合。
可以遍历,方法很多可以跟各种数据格式转换。
WeakMap:
只接受对象作为键名(null除外),不接受其他类型的值作为键名。
键名是弱引用,键值可以是任意的,键名所指向的对象可以被垃圾回收,此时键名是无效的。
不能遍历,方法有get、set、has、delete。
Symbol
是 ES6
新推出的一种基本类型,它表示独一无二的值
Symbol
有两个方法:
Symbol.for()
Symbol.for()
定义的值会先检查给定的描述是否已经存在,如果不存在才会新建一个值,否则描述相同则他们就是同一个值
Symbol.keyFor()
Symbol.keyFor()
是用来检测该字符串参数作为名称的 Symbol
值是否已被登记,返回一个已登记的 Symbol
类型值的key
概念 Promise是 js 进行异步编辑的新的解决方案(旧的方式:纯回调的形式)
Promise构造函数接受一个函数作为参数,该函数的两个参数分别是resolve和reject。
resolve函数的作用,将Promise对象的状态从“未完成”变成“成功”(即从Pending变为Resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;
reject函数的作用是,在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。
then 方法接收两个函数作为参数,第一个参数是 Promise 执行成功时的回调,第二个参数是 Promise 执行失败时的回调,两个函数只会有一个被调用。
Promise对象除了then方法,还有一个catch方法.它和then的第二个参数一样,用来指定reject的回调
Promise优点
统一异步 API
Promise 的一个重要优点是它将逐渐被用作浏览器的异步 API ,统一现在各种各样的 API ,以及不兼容的模式和手法。
Promise 与事件对比
和事件相比较, Promise 更适合处理一次性的结果。在结果计算出来之前或之后注册回调函数都是可以的,都可以拿到正确的值。 Promise 的这个优点很自然。但是,不能使用 Promise 处理多次触发的事件。链式处理是 Promise 的又一优点,但是事件却不能这样链式处理。
Promise 与回调对比
解决了回调地狱的问题,将异步操作以同步操作的流程表达出来。
Promise 带来的额外好处是包含了更好的错误处理方式(包含了异常处理),并且写起来很轻松(因为可以重用一些同步的工具,比如 Array.prototype.map() )。
Promise缺点
无法取消Promise,一旦新建它就会立即执行,无法中途取消。
如果不设置回调函数,Promise内部抛出的错误,不会反应到外部。
当处于Pending状态时,无法得知目前进展到哪一个阶段(刚刚开始还是即将完成)。
Promise 真正执行回调的时候,定义 Promise 那部分实际上已经走完了,所以 Promise 的报错堆栈上下文不太友好。
1 指定的回调函数的方式更加灵活
旧:必须要启动异步任务前指定
promise 启动异步任务=>返回 promise对象=>给promise对象
绑定回调函数(甚至可以在异步结束后指定/多个)
2 promise 支持链式调用。可以解决回调地狱问题
什么是回调地狱 回调函数嵌套调用,外部回调函异步执行的结果是嵌套的
回调函数执行条件
回调地狱的缺点?不便于阅读/不便于异常处理
解决方案 promise 链式调用
错误回调:异常传透
then 是原型对象方法
new Promise 是实例对象方法
Promise.all promise函数对象方法
async 函数是 Generator 函数的语法糖。使用 关键字 async 来表示,在函数内部使用await 表明当前函数是异步函数 不会阻塞线程导致后续代码停止运行。
await意思是async wait(异步等待)。这个关键字只能在使用async定义的函数里面使用。任何async函数都会默认返回promise,并且这个promise解析的值都将会是这个函数的返回值,而async函数必须等到内部所有的 await 命令的 Promise 对象执行完,才会发生状态改变
箭头函数是匿名函数,不能作为构造函数,不能使用new
箭头函数不绑定arguments,取而代之用rest参数...解决
箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值
箭头函数通过call()或apply()方法调用一个函数时,只传入了一个参数,对 this 并没有影响
箭头函数没有原型属性
普通函数通过 function 关键字定义, this 无法结合词法作用域使用,在运行时绑定,只取决于函数的调用方式,在哪里被调用,调用位置。(取决于调用者,和是否独立运行)
箭头函数使用被称为 “胖箭头” 的操作 =>
定义,箭头函数不应用普通函数 this 绑定的四种规则,而是根据外层(函数或全局)的作用域来决定 this,且箭头函数的绑定无法被修改(new 也不行)。
箭头函数常用于回调函数中,包括事件处理器或定时器
箭头函数和 var self = this,都试图取代传统的 this 运行机制,将 this 的绑定拉回到词法作用域
没有原型、没有 this、没有 super,没有 arguments,没有 new.target
不能通过 new 关键字调用
一个函数内部有两个方法:[[Call]] 和 [[Construct]],在通过 new 进行函数调用时,会执行 [[construct]] 方法,创建一个实例对象,然后再执行这个函数体,将函数的 this 绑定在这个实例对象上
当直接调用时,执行 [[Call]] 方法,直接执行函数体
箭头函数没有 [[Construct]] 方法,不能被用作构造函数调用,当使用 new 进行函数调用时会报错。
同步:浏览器访问服务器请求,用户看得到页面刷新,重新发请求,等请求完,页面刷新,新内容出现,用户看到新内容,j进行下一步操作。
异步:浏览器访问服务器请求,用户正常操作,浏览器后端进行请求。等请求完,页面不刷新,新内容也会出现,用户看到新内容。
get参数通过url传递,post放在request body中。
get请求在url中传递的参数是有长度限制的,而post没有。
get比post更不安全,因为参数直接暴露在url中,所以不能用来传递敏感信息。
get请求只能进行url编码,而post支持多种编码方式
get请求会浏览器主动cache,而post支持多种编码方式。
get请求参数会被完整保留在浏览历史记录里,而post中的参数不会被保留。
GET和POST本质上就是TCP链接,并无差别。但是由于HTTP的规定和浏览器/服务器的限制,导致他们在应用过程中体现出一些不同。
GET产生一个TCP数据包;POST产生两个TCP数据包。
跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。
解决跨域
jsonp:只支持 GET,不支持 POST 请求,不安全 XSS
cors:需要后台配合进行相关的设置
postMessage:配合使用 iframe,需要兼容 IE6、7、8、9
document.domain:仅限于同一域名下的子域
websocket:需要后台配合修改协议,不兼容,需要使用 http://socket.io
proxy:使用代理去避开跨域请求,需要修改 nginx、apache 等的配置
同源策略
同源策略指的是:协议+域名+端口三者皆相同,可以视为在同一个域,否则为不同域。同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。
作用是一个用于隔离潜在恶意文件的重要安全机制。
所限制的跨域交互包括:
Cookie、LocalStorage、IndexdDB 等存储内容;
DOM 节点;
Ajax 请求。
Ajax 为什么不能跨域
Ajax 其实就是向服务器发送一个 GET 或 POST 请求,然后取得服务器响应结果,返回客户端。Ajax 跨域请求,在服务器端不会有任何问题,只是服务端响应数据返回给浏览器的时候,浏览器根据响应头的Access-Control-Allow-Origin
字段的值来判断是否有权限获取数据。
因此,服务端如果没有设置跨域字段设置,跨域是没有权限访问,数据被浏览器给拦截了。
所以,要解决的问题是:如何从客户端拿到返回的数据?
其实,在同源策略的基础上,选择性地为同源策略开放了一些后门。例如 img、script、style 等标签,都允许跨域引用资源。
JSONP 实现
只支持GET请求,不支持POST等其它请求,也不支持复杂请求,只支持简单请求。
JSONP 缺点
只支持 GET 请求
只支持跨域 HTTP 请求这种情况,不能解决不同域的两个页面之间如何进行 JavaScript 调用的问题
调用失败的时候不会返回各种 HTTP 状态码。
安全性,万一假如提供 JSONP 的服务存在页面注入漏洞,即它返回的 javascript 的内容被人控制的。
跨域资源共享 CORS
支持所有的请求,包含GET、POST、OPTOIN、PUT、DELETE等。既支持复杂请求,也支持简单请求。
JSONP和CORS跨域理解
JSONP与CORS的使用目的相同,并且都需要服务端和客户端同时支持,但CORS的功能更加强大。
SONP和CORS的优缺点
JSONP的主要优势在于对浏览器的支持较好;虽然目前主流浏览器都支持CORS,但IE9及以下不支持CORS。
JSONP只能用于获取资源(即只读,类似于GET请求);CORS支持所有类型的HTTP请求,功能完善。JSONP的错误处理机制并不完善,我们没办法进行错误处理;而CORS可以通过onerror事件监听错误,并且浏览器控制台会看到报错信息,利于排查。
JSONP只会发一次请求;而对于复杂请求,CORS会发两次请求。
始终觉得安全性这个东西是相对的,没有绝对的安全,也做不到绝对的安全。毕竟JSONP并不是跨域规范,它存在很明显的安全问题:callback参数注入和资源访问授权设置。CORS好歹也算是个跨域规范,在资源访问授权方面进行了限制(Access-Control-Allow-Origin),而且标准浏览器都做了安全限制,比如拒绝手动设置origin字段,相对来说是安全了一点。但是回过头来看一下,就算是不安全的JSONP,我们依然可以在服务端端进行一些权限的限制,服务端和客户端也都依然可以做一些注入的安全处理,哪怕被攻克,它也只能读一些东西。就算是比较安全的CORS,同样可以在服务端设置出现漏洞或者不在浏览器的跨域限制环境下进行攻击,而且它不仅可以读,还可以写。
应用场景
如果需要兼容IE低版本浏览器,无疑,JSONP。 如果需要对服务端资源进行操作,无疑,CORS。
缓存分为两种:强缓存和协商缓存,根据响应的header内容来决定。
强缓存相关字段有expires,cache-control。如果cache-control与expires同时存在的话,cache-control的优先级高于expires。
协商缓存相关字段有Last-Modified/If-Modified-Since,Etag/If-None-Match
原生ajax的请求步骤
//创建 XMLHttpRequest 对象 var ajax = new XMLHttpRequest(); //规定请求的类型、URL 以及是否异步处理请求。 ajax.open('GET',url,true); //发送信息至服务器时内容编码类型 ajax.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //发送请求 ajax.send(null); //接受服务器响应数据 ajax.onreadystatechange = function () { if (obj.readyState == 4 && (obj.status == 200 || obj.status == 304)) { } };
ajax
使用步骤
创建 XmlHttpRequest 对象
调用 open 方法设置基本请求信息
设置发送的数据,发送请求
注册监听的回调函数
拿到返回值,对页面进行更新
2, axios
Axios 是一个基于 promise 的 HTTP库,可以再浏览器和Node.js中使用。
特性
从浏览器中创建XMLHttpRequests
从Node.js创建 http 请求
支持Promise API
拦截请求和响应
转换请求数据和相应数据
取消请求
自动转换JSON数据
客户端支持防御 XSRF
优缺点:
从 node.js 创建 http请求
支持Promise API
客户端支持防止CSRF
提供了一些并发请求的接口
fetch
Fetch API提供了一个JavaScript 接口,用于访问和操纵HTTP 管道的部分,例如请求和响应。
它提供了一个全局的fetch()
方法,该方法提供了一种简单,合理的方式来跨网络以不获取资源。 fetch 是一种 HTTP 数据请求方式,是 XMLHTTPRequest 的一种替代方案。 fetch 不是 ajax 的进一步封装,而是原生 js。 Fetch 函数就是原生 js。
优缺点:
符合关注分离,没有将输入、输出和用事件来跟踪的状态混在一个对象里。
更加底层,提供了API丰富(request、response)
脱离了XHR,是ES规范里新的实现方式
fetch 只对网络请求报错,对400/500 都当成功的请求,需要封装去处理
fetch 默认不会带cookie,需要添加配置项
fetch不支持abort,不支持超时控制,使用setTimeout 及 Promise.reject 的实现的超时控制并不能阻止请求过程继续在后台运行,造成了量的浪费
fetch没有办法原生检测请求的进度,而XHR可以
XSS攻击的防范
1、HttpOnly 防止劫取 Cookie 2、输入检查-不要相信用户的所有输入 3、输出检查-存的时候转义或者编码
CSRF攻击的防范
1、验证码 2、Referer Check 3、添加token验证
1、输入地址
2、浏览器查找域名的 IP 地址
3、浏览器向 web 服务器发送一个 HTTP 请求
4、服务器的永久重定向响应
6、服务器处理请求
7、服务器返回一个 HTTP 响应
8、浏览器显示 HTML
9、浏览器发送请求获取嵌入在 HTML 中的资源(如图片、音频、视频、CSS、JS等等)
基本概念:
HTTP,全称为 HyperText Transfer Protocol,即为超文本传输协议。是互联网应用最为广泛的一种网络协议 所有的 www 文件都必须遵守这个标准。
http特性:
HTTP 是无连接无状态的 HTTP 一般构建于 TCP/IP 协议之上,默认端口号是 80 HTTP 可以分为两个部分,即请求和响应。
http请求:
HTTP 定义了在与服务器交互的不同方式,最常用的方法有 4 种 分别是 GET,POST,PUT, DELETE。URL 全称为资源描述符,可以这么认为:一个 URL 地址 对应着一个网络上的资源,而 HTTP 中的 GET,POST,PUT,DELETE 就对应着对这个资源的查询,修改,增添,删除4个操作。
HTTP 请求由 3 个部分构成,分别是:状态行,请求头(Request Header),请求正文。
HTTP 响应由 3 个部分构成,分别是:状态行,响应头(Response Header),响应正文。
HTTP 响应中包含一个状态码,用来表示服务器对客户端响应的结果。 状态码一般由3位构成:
1xx : 表示请求已经接受了,继续处理。 2xx : 表示请求已经处理掉了。 3xx : 重定向。 4xx : 一般表示客户端有错误,请求无法实现。 5xx : 一般为服务器端的错误。
比如常见的状态码:
200 OK 客户端请求成功。 301 Moved Permanently 请求永久重定向。 302 Moved Temporarily 请求临时重定向。 304 Not Modified 文件未修改,可以直接使用缓存的文件。 400 Bad Request 由于客户端请求有语法错误,不能被服务器所理解。 401 Unauthorized 请求未经授权,无法访问。 403 Forbidden 服务器收到请求,但是拒绝提供服务。服务器通常会在响应正文中给出不提供服务的原因。 404 Not Found 请求的资源不存在,比如输入了错误的URL。 500 Internal Server Error 服务器发生不可预期的错误,导致无法完成客户端的请求。 503 Service Unavailable 服务器当前不能够处理客户端的请求,在一段时间之后,服务器可能会恢复正常。
应用层:向用户提供服务,处理特定的细节,比如:文件传输,DNS服务,HTTP等
传输层:为两台主机上的应用程序提供端到端的通信,主要分为TCP和UDP两种通讯方式
tcp是一种可靠的传输协议,需要经过三次握手确保双方可以正常通讯,此外还有切包,超时重传、发送和接收端到端的确认分组等机制。
udp是不可靠的传输协议,所以需要应用层来保证可靠性
网络层:在众多的选项内选择一条传输路线。依赖mac地址
链路层:处理连接网络的硬件部分
get:获取
post:传给服务器
put:传输文件,http1.1不带验证机制
head:和get类似,只是不返回主体部分,用于确认uri的有效性
delete:用于删除文件,http1.1不带验证机制
options:询问支持的方法
cookie是网站为了标示用户身份而储存在用户本地终端(Client Side)上的数据(通常经过加密)。 cookie数据始终在同源的http请求中携带(即使不需要),记会在浏览器和服务器间来回传递。 sessionStorage和localStorage不会自动把数据发给服务器,仅在本地保存。
存储大小: cookie数据大小不能超过4k。 sessionStorage和localStorage 虽然也有存储大小的限制,但比cookie大得多,可以达到5M或更大。
有期时间: localStorage 存储持久数据,浏览器关闭后数据不丢失除非主动删除数据; sessionStorage 数据在当前浏览器窗口关闭后自动删除。 cookie 设置的cookie过期时间之前一直有效,即使窗口或浏览器关闭
HTTPS是在HTTP上建立SSL加密层,并对传输数据进行加密,是HTTP协议的安全版。现在它被广泛用于万维网上安全敏感的通讯,例如交易支付方面。
HTTPS主要作用是:
(1)对数据进行加密,并建立一个信息安全通道,来保证传输过程中的数据安全;
(2)对网站服务器进行真实身份认证。
HTTPS比HTTP更加安全,对搜索引擎更友好,利于SEO,谷歌、百度优先索引HTTPS网页;
HTTPS需要用到SSL证书,而HTTP不用;
HTTPS标准端口443,HTTP标准端口80;
HTTPS基于传输层,HTTP基于应用层;
HTTPS在浏览器显示绿色安全锁,HTTP没有显示;
SPA( single-page application )仅在 Web 页面初始化时加载相应的 HTML、JavaScript 和 CSS。一旦页面加载完成,SPA 不会因为用户的操作而进行页面的重新加载或跳转;取而代之的是利用路由机制实现 HTML 内容的变换,UI 与用户的交互,避免页面的重新加载。
优点:
用户体验好、快,内容的改变不需要重新加载整个页面,避免了不必要的跳转和重复渲染;
基于上面一点,SPA 相对对服务器压力小;
前后端职责分离,架构清晰,前端进行交互逻辑,后端负责数据处理;
缺点:
初次加载耗时多:为实现单页 Web 应用功能及显示效果,需要在加载页面的时候将 JavaScript、CSS 统一加载,部分页面按需加载;
前进后退路由管理:由于单页应用在一个页面中显示所有的内容,所以不能使用浏览器的前进后退功能,所有的页面切换需要自己建立堆栈管理;
SEO 难度较大:由于所有的内容都在一个页面中动态替换显示,所以在 SEO 上其有着天然的弱势。
父级 prop 的更新会向下流动到子组件中,每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值
computed: 是计算属性,依赖其它属性值,并且 computed 的值有缓存,只有它依赖的属性值发生改变,下一次获取 computed 的值时才会重新计算 computed 的值;
watch: 更多的是「观察」的作用,类似于某些数据的监听回调 ,每当监听的数据变化时都会执行回调进行后续操作;
运用场景:
当我们需要进行数值计算,并且依赖于其它数据时,应该使用 computed,因为可以利用 computed 的缓存特性,避免每次获取值时,都要重新计算;
当我们需要在数据变化时执行异步或开销较大的操作时,应该使用 watch,使用 watch 选项允许我们执行异步操作 ( 访问一个 API ),限制我们执行该操作的频率,并在我们得到最终结果前,设置中间状态。这些都是计算属性无法做到的。
(1)生命周期是什么?
Vue 实例有一个完整的生命周期,也就是从开始创建、初始化数据、编译模版、挂载 Dom -> 渲染、更新 -> 渲染、卸载等一系列过程,我们称这是 Vue 的生命周期。
(2)各个生命周期的作用
Vue生命周期总共可以分为8个阶段:创建前后, 载入前后,更新前后,销毁前销毁后,以及一些特殊场景的生命周期
生命周期 | 描述 |
---|---|
beforeCreate | 组件实例被创建之初,组件的属性生效之前 |
created | 组件实例已经完全创建,属性也绑定,但真实 dom 还没有生成,$el 还不可用 |
beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用 |
mounted | el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子 |
beforeUpdate | 组件数据更新之前调用,发生在虚拟 DOM 打补丁之前 |
update | 组件数据更新之后 |
activited | keep-alive 专属,组件被激活时调用 |
deactivated | keep-alive 专属,组件被销毁时调用 |
beforeDestory | 组件销毁前调用 |
destoryed | 组件销毁后调用 |
小程序,uni-app: 1. onLoad:首次进入页面加载时触发,可以在 onLoad 的参数中获取打开当前页面路径中的参数。 2. onShow:加载完成后、后台切到前台或重新进入页面时触发 3. onReady:页面首次渲染完成时触发 4. onHide:从前台切到后台或进入其他页面触发 5. onUnload:页面卸载时触发 6. onPullDownRefresh:监听用户下拉动作 7. onReachBottom:页面上拉触底事件的处理函数 8. onShareAppMessage:用户点击右上角转发
jq传参 rl拼接参数进行传参。
vue传参 可以通过标签router-link跳转传参,通过path+路径,query+参数, 也可以通过事件里的this.$router.push({ })跳转传参
小程序传参 转路径后面拼接参数来进行跳转传参
vue中组件是用来复用的,为了防止data复用,将其定义为函数。
我们将组件中的data写成一个函数,数据以函数返回值形式定义,这样每复用一次组件,就会返回一份新的data,拥有自己的作用域,类似于给每个组件实例创建一个私有的数据空间,让各个组件实例维护各自的数据。
当我们组件的date单纯的写成对象形式,这些实例用的是同一个构造函数,由于JavaScript的特性所导致,所有的组件实例共用了一个data,就会造成一个变了全都会变的结果
使用 key
来给每个节点做一个唯一标识, Diff
算法就可以正确的识别此节点。作用主要是为了高效的更新虚拟 DOM。
v-model 本质上是语法糖,v-model 在内部为不同的输入元素使用不同的属性并抛出不同的事件:
text 和 textarea 元素使用 value 属性和 input 事件;
checkbox 和 radio 使用 checked 属性和 change 事件;
select 字段将 value 作为 prop 并将 change 作为事件。
双向数据绑定是基于Object.defineProperty()重新定义get和set方法实现的。修改触发set方法赋值,获取触发get方法取值,并通过数据劫持发布信息。
v-if 是真正的条件渲染,因为它会确保在切换过程中条件块内的事件监听器和子组件适当地被销毁和重建;也是惰性的:如果在初始渲染时条件为假,则什么也不做——直到条件第一次变为真时,才会开始渲染条件块。
v-show 就简单得多——不管初始条件是什么,元素总是会被渲染,并且只是简单地基于 CSS 的 “display” 属性进行切换。
所以,v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景;v-show 则适用于需要非常频繁切换条件的场景。
v-for比v-if优先级高,意味着如果两个指令同时使用,会先循环后判断,会造成资源浪费
.stop
:等同于 JavaScript 中的 event.stopPropagation()
,防止事件冒泡;
.prevent
:等同于 JavaScript 中的 event.preventDefault()
,防止执行预设的行为(如果事件可取消,则取消该事件,而不停止事件的进一步传播);
.capture
:与事件冒泡的方向相反,事件捕获由外到内;
.self
:只会触发自己范围内的事件,不包含子元素;
.once
:只会触发一次。
用法:query要用path来引入,params要用name来引入,接收参数都是类似的,分别是 this.$route.query.name
和 this.$route.params.name
。url地址显示:query更加类似于我们ajax中get传参,params则类似于post,说的再简单一点,前者在浏览器地址栏中显示参数,后者则不显示
注意点:query刷新不会丢失query里面的数据 params刷新 会 丢失 params里面的数据。
$route
和 $router
区别
$router
是VueRouter的实例,在script标签中想要导航到不同的URL,使用 $router.push
方法。返回上一个历史history用 $router.to(-1)
$route
为当前router跳转对象。里面可以获取当前路由的name,path,query,parmas等。
Vue通信
通过 props 传递
适用场景:父组件传递数据给子组件
子组件设置props
属性,定义接收父组件传递过来的参数
父组件在使用子组件标签中通过字面量来传递值
通过 $emit 触发自定义事件
适用场景:子组件传递数据给父组件
子组件通过$emit触发
自定义事件,$emit
第二个参数为传递的数值
父组件绑定监听器获取到子组件传递过来的参数
使用 ref
父组件在使用子组件的时候设置ref
父组件通过设置子组件ref
来获取数据
EventBus
使用场景:兄弟组件传值
创建一个中央时间总线EventBus
兄弟组件通过$emit
触发自定义事件,$emit
第二个参数为传递的数值
另一个兄弟组件通过$on
监听自定义事件
$parent
或 $root
通过共同祖辈$parent
或者$root
搭建通信侨联
$attrs 与 $listeners
适用场景:祖先传递数据给子孙
设置批量向下传属性$attrs
和 $listeners
包含了父级作用域中不作为 prop
被识别 (且获取) 的特性绑定 ( class 和 style 除外)。
可以通过 v-bind="$attrs"
传⼊内部组件
Provide 与 Inject
在祖先组件定义provide
属性,返回传递的值
在后代组件通过inject
接收组件传递过来的值
Vuex
适用场景: 复杂关系的组件数据传递
Vuex
作用相当于一个用来存储共享变量的容器
Vue路由守卫有哪些,怎么设置,使用场景
常用的两个路由守卫:router.beforeEach 和 router.afterEach
每个守卫方法接收三个参数:
to: Route: 即将要进入的目标 路由对象
from: Route: 当前导航正要离开的路由
next: Function: 一定要调用该方法来 resolve 这个钩子。
在项目中,一般在beforeEach这个钩子函数中进行路由跳转的一些信息判断。 判断是否登录,是否拿到对应的路由权限等等。
组件中的name
项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
DOM 做递归组件时需要调用自身 name
vue-devtools 调试工具里显示的组见名称是由vue中组件name决定的
vue-router 路由模式
abstract : 支持所有 JavaScript 运行环境,如 Node.js 服务器端。如果发现没有浏览器的 API,路由会自动强制进入这个模式.
hash模式: 即地址栏 URL 中的 # 符号;
history模式: window.history对象打印出来可以看到里边提供的方法和记录长度。利用了 HTML5 History Interface 中新增的 pushState() 和 replaceState() 方法。(需要特定浏览器支持)。
history与hash路由的区别
hash前端路由,无刷新,history 会去请求接口
hash :hash 虽然出现在 URL 中,但不会被包含在 http 请求中,对后端完全没有影响,因此改变 hash 不会重新加载页面。
history :history 利用了 html5 history interface 中新增的 pushState() 和 replaceState() 方法。这两个方法应用于浏览器记录栈,在当前已有的 back、forward、go 基础之上,它们提供了对历史记录修改的功能。只是当它们执行修改时,虽然改变了当前的 URL ,但浏览器不会立即向后端发送请求。
hash模式:在 url 中的 # 之后对应的是 hash 值, 其原理是通过hashChange() 事件监听hash值的变化, 根据路由表对应的hash值来判断加载对应的路由加载对应的组件
优点:
只需要前端配置路由表, 不需要后端的参与
兼容性好, 浏览器都能支持
hash值改变不会向后端发送请求, 完全属于前端路由
缺点:
hash值前面需要加#, 不符合url规范,也不美观
history模式: history运用了浏览器的历史记录栈,之前有back,forward,go方法,之后在HTML5中新增了pushState()和replaceState()方法,它们提供了对历史记录进行修改的功能,不过在进行修改时,虽然改变了当前的URL,但是浏览器不会马上向后端发送请求。
优点: 符合url地址规范, 不需要#, 使用起来比较美观
缺点:
在用户手动输入地址或刷新页面时会发起url请求, 后端需要配置index.html页面用户匹配不到静态资源的情况, 否则会出现404错误
兼容性比较差, 是利用了 HTML5 History对象中新增的 pushState() 和 replaceState() 方法,需要特定浏览器的支持.
实现的原理:
hash 模式的原理是 onhashchange 事件,可以在 window 对象上监听这个事件。
history :hashchange 只能改变 # 后面的代码片段,history api (pushState、replaceState、go、back、forward) 则给了前端完全的自由,通过在window对象上监听popState()事件。
导航守卫
全局前置守卫 router.beforeEach
全局解析守卫 router.beforeResolve
全局后置钩子 router.beforeResolve
路由独享守卫 beforeEnter
组件内的守卫
beforeRouteEnter
beforeRouteUpdate
(2.2 新增)
beforeRouteLeave
完整的导航守卫流程
导航被触发。
在准备离开的组件里调用 beforeRouteLeave 守卫。
调用全局的 beforeEach 守卫。
在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。(如果你的组件是重用的)
在路由配置里调用 beforeEnter。
解析即将抵达的组件。
在即将抵达的组件里调用 beforeRouteEnter。
调用全局的 beforeResolve 守卫 (2.5+)。
导航被确认。
调用全局的 afterEach 钩子。
触发 DOM 更新。
用创建好的实例调用 beforeRouteEnter 守卫中传给 next 的回调函数。
导航守卫的三个参数的含义
to:即将要进入的目标 路由对象。
from:当前导航正要离开的路由对象。
next()
:进入下一个路由。
next(false)
:中断当前的导航。
next('/')
或next({ path: '/' })
: 跳转到其他路由,当前导航被中断,进行新的一个导航。
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。简单来说就是:应用遇到多个组件共享状态时,使用vuex。
场景:多个组件共享数据或者是跨组件传递数据时
vuex的流程
页面通过mapAction异步提交事件到action。action通过commit把对应参数同步提交到mutation,mutation会修改state中对应的值。最后通过getter把对应值跑出去,在页面的计算属性中,通过,mapGetter来动态获取state中的值
vuex有哪几种属性
有五种,分别是State , Getter , Mutation , Action , Module (就是mapAction)
state:vuex的基本数据,用来存储变量
geeter:从基本数据(state)派生的数据,相当于state的计算属性
mutation:提交更新数据的方法,必须是同步的(如果需要异步使用action)。每个mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。
action:和mutation的功能大致相同,不同之处在于 ==》1. Action 提交的是 mutation,而不是直接变更状态。 2. Action 可以包含任意异步操作。
modules:模块化vuex,可以让每一个模块拥有自己的state、mutation、action、getters,使得结构非常清晰,方便管理。
vuex的优点
1.解决了非父子组件的消息传递(将数据存放在state中)
2.减少了AJAX请求次数,有些情景可以直接从内存中的state获取
vuex的缺点
1.刷新浏览器,vuex中的state会重新变为初始状态
解决方案vuex-along ,vuex-persistedstate
https://github.com/robinvdvleuten/vuex-persistedstate
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染
一般结合路由和动态组件一起使用,用于缓存组件;
提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。
处理数据动态变化后,dom还未及时更新的问题。$nextTick就可以获取到数据更新后最新的dom变化
代码层面:
合理使用 v-if
和 v-show
区分 computed
和 watch
的使用
v-for
遍历为 item
添加 key
v-for
遍历避免同时使用 v-if
通过 addEventListener
添加的事件在组件销毁时要用 removeEventListener
手动移除这些事件的监听
图片懒加载
路由懒加载
第三方插件按需引入
SSR
服务端渲染,首屏加载速度快,SEO
效果好
Webpack 层面优化:
对图片进行压缩
使用 CommonsChunkPlugin
插件提取公共代码
提取组件的 CSS
优化 SourceMap
构建结果输出分析,利用 webpack-bundle-analyzer
可视化分析工具
前端方面: 1、路由懒加载 2、图片,资源放cdn 3、页面图片较多进行懒加载 4、骨架屏方案 5、采用服务端渲染---nuxt.js 服务器端: 开启gzip
Vue.js 是构建客户端应用程序的框架。默认情况下,可以在浏览器中输出 Vue 组件,进行生成 DOM 和操作 DOM。然而,也可以将同一个组件渲染为服务端的 HTML 字符串,将它们直接发送到浏览器,最后将这些静态标记"激活"为客户端上完全可交互的应用程序。
即:SSR大致的意思就是vue在客户端将标签渲染成的整个 html 片段的工作在服务端完成,服务端形成的html 片段直接返回给客户端这个过程就叫做服务端渲染。
前端工程化
1、将前端项目当成一项系统工程进行分析、组织和构建从而达到项目结构清晰、分工明确、团队配合默契、开发效率提高的目的 2、工程化思维就是“结构、样式和动作分离”。如目录分为assets,components,router,util
前端模块化
1、可以简单的认为模块化和组件化是工程化的表现形式 2、JS模块化方案很多有AMD/CommonJS/UMD/ES6 Module等,CSS模块化开发大多是在less、sass、stylus
前端组件化
1、组件化将页面视为一个容器,页面上各个独立部分例如:头部、导航、焦点图、侧边栏、底部等视为独立组件,不同的页面根据内容的需要,去盛放相关组件即可组成完整的页面。 2、模块化和组件化一个最直接的好处就是复用
jq
1、需要频繁操作dom 2、容易引起重绘和回流,影响页面性能
vue
1、mvvm模式,采用虚拟dom不需要频繁操作dom,通过双向绑定,用数据驱动页面变化,页面变化对应数据也发生变化,只需要关注数据层的业务逻辑,而无需关注视图层的更新。可以尽量减少无用的更新操作,提高dom渲染效率。 2、组件化开发,页面由若干个组建组成,可复用性高。 3、社区环境好,各类资源文档十分齐全。 4、通过Object.defineProperty() 方法,监控对数据的操作,从而可以自动触发数据同步。
react
1、虚拟dom。
2、一切都是组件,组件实例之间可以嵌套。 3、使用独特的jsx语法。
angular
1、AngularJS的学习成本高,比如增加了Dependency Injection特性,而Vue.js本身提供的API都比较简单、直观。 2、在性能上,AngularJS依赖对数据做脏检查,所以Watcher越多越慢。
1、Entry:入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。 2、Module:模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。 3、Chunk:代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。 4、Loader:模块转换器,用于把模块原内容按照需求转换成新内容。 5、Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。 6、Output:打包后文件输出的位置
jQuery是使用选择器( $
)选取DOM对象,对其进行赋值、取值、事件绑定等操作,其实和原生的HTML的区别只在于可以更方便的选取和操作DOM对象,而数据和界面是在一起的。比如需要获取label标签的内容:$("lable").val();
,它还是依赖DOM元素的值。Vue则是通过Vue对象将数据和View完全分离开来了。对数据进行操作不再需要引用相应的DOM对象,可以说数据和View是分离的,他们通过Vue对象这个vm实现相互的绑定。这就是传说中的MVVM。
px:实际上就是像素,用px设置字体大小时,比较稳定和精准。像素px是相对于显示器屏幕分辨率而言的。
rpx:微信小程序独有的、解决屏幕自适应的尺寸单位
em:就是根据基准来缩放字体大小em的值并不是固定的;em会根据父级元素的字体大小变化。em相对于浏览器的默认字体尺寸。
rem:是根据根元素字体大小变化,这样就意味着,我们只需要在根元素确定一个参考值。
vw/vh:viewpoint width / viewpoint height,vw 相对于视窗的宽度,vh 相对于视窗的高度,1vw等于视窗宽度的1%
百分比:1% 对不同属性有不同的含义。font-size: 200% 和font-size: 2em 一样,表示字体大小是默认(继承自父亲)字体大小的2倍。line-height: 200% 表示行高是自己字体大小的 2 倍。width: 100%表示自己 content 的宽度等于父亲 content 宽度的1倍。
rpx
rpx是微信小程序独有的、解决屏幕自适应的尺寸单位
可以根据屏幕宽度进行自适应,不论大小屏幕,规定屏幕宽为 750rpx
通过 rpx 设置元素和字体的大小,小程序在不同尺寸的屏幕下,可以实现自动适配
rpx 和 px之间的区别:
在普通网页开发中,最常用的像素单位是px
在小程序开发中,推荐使用 rpx 这种响应式的像素单位进行开发
rem
相对长度单位,CSS3 新增的一个相对单位,rem 是相对于根元素(html)的 font-size
进行计算,rem 不仅可设置字体大小,也可以设置元素宽高属性。
em
相对长度单位,em 是相对于当前元素的父元素的 font-size
进行计算,如果当前元素未设置则相对于浏览器的默认字体尺寸
px 与 rem 的区别:
px 对于只需要适配少量设备,且分辨率对页面影响不大的,使用 px 即可, px 设置更为精准 。
随着 rem 在众多的浏览器都得到支持,有需要考虑到对多设备,多分辨率的自适应,无疑这时候 rem 是最合适的(如:移动端的开发)。
vw/vh
CSS3 特性 vh 和 vw:
vh 相对于视窗的高度,视窗高度是100vh
vw 相对于视窗的宽度,视窗宽度是100vw
百分比
通常认为子元素的百分比完全相对于直接父元素
渲染引擎开始解析html,根据标签构建DOM节点
根据css样式构建渲染树,包括元素的大小、颜色,隐藏的元素不会被构建到该树中。
根据css样式构建布局树,主要是确定元素要显示的位置。
根据前面的信息,绘制渲染树。
常见的兼容性问题
不同浏览器的标签默认的外补丁( margin )和内补丁(padding)不同
解决方案: css 里增加通配符 * { margin: 0; padding: 0; }
IE6双边距问题;在 IE6中设置了float , 同时又设置margin , 就会出现边距问题
解决方案:设置display:inline;
当标签的高度设置小于10px,在IE6、IE7中会超出自己设置的高度
解决方案:超出高度的标签设置overflow:hidden,或者设置line-height的值小于你的设置高度
图片默认有间距
解决方案:使用float 为img 布局
IE9一下浏览器不能使用opacity
解决方案:opacity: 0.5;filter: alpha(opacity = 50);filter: progid:DXImageTransform.Microsoft.Alpha(style = 0, opacity = 50);
边距重叠问题;当相邻两个元素都设置了margin 边距时,margin 将取最大值,舍弃最小值;
解决方案:为了不让边重叠,可以给子元素增加一个父级元素,并设置父级元素为overflow:hidden;
cursor:hand 显示手型在safari 上不支持
解决方案:统一使用 cursor:pointer
两个块级元素,父元素设置了overflow:auto;子元素设置了position:relative ;且高度大于父元素,在IE6、IE7会被隐藏而不是溢出;
解决方案:父级元素设置position:relative
git init - 初始化仓库。
git add . - 添加文件到暂存区。
git commit - 将暂存区内容添加到仓库中。
git clone 拷贝一份远程仓库,也就是下载一个项目。
git remote 远程仓库操作
git pull 下载远程代码并合并
git push 上传远程代码并合并
git log 查看历史提交记录
查看工作区状况:git status –s
查看提交记录命令:git reflog
git branch 查看本地所有分支
git branch -r 列出所有远程分支
git branch -a 查看本地和远程的所有分支
git branch 分支名 创建新的分支,但不会切出到此分支
git checkout -b 分支名 创建并切出到创建的分支
git branch -d 分支名 删除指定分支
git push origin --delete 分支名 删除远程分支,删除后还需推送到服务器
git checkout 分支名 切换到指定的分支,指定分支必须已存在,否则会报错
git branch -m
git status 显示有变更的文件
Add命令:
将文件加入暂存区:git add 文件名
保存新的修改和新建到暂存区:git add .
保存新的修改或者删除到暂存区:git add -u
保存所有更改到暂存区:git add -A
查看日志:
查看所有提交记录:git log
查看提交记录详细信息:git log -p
展示自己提交的最近的那条日志:git log –oneline -n
Entry: 指定webpack开始构建的入口模块,从该模块开始构建并计算出直接或间接依赖的模块或者库。
Output:告诉webpack如何命名输出的文件以及输出的目录
Module: 模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
Chunk:coding split
的产物,我们可以对一些代码打包成一个单独的chunk
,比如某些公共模块,去重,更好的利用缓存。或者按需加载某些功能模块,优化加载时间。在webpack3
及以前我们都利用CommonsChunkPlugin
将一些公共代码分割成一个chunk
,实现单独加载。在webpack4
中CommonsChunkPlugin
被废弃,使用SplitChunksPlugin
Loader:模块转换器,用于把模块原内容按照需求转换成新内容。
Plugin:扩展插件,在 Webpack 构建流程中的特定时机会广播出对应的事件,插件可以监听这些事件的发生,在特定时机做对应的事情。
Webpack 的运行流程是一个串行的过程,从启动到结束会依次执行以下流程 :
初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数。
开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译。
确定入口:根据配置中的 entry 找出所有的入口文件。
编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理。
完成模块编译:在经过第 4 步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系。
输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会。
输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。
在以上过程中,Webpack 会在特定的时间点广播出特定的事件,插件在监听到感兴趣的事件后会执行特定的逻辑,并且插件可以调用 Webpack 提供的 API 改变 Webpack 的运行结果。
网站重构:在不改变外部行为的前提下,简化结构、添加可读性,而在网站前端保持一致的行为。 也就是说是在不改变UI的情况下,对网站进行优化,在扩展的同时保持一致的UI。
对于传统的网站来说重构通常是:
表格(table)布局改为DIV+CSS 使网站前端兼容于现代浏览器(针对于不合规范的CSS、如对IE6有效的) 对于移动平台的优化 针对于SEO进行优化 深层次的网站重构应该考虑的方面
减少代码间的耦合 让代码保持弹性 严格按规范编写代码 设计可扩展的API 代替旧有的框架、语言(如VB) 增强用户体验 通常来说对于速度的优化也包含在重构中
压缩JS、CSS、image等前端资源(通常是由服务器来解决) 程序的性能优化(如数据读写) 采用CDN来加速资源加载 对于JS DOM的优化 HTTP服务器的文件缓存
公司常用的技术栈是什么?
目前这个职位最紧要的任务是什么?
未来打算采用那哪些新技术?
当前团队的规模和配置是怎么样的?
公司技术团队的架构和人员组成?