HTML、CSS相关
HTML5新特性
input新增了一些属性:color-调色板、tel-电话、number-数字、date-年月日
video、aideo视音频标签
语义化标签
语义化
语义化标签 : header、nav、main、footer
语义化的优点有:
(一)代码结构清晰,易于阅读,利于开发和维护
(二)方便设备解析根据语义渲染网页
(三)有利于(SEO)搜索引擎优化
(四)在浏览器css失效时,页面依然可读
如何语义化:不用纯样式标签(b、i、u)、少用无语义标签(div、span)、使用语义化标签
盒模型
所有HTML元素都可以看做是一个作盒子,在CSS中,"box model"这一术语是用来设计和布局时使用。
W3C盒子模型(标准盒子模型):宽=内部宽度(content)+border+padding+margin
IE盒子模型(怪异盒子模型):宽=内部宽度(content+border+padding)+margin
互换模型格式:
box-sizing:content-box;//变为标准盒模型(大部分浏览器默认)
box-sizing:border-box;//变为怪异盒子模型
行内元素、块级元素、空元素有哪些?区别?
1、行内元素:span、a、em、img、input
2、块级元素:div、ol、ul、form
3、空元素:br、hr、img、input
区别:
行内元素不换行、块级元素换行
正常情况下是块级元素包含行内元素,鲜少有行内元素包含块级元素
没有内容的标签称之为空元素,空元素是在开始标签中关闭的。
离线缓存与传统浏览器缓存的区别
离线缓存是整个应用,传统浏览器缓存是单个文件
离线缓存断网后依然可以打开页面,传统浏览器缓存不可以
离线缓断在有网络情况下优先使用缓存,传统浏览器缓存会通知网络更新缓存
能不能说一说浏览器的本地存储?各自优劣如何?
浏览器的本地存储主要分为Cookie、WebStorage, 其中WebStorage又可以分为localStorage和sessionStorage。
共同点:都会在浏览器端保存,有大小和同源限制
不同点:
一、cookie数据始终在同源的http请求中携带,即cookie在浏览器和服务器间来回传递。sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
二、存储大小限制也不同:cookie数据不能超过4K,sessionStorage和localStorage可以达到5M或者更多
三、作用域不同:sessionStorage:仅在当前浏览器窗口关闭之前有效;localstorage:数据始终有效,窗口或浏览器关闭也一直保存,除非删除数据;cookie:在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
CSS样式优先级
!important>style>id>class
BFC
BFC 即块格式化上下文。BFC内的元素不会影响外面的元素。
创建:
1.float不为none
2.position为absolute或fixed
3.overflow不为visible
4.display为inline-block、flex、inline-flex等
应用:
1. 防止margin重叠
2. 清除内部浮动
3. 自适应多栏布局
三栏布局
绝对定位法:中间栏目使用margin/padding空出左右位置,左右使用绝对定位
浮动法:中间栏目使用margin/padding空出左右位置,左右使用浮动定位
Flex:flex:1
Grid:父元素:display:grid 子元素:grid-template-columns:100px auto 20px
CSS选择器
标签选择器
ID选择器
类选择器
组选择器
通配符选择器
后代选择器
子元素选择器
伪类选择器
Flex:1是什么
经常用于自适应布局。也就是flex-grow、flex-shrink、flex-basis的缩写
Display:flex的常用属性
flex-drection:设置主轴方向
Justify-content:设置主轴排列方式
Flex-wrap:设置是否换行
Align-content/align-item:侧轴排列(多行/单行)
预处理器less、sass
是css中一种抽象层。好处:
1.结构清晰、便于扩展
2.方便屏蔽浏览器的语法差异
3.多重继承
DOM、BOM对象
BOM是指浏览器对象模型,可以对浏览器窗口进行访问和操作。使用 BOM,开发者可以移动窗口、改变状态栏中的文本以及执行其他与页面内容不直接相关的动作。
DOM 是指文档对象模型,通过它,可以访问HTML文档的所有元素。 DOM 是 W3C的标准。
浏览器渲染机制
网页生成过程:
1.HTML被HTML解析器解析成DOM 树
2.css则被css解析器解析成CSSOM 树
3.结合DOM树和CSSOM树,生成一棵渲染树(Render Tree)
4.生成布局(flow),即将所有渲染树的所有节点进行平面合成
5.将布局绘制(paint)在屏幕上
重排(也称回流)
当DOM的变化影响了元素的几何信息(DOM对象的位置和尺寸大小),浏览器需要重新计算元素的几何属性,将其安放在界面中的正确位置,这个过程叫做重排。 触发:添加或者删除可见的DOM元素、元素尺寸改变——边距、填充、边框、宽度和高度
重绘
当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。 触发:改变元素的color、background、box-shadow等属性
重排重绘优化建议
1.样式表越简单,重排和重绘就越快。尽量用class,少用style一条条改变样式
2.重排和重绘的DOM元素层级越高,成本就越高。如果可以灵活用display,absolute,flex等重排开销会比较小,或不会影响其他元素的重排。
JS相关
js数据类型、typeof、instanceof
1) string、number、boolean、null、undefined、object(function、array)、symbol
2) typeof 主要用来判断数据类型
3) instanceof 判断该对象是谁的实例。
ES6
1. 新增symbol类型 表示独一无二的值,用来定义独一无二的对象属性名;
2. const/let 都是用来声明变量,不可重复声明,具有块级作用域。存在暂时性死区,也就是不存在变量提升。(const一般用于声明常量);
3. 变量的解构赋值(包含数组、对象、字符串、数字及布尔值,函数参数),剩余运算符(...rest);
4. 模板字符串(${data});
5. 扩展运算符(数组、对象);;
6. 箭头函数;
7. Set和Map数据结构;
8. Proxy/Reflect;
9. Promise
ES6里的symble
它的功能类似于一种标识唯一性的ID,每个Symbol实例都是唯一的。 Symbol类型的key是不能通过Object.keys()或者for...in来枚举的, 它未被包含在对象自身的属性名集合(property names)之中。 所以,利用该特性,我们可以把一些不需要对外操作和访问的属性使用Symbol来定义。
ES6里的set和map
- Map对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。构造函数Map可以接受一个数组作为参数。
- Set对象允许你存储任何类型的值,无论是原始值或者是对象引用。它类似于数组,但是成员的值都是唯一的,没有重复的值。
vue的key
1.key的作用主要是为了高效的更新虚拟DOM,其原理是vue在patch过程中通过key可以精准判断两个节点是否是同一个,从而避免频繁更新不同元素,使得整个patch过程更加高效,减少DOM操作量,提高性能。
2.另外,若不设置key还可能在列表更新时引发一些隐蔽的bug
3. vue中在使用相同标签名元素的过渡切换时,也会使用到key属性,其目的也是为了让vue可以区分它们, 否则vue只会替换其内部属性而不会触发过渡效果。
普通函数和箭头函数的区别
1.箭头函数是匿名函数,不能作为构造函数,不能使用new
2.箭头函数不绑定arguments,取而代之用rest参数...解决
3.箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值
4.箭头函数通过 call() 或 apply() 方法调用一个函数时,只传入了一个参数,对 this 并没有影响。
5.箭头函数不能当做Generator函数,不能使用yield关键字
闭包(高频)
闭包是指有权访问另一个函数作用域中的变量的函数 当函数可以记住并访问所在的词法作用域时,就产生了闭包,即使函数是在当前词法作用域之外执行
- 闭包用途:
能够访问函数定义时所在的词法作用域(阻止其被回收)
私有化变量
模拟块级作用域
创建模块
- 闭包缺点:会导致函数的变量一直保存在内存中,过多的闭包可能会导致内存泄漏
原型、原型链(高频)
原型:对象中固有的__proto__属性,该属性指向对象的prototype原型属性。
原型链:当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,也就是原型链的概念。原型链的尽头一般来说都是Object.prototype所以这就是我们新建的对象为什么能够使用toString()等方法的原因。
特点: JavaScript对象是通过引用来传递的,我们创建的每个新对象实体中并没有一份属于自己的原型副本。当我们修改原型时,与之相关的对象也会继承这一改变。
this指向
代表的是当前上下文环境对象。在面向对象语言中this表示当前对象的一个引用。但在JavaScript中this是不固定的,它会随着环境的改变而改变。
1) 在方法中,this表示该方法所属的对象
2) 在单独使用的情况下,this代表的是全局对象
3) 在函数中,this表示的是全局对象
4) 在函数中但是在严格模式下,this为未定义(undefined)
5) 在事件中,this表示的是接收事件的元素
类似call、apply等方法可以改变this引用到的对象apply 、 call 和 bind 调用模式,这三个方法都可以显示的指定调用函数的 this 指向。apply接收参数的是数组,call接受参数列表,bind方法传入一个对象。
new关键字
1.首先创建了一个新的空对象
2.设置原型,将对象的原型设置为函数的prototype对象。
3.让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)
4.判断函数的返回值类型,如果是值类型,返回创建的对象。如果是引用类型,就返回这个引用类型的对象。
作用域、作用域链
作用域负责收集和维护由所有声明的标识符(变量)组成的一系列查询,并实施一套非常严格的规则,确定当前执行的代码对这些标识符的访问权限。(全局作用域、函数作用域、块级作用域)。 作用域链就是从当前作用域开始一层一层向上寻找某个变量,直到找到全局作用域还是没找到,就宣布放弃。这种一层一层的关系,就是作用域链。
继承(含es6)、多种继承方式
(1)第一种是以原型链的方式来实现继承,但是这种实现方式存在的缺点是,在包含有引用类型的数据时,会被所有的实例对象所共享,容易造成修改的混乱。还有就是在创建子类型的时候不能向超类型传递参数。
(2)第二种方式是使用借用构造函数的方式,这种方式是通过在子类型的函数中调用超类型的构造函数来实现的,这一种方法解决了不能向超类型传递参数的缺点,但是它存在的一个问题就是无法实现函数方法的复用,并且超类型原型定义的方法子类型也没有办法访问到。
(3)第三种方式是组合继承,组合继承是将原型链和借用构造函数组合起来使用的一种方式。通过借用构造函数的方式来实现类型的属性的继承,通过将子类型的原型设置为超类型的实例来实现方法的继承。这种方式解决了上面的两种模式单独使用时的问题,但是由于我们是以超类型的实例来作为子类型的原型,所以调用了两次超类的构造函数,造成了子类型的原型中多了很多不必要的属性。
(4)第四种方式是原型式继承,原型式继承的主要思路就是基于已有的对象来创建新的对象,实现的原理是,向函数中传入一个对象,然后返回一个以这个对象为原型的对象。这种继承的思路主要不是为了实现创造一种新的类型,只是对某个对象实现一种简单继承,ES5 中定义的 Object.create() 方法就是原型式继承的实现。缺点与原型链方式相同。
(5)第五种方式是寄生式继承,寄生式继承的思路是创建一个用于封装继承过程的函数,通过传入一个对象,然后复制一个对象的副本,然后对象进行扩展,最后返回这个对象。这个扩展的过程就可以理解是一种继承。这种继承的优点就是对一个简单对象实现继承,如果这个对象不是我们的自定义类型时。缺点是没有办法实现函数的复用。
(6)第六种方式是寄生式组合继承,组合继承的缺点就是使用超类型的实例做为子类型的原型,导致添加了不必要的原型属性。寄生式组合继承的方式是使用超类型的原型的副本来作为子类型的原型,这样就避免了创建不必要的属性。
EventLoop
JS是单线程的,为了防止一个函数执行时间过长阻塞后面的代码,所以会先将同步代码压入执行栈中,依次执行,将异步代码推入异步队列,异步队列又分为宏任务队列和微任务队列,因为宏任务队列的执行时间较长,所以微任务队列要优先于宏任务队列。微任务队列的代表就是,Promise.then,MutationObserver,宏任务的话就是setImmediate setTimeout setInterval
原生ajax
ajax是一种异步通信的方法,从服务端获取数据,达到局部刷新页面的效果。 过程:
1. 创建XMLHttpRequest对象;
2. 调用open方法传入三个参数 请求方式(GET/POST)、url、同步异步(true/false);
3. 监听onreadystatechange事件,当readystate等于4时返回responseText;
4. 调用send方法传递参数。
事件冒泡、捕获(委托)
- 事件冒泡指在在一个对象上触发某类事件,如果此对象绑定了事件,就会触发事件,如果没有,就会向这个对象的父级对象传播,最终父级对象触发了事件。
- 事件委托本质上是利用了浏览器事件冒泡的机制。因为事件在冒泡过程中会上传到父节点,并且父节点可以通过事件对象获取到目标节点,因此可以把子节点的监听函数定义在父节点上,由父节点的监听函数统一处理多个子元素的事件,这种方式称为事件代理。
event.stopPropagation() 或者 ie下的方法 event.cancelBubble = true; //阻止事件冒泡
Vue
简述MVVM
MVVM是Model-View-ViewModel缩写,也就是把MVC中的Controller演变成ViewModel。Model层代表数据模型,View代表UI组件,ViewModel是View和Model层的桥梁,数据会绑定到viewModel层并自动将数据渲染到页面中,视图变化的时候会通知viewModel层更新数据。
谈谈对vue生命周期的理解?
每个Vue实例在创建时都会经过一系列的初始化过程,vue的生命周期钩子,就是说在达到某一阶段或条件时去触发的函数,目的就是为了完成一些动作或者事件
- create阶段:vue实例被创建 beforeCreate: 创建前,此时data和methods中的数据都还没有初始化 created: 创建完毕,data中有值,未挂载
- mount阶段:vue实例被挂载到真实DOM节点 beforeMount:可以发起服务端请求,去数据 mounted: 此时可以操作Dom
- update阶段:当vue实例里面的data数据变化时,触发组件的重新渲染 beforeUpdate updated
- destroy阶段:vue实例被销毁 beforeDestroy:实例被销毁前,此时可以手动销毁一些方法 destroyed
data为什么是一个函数而不是对象
因为对象是一个引用数据类型,如果data是一个对象的情况下会造成所有组件共用一个data。而当data是一个函数的情况下,每次函数执行完毕后都会返回一个新的对象,这样的话每个组件都会维护一份独立的对象(data)
computed与watch
watch 属性监听是一个对象,键是需要观察的属性,值是对应回调函数,主要用来监听某些特定数据的变化,从而进行某些具体的业务逻辑操作,监听属性的变化,需要在数据变化时执行异步或开销较大的操作时使用
computed 计算属性属性的结果会被缓存,当computed中的函数所依赖的属性没有发生改变的时候,那么调用当前函数的时候结果会从缓存中读取。除非依赖的响应式属性变化时才会重新计算,主要当做属性来使用computed中的函数必须用return返回最终的结果 computed更高效,优先使用
使用场景 computed:当一个属性受多个属性影响的时候使用,例:购物车商品结算功能 watch:当一条数据影响多条数据的时候使用,例:搜索数据
v-for中key的作用
1. key的作用主要是为了更高效的对比虚拟DOM中每个节点是否是相同节点;
2. Vue在patch过程中判断两个节点是否是相同节点,key是一个必要条件,渲染一组列表时,key往往是唯一标识,所以如果不定义key的话,Vue只能认为比较的两个节点是同一个,哪怕它们实际上不是,这导致了频繁更新元素,使得整个patch过程比较低效,影响性能;
3. 从源码中可以知道,Vue判断两个节点是否相同时主要判断两者的key和元素类型等,因此如果不设置key,它的值就是undefined,则可能永 远认为这是两个相同的节点,只能去做更新操作,这造成了大量的dom更新操作,明显是不可取的。
vue组件的通信方式
父子组件通信
父->子props,子->父 $on、$emit` 获取父子组件实例 parent、parent、children Ref 获取实例的方式调用组件的属性或者方法 Provide、inject` 官方不推荐使用,但是写组件库时很常用
兄弟组件通信
Event Bus 实现跨组件通信 Vue.prototype.$bus = new Vue() Vuex
跨级组件通信
$attrs、$listeners Provide、inject
路由传参
1. 使用router-link进行路由导航,传递参数
2. 直接调用$router.push 实现携带参数的跳转
3. 通过路由属性中的name来确定匹配的路由,通过params来传递参数
4. 使用path来匹配路由,然后通过query来传递参数,这种情况下 query传递的参数会显示在url
路由的两种模式hash与history
对于Vue 这类渐进式前端开发框架,为了构建SPA(单页面应用),需要引入前端路由系统,这也就是Vue-router存在的意义。前端路由的核心,就在于改变视图的同时不会向后端发出请求。
1、hash ——即地址栏URL中的#符号,它的特点在于:hash 虽然出现URL中,但不会被包含在HTTP请求中,对后端完全没有影响,因此改变hash不会重新加载页面。
2、history ——利用了HTML5 History Interface 中新增的pushState() 和replaceState() 方法。这两个方法应用于浏览器的历史记录站,在当前已有的back、forward、go 的基础之上,它们提供了对历史记录进行修改的功能。只是当它们执行修改是,虽然改变了当前的URL,但你浏览器不会立即向后端发送请求。history模式,会出现404 的情况,需要后台配置。
路由守卫
双向绑定实现原理
当一个Vue实例创建时,Vue会遍历data选项的属性,用Object.defineProperty将它们转为 getter/setter并且在内部追踪相关依赖,在属性被访问和修改时通知变化。每个组件实例都有相应的 watcher 程序实例,它会在组件渲染的过程中把属性记录为依赖,之后当依赖项的 setter 被调用时,会通知 watcher重新计算,从而致使它关联的组件得以更新。