CSS
1、垂直水平居中
水平居中
行内元素: text-align: center
块级元素: margin: 0 auto
position:absolute +left:50%+ transform:translateX(-50%)
display:flex + justify-content: center
垂直居中
设置line-height 等于height
position:absolute +top:50%+ transform:translateY(-50%)
display:flex + align-items: center
display:table+display:table-cell + vertical-align: middle;
2、calc
calc() 函数用于动态计算长度值。
需要注意的是,运算符前后都需要保留一个空格,例如:width: calc(100% - 10px);
任何长度值都可以使用calc()函数进行计算;
calc()函数支持 "+", "-", "*", "/" 运算;
calc()函数使用标准的数学运算优先级规则;
el:width: calc(100% - 100px);
3、万能清楚浮动
.clearfix:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
4、BFC
块级格式化上下文,是一个独立的渲染区域,让处于 BFC 内部的元素与外部的元素相互隔离,使内外元素的定位不会相互影响。
5、link和@import区别
link功能较多,可以定义 RSS,定义 Rel 等作用,而@import只能用于加载 css
当解析到link时,页面会同步加载所引的 css,而@import所引用的 css 会等到页面加载完才被加载
@import需要 IE5 以上才能使用
link可以使用 js 动态引入,@import不行
CSS预处理器(Sass/Less/Postcss)
CSS预处理器的原理: 是将类 CSS 语言通过 Webpack 编译 转成浏览器可读的真正 CSS。在这层编译之上,便可以赋予 CSS 更多更强大的功能,常用功能:
嵌套
变量
循环语句
条件语句
自动前缀
单位转换
mixin复用
JS
1、输入url后的流程:
DNS 解析
TCP 三次握手
发送请求,分析 url,设置请求报文(头,主体)
服务器返回请求的文件 (html)
浏览器渲染
HTML parser --> DOM Tree
标记化算法,进行元素状态的标记
dom 树构建
CSS parser --> Style Tree
解析 css 代码,生成样式树
attachment --> Render Tree结合 dom树 与 style树,生成渲染树
layout: 布局
GPU painting: 像素绘制页面
2、继承问题/原型/原型链
原型(prototype): 一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个JavaScript对象中都包含一个__proto__ (非标准)的属性指向它爹(该对象的原型),可obj.__proto__进行访问。
原型链是由原型对象组成,每个对象都有 __proto__ 属性,指向了创建该对象的构造函数的原型,__proto__ 将对象连接起来组成了原型链。是一个用来实现继承和共享属性的有限的对象链
在 JS 中,继承通常指的便是 原型链继承,也就是通过指定原型,并可以通过原型链继承原型上的属性或者方法。
最优化: 圣杯模式
var inherit = (function(c,p){
var F = function(){};
return function(c,p){
F.prototype = p.prototype;
c.prototype = new F();
c.uber = p.prototype;
c.prototype.constructor = c;
}
})();
使用 ES6 的语法糖 class / extends
3、Promise/async/await/地狱回调
Promise 有三种状态,分别是:
等待中(pending)
完成了 (resolved)
拒绝了(rejected)
Promise.resolve(1)
.then(res => {
console.log(res) // => 1
return 2 // 包装成 Promise.resolve(2)
})
.then(res => {
console.log(res) // => 2
})
一个函数如果加上 async ,那么该函数就会返回一个 Promise
async 就是将函数返回值使用 Promise.resolve() 包裹了下,和 then 中处理返回值一样,并且 await 只能配套 async 使用
async 和 await 可以说是异步终极解决方案了,相比直接使用 Promise 来说,优势在于处理 then 的调用链,能够更清晰准确的写出代码,毕竟写一大堆 then 也很恶心,并且也能优雅地解决回调地狱问题。当然也存在一些缺点,因为 await 将异步代码改造成了同步代码,如果多个异步代码没有依赖性却使用了 await 会导致性能上的降低。
4、bind/apply/call
改变了 this 指向,让新的对象可以执行该函数,并能接受参数
func.call(this, arg1, arg2);直接执行
func.apply(this, [arg1, arg2]);直接执行
func.bind(this, arg1, arg2);未执行
5、Set/Map
Set:删除数组重复选项
Map:Obj的key值只能是字符串,Map可以是参数
6、闭包
7、深浅拷贝(MessageChannel)
JSON.parse(JSON.stringify(obj))
该方法也是有局限性的:
会忽略 undefined
会忽略 symbol
不能序列化函数
不能解决循环引用的对象
可以使用 MessageChannel
MessageChannel创建了一个通信的管道,这个管道有两个端口,每个端口都可以通过postMessage发送数据,而一个端口只要绑定了onmessage回调方法,就可以接收从另一个端口传过来的数据。
8、this
9、存储(coolie,localStorage,sessionStorage,indexDB)
10、var let const
11、Class
12、Proxy
Proxy :
以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截。
两个参数:
target 代表需要添加代理的对象,handler 用来自定义对象中的操作,比如可以用来自定义 set 或者 get 函数。
13、map\filter\reduce
map 作用是生成一个新数组,遍历原数组,将每个元素拿出来做一些变换然后放入到新的数组中。
filter 的作用也是生成一个新数组,在遍历数组的时候将返回值为 true 的元素放入新数组,我们可以利用这个函数删除一些不需要的元素
reduce 可以将数组中的元素通过回调函数最终转换为一个值。(它接受两个参数,分别是回调函数和初始值)
el:
const arr = [1, 2, 3]
const sum = arr.reduce((acc, current) => acc + current, 0)
console.log(sum)//6
14、构造函数和普通函数区别
1、构造函数也是一个普通函数,创建方式和普通函数一样,但构造函数习惯上首字母大写
2、构造函数和普通函数的区别在于:调用方式不一样。作用也不一样(构造函数用来新建实例对象)
3、调用方式不一样。
普通函数的调用方式:直接调用 person();
构造函数的调用方式:需要使用new关键字来调用 new Person();
4、构造函数的函数名与类名相同:Person( ) 这个构造函数,Person 既是函数名,也是这个对象的类名
5、内部用this 来构造属性和方法
6、构造函数的执行流程
立刻在堆内存中创建一个新的对象
将新建的对象设置为函数中的this
逐个执行函数中的代码
将新建的对象作为返回值
7、普通函数例子:因为没有返回值,所以为undefined
15、跨域
1、通过jsonp跨域
2、通过修改document.domain来跨子域
3、使用window.name来进行跨域
比如:有一个页面a.html,它里面有这样的代码:
window.name = "我是a页面设置的";
setTimeout(function(){
window.location = "http://127.0.0.1/JSONP/b.html";
},1000)
b.html页面的代码:
console.log(window.name);
a.html页面载入后1秒,跳转到了b.html页面,结果b页面打印出了:
我是a页面设置的
16、websocket
Websocket 是一个 持久化的协议, 基于 http , 服务端可以 主动 push
17、错误码
1xx: 接受,继续处理
200: 成功,并返回数据
201: 已创建
202: 已接受
203: 成为,但未授权
204: 成功,无内容
205: 成功,重置内容
206: 成功,部分内容
301: 永久移动,重定向
302: 临时移动,可使用原有URI
304: 资源未修改,可使用缓存
305: 需代理访问
400: 请求语法错误
401: 要求身份认证
403: 拒绝请求
404: 资源不存在
500: 服务器错误
18、性能优化
19、instanceof原理
```能在实例的 原型对象链 中找到该构造函数的prototype属性所指向的 原型对象,就返回true。```
20、防抖和节流
(防抖 (debounce)、节流(throttle))
21、AST
(抽象语法树 (Abstract Syntax Tree)是将代码逐字母解析成 树状对象 的形式。这是语言之间的转换、代码语法检查,代码风格检查,代码格式化,代码高亮,代码错误提示,代码自动补全等等的基础。)
22、函数柯里化
const add = function add(x) {
return function (y) {
return x + y
}
}
const add1 = add(1)
add1(2) === 3
add1(20) === 21
23、Event Loop
事件循环是指: 执行一个宏任务,然后执行清空微任务列表,循环再执行宏任务,再清微任务列表
24、重绘与回流
重绘(repaint): 当元素样式的改变不影响布局时,浏览器将使用重绘对元素进行更新,此时由于只需要UI层面的重新像素绘制,因此 损耗较少
回流(reflow): 当元素的尺寸、结构或触发某些属性时,浏览器会重新渲染页面,称为回流。此时,浏览器需要重新经过计算,计算后还需要重新页面布局,因此是较重的操作。
25、Proxy 相比于 defineProperty 的优势
优势:
数组变化也能监听到
不需要深度遍历监听
26、for in和for of
for ... in 循环返回的值都是数据结构的 键值名。
遍历对象返回的对象的key值,遍历数组返回的数组的下标(key)。
for ... in 循环不仅可以遍历数字键名,还会遍历原型上的值和手动添加的其他键。
for of 循环用来获取一对键值对中的值,而 for in 获取的是 键名
for of 不同与 forEach, 它可以与 break、continue和return 配合使用,也就是说 for of 循环可以随时退出循环。
VUE
1、生命周期
...
2、组件通信
父子通讯
父组件通过 props 传递数据给子组件,子组件通过 emit 发送事件传递数据给父组件,这两种方式是最常用的父子通信实现办法。
这种父子通信方式也就是典型的单向数据流,父组件通过 props 传递数据,子组件不能直接修改 props, 而是必须通过发送事件的方式告知父组件修改数据。
另外这两种方式还可以使用语法糖 v-model 来直接实现,因为 v-model 默认会解析成名为 value 的 prop 和名为 input 的事件。这种语法糖的方式是典型的双向绑定,常用于 UI 控件上,但是究其根本,还是通过事件的方法让父组件修改数据。
当然我们还可以通过访问 $parent 或者 $children 对象来访问组件实例中的方法和数据。
另外如果你使用 Vue 2.3 及以上版本的话还可以使用 $listeners 和 .sync 这两个属性。
$listeners 属性会将父组件中的 (不含 .native 修饰器的) v-on 事件监听器传递给子组件,子组件可以通过访问 $listeners 来自定义监听器。
.sync 属性是个语法糖,可以很简单的实现子组件与父组件通信
<!--父组件中-->
<input :value.sync="value" />
<!--以上写法等同于-->
<input :value="value" @update:value="v => value = v"></comp>
<!--子组件中-->
<script>
this.$emit('update:value', 1)
</script>
兄弟组件通信
对于这种情况可以通过查找父组件中的子组件实现,也就是 this.$parent.$children,在 $children 中可以通过组件 name 查询到需要的组件实例,然后进行通信。
跨多层次组件通信
对于这种情况可以使用 Vue 2.2 新增的 API provide / inject,虽然文档中不推荐直接使用在业务中,但是如果用得好的话还是很有用的。
假设有父组件 A,然后有一个跨多层级的子组件 B
// 父组件 A
export default {
provide: {
data: 1
}
}
// 子组件 B
export default {
inject: ['data'],
mounted() {
// 无论跨几层都能获得父组件的 data 属性
console.log(this.data) // => 1
}
}
任意组件
这种方式可以通过 Vuex 或者 Event Bus 解决,另外如果你不怕麻烦的话,可以使用这种方式解决上述所有的通信情况
3、extend作用是扩展组件生成一个构造器,通常会与 $mount 一起使用。
4、mixin 和 mixins 区别
Vue.mixin({
beforeCreate() {
// ...逻辑
// 这种方式会影响到每个组件的 beforeCreate 钩子函数
}
})
虽然文档不建议我们在应用中直接使用 mixin,但是如果不滥用的话也是很有帮助的,比如可以全局混入封装好的 ajax 或者一些工具函数等等。
mixins 应该是我们最常使用的扩展组件的方式了。如果多个组件中有相同的业务逻辑,就可以将这些逻辑剥离出来,通过 mixins 混入代码,比如上拉下拉加载数据这种逻辑等等。
5、computed 和 watch 区别
computed 是计算属性,依赖其他属性计算值,并且 computed 的值有缓存,只有当计算值变化才会返回内容。
watch 监听到值的变化就会执行回调,在回调中可以进行一些逻辑操作。
6、keep-alive 组件有什么作用
keep-alive 独有的生命周期,分别为 activated 和 deactivated 。用 keep-alive 包裹的组件在切换时不会进行销毁,而是缓存到内存中并执行 deactivated 钩子函数,命中缓存渲染后会执行 actived 钩子函数。
7、组件中 data 什么时候可以使用对象
组件复用时所有组件实例都会共享 data,如果 data 是对象的话,就会造成一个组件修改 data 以后会影响到其他所有组件,所以需要将 data 写成函数,每次用到就调用一次函数获得新的数据。
当我们使用 new Vue() 的方式的时候,无论我们将 data 设置为对象还是函数都是可以的,因为 new Vue() 的方式是生成一个根组件,该组件不会复用,也就不存在共享 data 的情况了。
8、响应式原理
Vue 内部使用了 Object.defineProperty() 来实现数据响应式,通过这个函数可以监听到 set 和 get 的事件。
9、nextTick原理
nextTick 可以让我们在下次 DOM 更新循环结束之后执行延迟回调,用于获得更新后的 DOM。
在 Vue 2.4 之前都是使用的 microtasks,但是 microtasks 的优先级过高,在某些情况下可能会出现比事件冒泡更快的情况,但如果都使用 macrotasks 又可能会出现渲染的性能问题。所以在新版本中,会默认使用 microtasks,但在特殊情况下会使用 macrotasks,比如 v-on。
对于实现 macrotasks ,会先判断是否能使用 setImmediate ,不能的话降级为 MessageChannel ,以上都不行的话就使用 setTimeout
10、 vuex
state: 状态中心
mutations: 更改状态
actions: 异步更改状态
getters: 获取状态
modules: 将state分成多个modules,便于管理