HTML语义化
- 语义化标签
- 利于页面内容结构化
- 利于SEO
- 利于代码可读
- 使用HTML标签构建页面时,尽可能的使用具有语义的标签
HTML5有哪些新特性
HTML5新增:
(1)新增语义化标签:nav、header、footer、aside、section、article
(2)音频、视频标签:audio、video
(3)数据存储:localStorage、sessionStorage
(4)canvas(画布)、Geolocation(地理定位)、websocket(通信协议)
(5)input标签新增属性:placeholder、autocomplete、autofocus、required
(6)history API:go、forward、back、pushstate
CSS3有哪些新特性
1、边框和圆角:css3引入了border-radius属性,可以实现元素的边框的圆角效果,而无需使用额外的背景图片或复杂的Hack方法。
2、过度和动画:css3 提供了transition和animation属性,允许开发者为元素添加过度效果(移动translate,旋转rotate,缩放scale)和动画效果(@keyframe),使页面更具交互性和活力。
3、盒子模型:css3 引入了box-sizing属性,可以更精确的控制元素盒子模型的大小计算方式,包括content-box(默认)、border-box和padding-box。
4、阴影和渐变:css3 新增了box-shadow和linear-gradient/radial-gradient等属性,是的开发者可以通过css直接添加阴影效果和渐变色的效果,而无需依赖图像编辑工具。
5、文字排版:css3引入了一系列用于文字排版的属性,如text-shadow(文字阴影)、(text-overflow(文本溢出)、worder-wrap(断行处理)、text-justify(文本对齐和间距调整)等
6、媒体查询:css3 的媒体查询功能允许开发者根据不同的设备或屏幕尺寸应用不同的样式,从而实现响应式布局和设计,提供更好的移动端适配性。@media
7、伸缩布局(flexbox):css3 的flexbox布局模块提供了一种灵活的布局方式,可以方便实现弹性盒子布局,是的网页布局更加简洁、灵活和响应式。
8、字体和多列布局:css3 新增了@font-face规则,可以通过css引入自定义字体和文件,丰富了网页字体选择的可能性。同时css3还引入了column-count和column-gap等属性,实现了多列布局的效果
9、选择器(基本选择器、属性选择器、伪类选择器)
var 、let、const区别
1.var声明的变量会挂载在window上,而let和const声明的变量不会
2.var声明变量存在变量提升,而let和const不存在变量提升
3.let和const声明形成块作用域,var声明不形成块作用域
4.同一作用域下let和const不能声明同名变量,而var可以声明同名变量
5.暂存死区:在使用let、const命令声明变量之前,该变量都是不可用的。这在语法上,称为暂时性死区。使用var声明的变量不存在暂时性死区。
6.let声明的变量允许重新赋值,const不允许
const声明的对象属性和数组的值是可以修改的
- 我们都知道const 是声明常量的,如果用const声明过后的变量是不可以修改的
- 但如果是const 声明了对象,其实对象的属性是可以修改的,对象属性被赋值为常量是不受保护的
- 如果是const声明了数组,数组里面的值也是可以修改的,数组的被定义为常量也是不受保护的
Object.is() 与比较操作符 “===”、“==” 的区别?
- 使用双等号(==)进行相等判断时,如果两边的类型不一致,则会进 行强制类型转化后再进行比较。
- 使用三等号(===)进行相等判断时,如果两边的类型不一致时,不 会做强制类型准换,直接返回 false。
- 使用 Object.is 来进行相等判断时,一般情况下和三等号的判断相 同,它处理了一些特殊的情况,比如 -0 和 +0 不再相等,两个 NaN 是相等的。
默认情况下,哪些HTML标签是块级元素、内联元素、空元素?
- 内联(行内)元素有:
a b span img input select strong - 块级元素有:
div ul ol li dl dt dd h1 h2 h3 h4 h5 h6 p - 常见的空元素:
<br>、<hr>、<img>、<input>、<link>、<meta>
如何判断一个对象是空对象
使用 JSON 自带的.stringify 方法来判断:
使用 ES6 新增的方法 Object.keys()来判断:
JS继承方式有几种,各自优缺点?
- 原型链继承(prototype)
- 构造函数继承(借助call方法)
- 组合继承(原型链继承+构造函数继承)
- 原型式继承(借助Object.create)
- 寄生式继承
- 寄生组合式继承
- ES6 的 class和extends 关键字实现逻辑
常见Web安全问题及解决方案
SQL注入问题、XSS跨站脚本攻击、XSRF跨站请求伪造、Session劫持
SQL注入问题的解决方案
1.做好客户端表单验证
2.做好服务端参数验证
3.数据库使用预编译的SQL语句
Session劫持的解决方案
Session IP双重认证、Token机制
XSS的解决方案(危机种类:窃取网页浏览的cookie值、劫持流量实现恶意跳转)
使用转义解决,将<转义成<;>转义成>
XSRF常见解决方案
token验证
对eventLoop机制的理解?
浏览器中的事件循环机制又叫事件队列
axios是怎么做封装的?
axios是什么?怎么使用?
axios 是基于Promise的,用于浏览器和nodejs的一个http客户端。 主要用于向后台发送请求,还有就是在请求中做更多的控制。 优点
- 支持Promise
- 提供了一些并发的方法,比如Promise.all
- 提供拦截器(守卫)
- 客户端支持抵御XSRF攻击(跨站请求伪造)
- 浏览器端发起 XMLHttpRequests 请求
- 监听请求和返回
- 对请求和返回进行转化
- 取消请求
- 自动转换 json 数据
delete和Vue.delete删除数组的区别
普通的delete删除一个数组中的元素,该元素会成为空值(empty)。数组长度不变。键值还是不变
vue.delete删除会直接删除一个数组元素,长度会减少。改变了数组的键值
Javascript设计模式的定义
一套被反复使用,思想成熟,经过分类和无数实战设计经验的总结,使用设计模式是为了让系统代码,可重用,可扩展,可解耦,更容易被人理解且能保证代码可靠性
JavaScript设计原则
开闭原则、里氏转换原则、依赖倒转原则、接口隔离原则、合成/聚合复用原则、迪米特原则
原型和原型链
原型是每个函数都有prototype属性,因为这个属性的值是个对象,也称为原型对象
作用:存放一些属性和方法、在JavaScript中实现继承
原型链是由一些用来继承和共享属性__proto__的对象组成的对象键(一个原型对象的原型不为 null 的话)
原型链是一种查找规则
当访问一个对象的属性时,如果这个对象内部不存在这个属性,那么它就会去它的原型对象里找这个属性,这个原型对象又会有自己的原型,于是就这样一直找下去,这种链式查找过程称之为原型链
原型链的尽头是null。也就是Object.prototype.proto
同源策略
同源策略是浏览器里的一种安全协议确保两页面间的协议、域名和端口都相同(一段脚本只能读取来自同一来源的窗口和文档的属性)
如何解决跨域问题
- jsonp(原理是动态插入script标签,但是只支持get请求)
- 服务器上设置代理页面
- CORS(跨域资源共享——服务端设置Access-Control-Allow-Origin即可,前端无须设置,若要带cookie请求,前后端都需要设置)
- window.name+ iframe
- window.postMessage
- document.domain+iframe
- websocket
- location.hash+iframe
display:none和visibility:hidden的区别
display:none在文档布局中不再给它分配空间
visibility:hidden隐藏后还在文档布局仍保留原来的空间
JS节点操作
- 创建节点、追加节点
1.createElement创建一个元素节点。
2.appendChild 追加一个节点。
3.createTextNode创建一个文本节点。
- 删除、移除节点
removeChild(节点) 删除一个节点,用于移除删除一个参数(节点)。 其返回的被移除的节点,被移除的节点仍在文档中,只是文档中已没有其位置了。
- 替换节点
replaceChild(插入的节点,被替换的节点) ,用于替换节点,接受两个参数,
第一参数是要插入的节点,第二个是要被替换的节点。返回的是被替换的节点。
- 查找节点
childNodes 包含文本节点和元素节点的子节点。
- 复制节点
cloneNode()
浏览器缓存机制
分为强缓存和协商缓存,根据响应的header内容来决定
强缓存:浏览器直接从本地缓存中获取数据,不与服务器进行交互(不用请求服务器,直接使用本地缓存)-expires、cache-control
协商缓存:浏览器发送请求到服务器,服务器判断是否可使用本地缓存(浏览器发现本地有资源的副本,单不太确定要不要使用于是去问服务器)-Last-Modified/If-Modified-Since,Etag/If-None-Match
Vue数据双向绑定的原理
通过数据劫持结合发布者-订阅者模式的方式实现的,利用了Object.defineProperty()重新定义了对象获取属性值(get)和设置属性值(set)
双向数据绑定v-model的实现原理
- 通过input元素的value=this.name
- 绑定input事件this.name=$event.target.value
- data更新触发re-render
v-model只是语法糖(在内部为不同的输入元素使用不同的property并抛出不同的事件)
- text和textarea元素使用value property和input事件
- checkbox和radio使用checked property和change事件
- select字段将value作为property并将change作为事件
Object.defineProperty(target, key, options),options可传什么参数?
- value:给target[key]设置初始值
- get:调用target[key]时触发
- set:设置target[key]时触发
- writable:规定target[key]是否可被重写,默认false
- enumerable:规定了key是否会出现在target的枚举属性中,默认为false
- configurable:规定了能否改变options,以及删除key属性,默认false,具体详细请看
Vue的核心点:数据劫持和组件系统
渐进式代表的含义是:没有多做职责之外的事。
vue.js只提供了 vue-cli 生态中最核心的 组件系统 和 双向数据绑定。
数据劫持:ViewModel保证数据和视图的一致性
组件系统:应用类UI可以看作全部是有组件树构成的
- 组件化开发能大幅提高应用开发效率、测试性、复用性
- 常用的组件化技术:属性、自定义事件、插槽
- 降低更新范围,值重新渲染变化的组件
- 高内聚、低耦合、单向数据流
对 Vue 组件化的理解
- 组件是独立和可复用的代码组织单元。组件系统是 Vue 核心特性之 一,它使开发者使用小型、独立和通常可复用的组件构建大型应用;
- 组件化开发能大幅提高应用开发效率、测试性、复用性等;
- 组件使用按分类有:页面组件、业务组件、通用组件;
- vue 的组件是基于配置的,我们通常编写的组件是组件配置而非组 件,框架后续会生成其构造函数,它们基于 VueComponent,扩展于 Vue;
- vue 中常见组件化技术有:属性 prop,自定义事件,插槽等,它们 主要用于组件通信、扩展等;
- 合理的划分组件,有助于提升应用性 能;
- 组件应该是高内聚、低耦合的;
- 遵循单向数据流的原则。
vue中异步组件和动态组件的区别是什么
区别:
- 动态组件是vue中一个特殊的html元素“”,它拥有一个特殊的is属性,属性值可以是“已注册组件的名称”或“一个组件的选项对象”;而异步组件不是实物,是一个概念,一个可以让组件异步加载的方式。
- 动态组件用于不同组件之间进行动态切换;而异步组件用于性能优化,比如减小首屏加载时间、加载资源大小。
动态组件:是Vue中一个特殊的Html元素:``,它拥有一个特殊的 is 属性,属性值可以是 已注册组件的名称 或 一个组件的选项对象,它是用于不同组件之间进行动态切换的。
异步组件:简单来说是一个概念,一个可以让组件异步加载的方式;它一般会用于性能优化,比如减小首屏加载时间、加载资源大小。
$route和$router的区别
$route相当于当前正在跳转的路由对象
$router为vueRouter的实例,相当于一个全局路由对象,里面含有很多的属性和子对象
JSON的定义
json是一种轻量级的数据交换格式,是基于JavaScript的一个子集
json转换成js对象(JSON.parse) js对象转换成json(JSON.stringify)
字符串转化为json JSON.parse()json转化为字符串 JSON.stringify()
变量提升和函数提升
变量提升:将var变量的声明提升到所在作用域顶端去执行,赋值仍然在同一行显示
函数提升:将function声明的函数提升到作用域顶端执行,函数提升优先于变量提升
编写一个数组去重的方法
function sort(arr){
for(var i=0; i < arr.length; i++) {
for (var j = i+1; j < arr.length; j++) {
if (arr[i] == arr[j]) {
arr.splice(j,1)
j-- // 删除一个元素后,后面的元素会依次往前,下标也需要依次往前
}
}
}
return arr
}
冒泡算法排序
for (var i=0; i < arr.length-1;i++) {
for (var j=0;j < arr.length-1-i; j++) {
if (arr[j]>arr[j+1]) {
var temp = arr[j]
arr[j] = arr[j+1]
arr[j+1] = temp
}
}
}
Map和weakMap的区别
- Map可以被遍历,weakMap不能被遍历
- Map的键可以是任意类型,weakMap只接受对象作为键(null除外,不接受其他类型的值作为键)
- Map的键实际上是跟内存地址绑定的,只要内存地址不一样,就视为两个键, weakMap的键是弱作用,键所指指向的对象可以被垃圾回收,此时键是无效的
weakMap的应用
数据缓存
部署私有属性
在DOM对象上保存相关数据
介绍下Set和Map的区别
应用场景:Set用于数据重组、Map用于数据储存
Set:
- 成员不能重复
- 只有键值没有键名,类似数组
- 可以遍历,方法有add,delete,has
Map:
- 本质上是键值对的集合,类似集合
- 可以遍历,可以跟各种数据格式转换
Vue3新特性 组合式Api
实现原理:
通过Proxy(代理): 拦截对象中任意属性的变化, 包括:属性值的读写、属性的添加、属性的删除等。
通过Reflect(反射): 对源对象的属性进行操作。
- setup - 组件内使用 Composition API 的入口点
- reactive(对象数据), ref (单值数据)- 数据响应式
- computed - 计算属性
- watchEffect、watch - 侦听器
- watchEffect
立即执行传入的一个函数,并响应式追踪其依赖,并在其依赖变更时重新运行该函数。
watch对比watchEffect,watch允许我们:
- 懒执行副作用,也就是说仅在侦听的源变更时才执行回调;
- 更明确哪些状态的改变会触发侦听器重新运行副作用;
- 访问侦听状态变化前后的值。
toRefs - 解构响应式对象数据
Vue3和Vue2的区别
一、Vue3比Vue2更加友好地集成Typescript
二、响应式原理不同(Vue2是通过ES5的Object.defineProperty,Vue3是通过更快的原生proxy和reflect)
三、Vue3在Vue2的基础更加完善处
1.Vue3性能更比Vue2强(diff算法的优化、静态提升、事件监听缓存)
2.打包更科学,不再打包没用到的模块
3.Composition API(组合式API)
4.Fragment(碎片)、Teleport(传送门)、Suspense(悬念)
5.更加友好的支持和兼容TS
6.Custom Renderer API(自定义渲染API)
Vue2和Vue3的生命周期对比
beforeCreate->setup()
created->setup()
beforeMount->onBeforeMount
mounted->onMounted
beforeUpdate->onBeforeUpdate
updated->onUpdated
beforeDestroy->onBeforeUnmount
destroyed->onUnmounted
activated-> onActivated
deactivated-> onDeactivated
errorCaptured-> onErrorCaptured
| beforeCreate | 组件实例被创建之初,组件的属性生效之前 |
|---|---|
| created | 组件实例已经完全创建,属性也绑定,但真实 dom 还没有生成,$el 还不可用 |
| beforeMount | 在挂载开始之前被调用:相关的 render 函数首次被调用 |
| mounted | el 被新创建的 vm.$el 替换,并挂载到实例上去之后调用该钩子 |
| beforeUpdate | 组件数据更新之前调用,发生在虚拟 DOM 打补丁之前 |
| update | 组件数据更新之后 |
| activated | keep-alive 专属,组件被激活时调用 |
| deactivated | keep-alive 专属,组件被销毁时调用 |
| beforeDestory | 组件销毁前调用 |
| destoryed | 组件销毁后调用 |
vue中父子组件钩子的执行顺序
父组件先于子组件created,而子组件先于父组件mounted
父子组件加载渲染过程:
父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新:父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程:父beforeUpdate->父updated
销毁:父beforeDestroy->子beforeDestroy->子destroyed->父destroyed
created 和 mounted 的区别
- created:在模板渲染成 html 前调用,即通常初始化某些属性值,然 后再渲染成视图。
- mounted:在模板渲染成 html 后调用,通常是初始化页面完成后,再 对 html 的 dom 节点进行一些需要的操作。
一般在哪个生命周期请求异步数据
我们可以在钩子函数 created、beforeMount、mounted 中进行调用, 因为在这三个钩子函数中,data 已经创建,可以将服务端端返回的 数据进行赋值。
推荐在 created 钩子函数中调用异步请求,因为在 created 钩子函 数中调用异步请求有以下优点: 能更快获取到服务端数据,减少页面加载时间,用户体验更好;
SSR 不支持 beforeMount 、mounted 钩子函数,放在 created 中有 助于一致性。
子组件可以直接改变父组件的数据吗?
子组件不可以直接改变父组件的数据。这样做主要是为了维护父子组 件的单向数据流。每次父级组件发生更新时,子组件中所有的 prop 都将会刷新为最新的值。如果这样做了,Vue 会在浏览器的控制台中 发出警告。
Vue项目前端性能优化
- vue-router路由懒加载
- 打包优化-工程文件打包的时候不生成.map文件
- 切换多入口模式
- 使用字体图标代替切图
- 使用雪碧图
- 提取公共样式和方法
- 销毁控件
- 销毁定时器
- 路由离开及时解绑事件vm.off()
- 使用keep-alive
- 代码层面的优化
- iframe的内存释放
Vue数据更新而视图不更新问题?
- 使用Vue.set/Vue.delete (this.$set(this.obj,'e',5))
- 使用vm.forceUpdate()对视图进行强制更新)
- 使用深拷贝,重新赋值替换
Vue上线打包优化
- 禁止生成sourceMap文件
- 关闭prefetch(预先加载模块,提前获取用户未来可能会访问的内容
- 路由懒加载
- ElementUI组件库按需加载
- 使用CDN加载外部资源
- GZIP
- 图片压缩
- 代码压缩
防抖的原理及应用场景
原理:事件响应函数在一段时间之后才会执行,如果在这段时间之内,再次调用,则重新计算执行时间(通过setTimeout的方式,在一定的时间间隔内,将多次触发转变为一次触发)
应用场景:
- scroll时间滚动触发
- 搜索框输入查询
- 表单验证
- 按钮提交事件
- 浏览器窗口缩放
节流的原理及应用场景
原理:如果持续触发事件,每隔一段时间,只执行一次操作(减少一段时间之内的事件触发频率)
应用场景:
- DOM元素的拖拽
- 射击类游戏
- 计算鼠标移动的距离
哪些操作会造成内存泄漏?
内存泄漏指由于疏忽或错误造成程序未能释放已经不再使用的内存
垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收。
针对JavaScript的来及回收机制有以下两种方法(常用):标记清除法,引用计数法
- setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏。
- 闭包
- 控制台日志console
- 没有清理对DOM元素的引用
- 意外的全局变量
new操作符具体干了什么呢?
- 创建一个空对象,并且 this 变量引用该对象,同时还继承了该函数的原型
- 属性和方法被加入到 this 引用的对象中
- 新创建的对象由 this 所引用,并且最后隐式的返回 this
new操作符原理
- 创建个空对象。
- 空对象的proto指向类的prototype。
- 通过this添加属性和方法。
- this指向实例对象。
- 返回实例。
var obj = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
iframe的优缺点?
优点:
- 解决加载缓慢的第三方内容如图标和广告等的加载问题
- Security sandbox
- 并行加载脚本
缺点:
- iframe会阻塞主页面的Onload事件
- 即时内容为空,加载也需要时间
- 没有语意
CSS哪些属性可以继承?哪些属性不可以继承?
可继承的样式:
- font-size
- font-family
- color
- text-indent
- text-align
- line-height
- text-transform
- font-weight
不可继承的样式:
- border
- padding
- margin
- width
- height
px、em与rem的区别?
px像素相对于显示器屏幕分辨率是固定不变的,不受浏览器缩放影响
em相对于父元素的字体大小font-size
rem相对于根元素html的字体大小font-size
Vue首屏白屏原因
- 由于把路由模式mode设置成history了,默认是hash(改为hash或者直接删除模式配置,如果非要用的话,在服务端加一个覆盖所有情况的候选资源。)
- 打包后的dist目录下的文件引用路径不对,因找不到文件而报错导致白屏(修改config下面index.js的模块导出路径。)
- 在项目中使用了es6语法,一些浏览器不支持es6,造成编译错误不能解析而造成白屏(安装Babel ,Babel 会把这些新语法转译成较低版本的代码。)
vue项目实现路由按需加载(路由懒加载)的三种方式:
- Vue异步组件 ## resolve
- ES6标准语法import()---------推荐使用!!!!!
- webpack的require,ensure()
路由传参query和params区别
- 引入方式不同:query使用path引入,params使用name引入
- 接收方式不同:query使用this.route.params.name
- 刷新页面时,query参数不会消失,params参数会消失。
- query传过来的参数会显示在地址栏中、类似于?id=1,params传过来的参数不会显示在地址栏中,直白来说就是query相当于get请求,params相当于post请求。
首屏优化该如何去做
- 使用路由懒加载
- 非首屏组件使用异步组件
- 首屏不重要的组件延迟加载
- 静态资源放在CDN上
- 减少首屏上JS,CSS等资源文件的大小
- 使用服务器渲染
- 尽量减少DOM的数量和层级
- 使用精灵图请求
- 做一些loading
- 开启Gzip压缩
- 图片懒加载
首屏加载白屏怎么进行优化?
- 采用路由懒加载的方式,当用户访问的时候,再加载相应的模块。
- webpack开启gzip压缩。
- 使用CDN减小代码体积加快请求速度。
- 项目打包禁止生成map文件。
- 使用外链css和js文件 。
- 使用骨架屏,在首页加载的时候显示页面结构轮廓。
CDN的作用(为什么静态资源要放在CDN上)
1. 加速网站的访问
2. 为了实现跨运营商、跨地域的全网覆盖
互联不互通、区域ISP地域局限、出口带宽受限制等种种因素都造成了网站的区域性无法访问。CDN加速可以覆盖全球的线路,通过和运营商合作,部署IDC资源,在全国骨干节点商,合理部署CDN边缘分发存储节点,充分利用带宽资源,平衡源站流量。
3. 为了保障你的网站安全
CDN的负载均衡和分布式存储技术,可以加强网站的可靠性,相当无无形中给你的网站添加了一把保护伞,应对绝大部分的互联网攻击事件。防攻击系统也能避免网站遭到恶意攻击。
4. 为了异地备援
当某个服务器发生意外故障时,系统将会调用其他临近的健康服务器节点进行服务,进而提供接近100%的可靠性,这就让你的网站可以做到永不宕机。
5. 为了节约成本投入
使用CDN加速可以实现网站的全国铺设,你根据不用考虑购买服务器与后续的托管运维,服务器之间镜像同步,也不用为了管理维护技术人员而烦恼,节省了人力、精力和财力。
6. 为了让你更专注业务本身
CDN加速厂商一般都会提供一站式服务,业务不仅限于CDN,还有配套的云存储、大数据服务、视频云服务等,而且一般会提供7x24运维监控支持,保证网络随时畅通,你可以放心使用。并且将更多的精力投入到发展自身的核心业务之上。
CSS中 link 和@import 的区别是?
- link属于HTML标签,而@import是CSS提供的;
- 页面被加载的时,link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;
- import只在IE5以上才能识别,而link是HTML标签,无兼容问题;
- link方式的样式的权重 高于@import的权重
BFC(块级格式化上下文,用于清除浮动,防止margin重叠等)
块级格式化上下文,是页面上一个隔离的独立渲染区域,并且有一定的布局规则(容器里面的资源元素不会影响到外面的元素)。
- BFC区域不会与float box重叠
- BFC是页面上的一个独立容器,子元素不会影响到外面
- 计算BFC的高度时,浮动元素也会参与计算
那些元素会生成BFC/如何触发BFC:
- 根元素
- float不为none的元素
- position为fixed和absolute的元素
- display为inline-block、table-cell、table-caption,flex,inline-flex的元素
- overflow不为visible的元素
GET和POST的区别
- 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数据包。
GET和POST区别(高频)
- GET在浏览器回退不会再次请求,POST会再次提交请求
- GET请求会被浏览器主动缓存,POST不会,要手动设置
- GET请求参数会被完整保留在浏览器历史记录里,POST中的参数不会
- GET请求在URL中传送的参数是有长度限制的,而POST没有限制
- GET参数通过URL传递,POST放在Request body中
- GET参数暴露在地址栏不安全,POST放在报文内部更安全
- GET一般用于查询信息,POST一般用于提交某种信息进行某些修改操作
- GET产生一个TCP数据包;POST产生两个TCP数据包
Get和post的选择: 1.私密性的信息请求使用post(如注册、登陆)。 2.查询信息使用get。
请列举几种清除浮动的方法
- 父级div定义 height x
- 结尾处加空div标签 clear:both x
- 父级div定义 伪类:after 和 zoom +
- 父级div定义 overflow:hidden +
- 父级div定义 overflow:auto x
常见浏览器兼容性问题与解决方案?
- 不同浏览器的标签默认的外补丁和内补丁不同——CSS里 *{margin:0;padding:0;}
- 块属性标签float后,又有横行的margin情况下,在IE6显示margin比设置的大——块属性标签float后,又有横行的margin情况下,在IE6显示margin比设置的大
- 设置较小高度标签(一般小于10px),在IE6,IE7,遨游中高度超出自己设置高度——给超出高度的标签 设置overflow:hidden;或者设置行高line-height 小于你设置的高度。
- 行内属性标签,设置display:block后采用float布局,又有横行的margin的情况,IE6间距bug——在display:block;后面加入display:inline;display:table;
- 图片默认有间距——使用float属性为img布局
- 标签最低高度设置min-height不兼容——如果我们要设置一个标签的最小高度200px,需要进行的设置为:{min-height:200px; height:auto !important; height:200px; overflow:visible;}
- 透明度的兼容CSS设置——一般在ie中用的是filter:alpha(opacity=0)和一般就是直接使用opacity:0,对于兼容的
浏览器的内核
- IE: trident 内核
- Firefox : gecko 内核
- Safari:webkit 内核
- Opera: 以前是 presto 内核, Opera 现已改用 Google Chrome 的 Blink 内核
- Chrome:Blink( 基于 webkit , Google 与 Opera Software 共同开发 )
WebSocket的理解
WebSocket是HTML5开始提供的一种浏览器与服务器间进行全双工通讯的网络技术。依靠这种技术可以实现客户端和服务器端的长连接,双向实时通信。
特点:
- 事件驱动
- 异步
- 使用ws或者wss协议的客户端socket
- 能够实现真正意义上的推送功能
缺点:
- 少部分浏览器不支持,浏览器支持的程度与方式有区别。
前端的项目如何进行优化
- 减少请求数量,
- 减少资源大小,
- 优化网络连接,
- 优化资源加载,
- 减少重绘回流,
- 使用性能更好的API和构建优化
web前端项目性能优化
- 减少HTTP请求
- 使用内容发布网络(CDN)
- 添加本地缓存
- 压缩资源文件
- 将CSS样式表放在顶部,把javascript放在底部(浏览器的运行机制决定)
- 避免使用CSS表达式
- 减少DNS查询
- 使用外部javascript和CSS
- 避免重定向
- 图片lazyLoad懒加载
arguments的理解
- arguments是类数组对象,有length属性,不能调用数组方法
- 可用Array.from()转换
- 箭头函数获取arguments(可用…rest参数获取)
箭头函数和function有什么区别
- 箭头函数只能是匿名函数。
- 箭头函数不能用于构造函数,不能用new创建实例对象。
- 箭头函数的this从其所在上下文捕获,而普通函数拥有自己的this。注意:箭头函数的this一旦被捕获,就不会再发生改变,call、apply、bind均无法改变。
- 箭头函数没有arguments参数,取而代之的是三点运算符(...)
- 箭头函数不能使用Generator函数,不能使用yeild关键字。
- 箭头函数不具有prototype原型对象。
- 箭头函数不具有super。
- 箭头函数不具有new.target。
箭头函数的 this 指向哪⾥?
箭头函数不同于传统 JavaScript 中的函数,箭头函数并没有属于⾃ ⼰的 this,它所谓的 this 是捕获其所在上下⽂的 this 值,作为⾃ ⼰的 this 值,并且由于没有属于⾃⼰的 this,所以是不会被 new 调⽤的,这个所谓的 this 也不会被改变。
扩展运算符的作用及使用场景
- 对象的扩展运算符(...)用于取出参数对象中的所有可遍历属性,拷 贝到当前对象之中。
- 数组的扩展运算符可以将一个数组转为用逗号分隔的参数序列,且每 次只能展开一层数组。
事件委托以及冒泡原理
事件委托,又名事件代理。事件委托就是利用事件冒泡(自里向外),就是把子元素的事件都绑定到父元素上。如果子元素阻止了事件冒泡,那么委托也就没法实现了。
事件委托是利用冒泡阶段的运行机制来实现的,就是把一个元素响应事件的函数委托到另一个元素,一般是把一组元素的事件委托到他的父元素上,委托的优点是减少内存消耗,节约效率,动态绑定事件。
指的是,不在事件的发生地(直接dom)上设置监听函数,而是在其父元素上设置监听函数,通过事件冒泡,父元素可以监听到子元素上事件的触发,通过判断事件发生元素DOM的类型,来做出不同的响应。 好处:比较合适动态元素的绑定,新添加的子元素也会有监听函数,也可以有事件触发机制
事件冒泡,就是元素自身的事件被触发后,如果父元素有相同的事件,如onclick事件,那么元素本身的触发状态就会传递,也就是冒到父元素,父元素的相同事件也会一级一级根据嵌套关系向外触发,直到document/window,冒泡过程结束
数组去重的方法
- ES6的set
- indexOf循环去重
- Object 键值对去重;把数组的值存成 Object 的 key 值,比如 Object[value1] = true,在判断另一个值的时候,如果 Object[value2]存在的话,就说明该值是重复的。
- splice循环去重
- 哈希集合循环去重
- for循环嵌套,利用splice()去重;
创建新数组,利用indexOf()去重;
ES6中利用(new Set())去重;
利用数组的sort()去重(相邻元素比较法);
利用数组的includes()去重;
利用数组的filter()去重。
图片的懒加载和预加载
预加载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染。 懒加载:懒加载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数。
两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载。 懒加载对服务器前端有一定的缓解压力作用,预加载则会增加服务器前端压力。
null 和 undefined 的区别?
相同:
在 if 语句中 null 和 undefined 都会转为false两者用相等运算符比较也是相等
首先 Undefined 和 Null 都是基本数据类型,这两个基本数据类型分别都只有一个值,就是 undefined 和 null。
不同:
undefined 代表的含义是未定义,
- 定义了形参,没有传实参,显示undefined
- 一般变量声明了但还没有定义的时候会返回 undefined
- 对象属性名不存在时,显示undefined
- 函数没有写返回值,即没有写return,拿到的是undefined
- null 代表的含义是空对象。也作为对象原型链的终点
- null 主要用于赋值给一些可能会返回对象的变量,作为初始化。
盒子模型的理解
- 标准盒子模型 (content-box)
盒子总宽度 = width + padding + border + margin;
盒子总高度 = height + padding + border + margin
width/height 只是内容高度,不包含 padding 和 border值
- IE 怪异盒子模型 (border-box)
盒子总宽度 = width + margin;
盒子总高度 = height + margin;
width/height 包含了 padding和 border值
元素水平垂直居中的方法有哪些?如果元素不定宽高呢?
- 利用定位+margin:auto
<style>
.father{
width:500px;
height:300px;
border:1px solid #0a3b98;
position: relative;
}
.son{
width:100px;
height:40px;
background: #f0a238;
position: absolute;
top:0;
left:0;
right:0;
bottom:0;
margin:auto;
}
</style>
<div class="father">
<div class="son"></div>
</div>
- 利用定位+margin:负值
<style>
.father {
position: relative;
width: 200px;
height: 200px;
background: skyblue;
}
.son {
position: absolute;
top: 50%;
left: 50%;
margin-left:-50px;
margin-top:-50px;
width: 100px;
height: 100px;
background: red;
}
</style>
<div class="father">
<div class="son"></div>
</div>
- 利用定位+transform
<style>
.father {
position: relative;
width: 200px;
height: 200px;
background: skyblue;
}
.son {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%,-50%);
width: 100px;
height: 100px;
background: red;
}
</style>
<div class="father">
<div class="son"></div>
</div>
- table布局
设置父元素为display:table-cell,子元素设置 display: inline-block。利用vertical和text-align可以让所有的行内块级元素水平垂直居中
<style>
.father {
display: table-cell;
width: 200px;
height: 200px;
background: skyblue;
vertical-align: middle;
text-align: center;
}
.son {
display: inline-block;
width: 100px;
height: 100px;
background: red;
}
</style>
<div class="father">
<div class="son"></div>
</div>
flex布局
<style>
.father {
display: flex;
justify-content: center;
align-items: center;
width: 200px;
height: 200px;
background: skyblue;
}
.son {
width: 100px;
height: 100px;
background: red;
}
</style>
<div class="father">
<div class="son"></div>
</div>
grid布局
<style>
.father {
display: grid;
align-items:center;
justify-content: center;
width: 200px;
height: 200px;
background: skyblue;
}
.son {
width: 10px;
height: 10px;
border: 1px solid red
}
</style>
<div class="father">
<div class="son"></div>
</div>
怎么理解回流跟重绘
在HTML中,每个元素都可以理解成一个盒子,在浏览器解析过程中,会涉及到回流与重绘:
回流:布局引擎会根据各种样式计算每个盒子在页面上的大小与位置
当渲染树中部分或者全部元素的尺寸、结构或者属性发生变化时,浏览器会重新渲染部分或者全部文档的过程
重绘:当计算好盒模型的位置、大小及其他属性后,浏览器根据每个盒子特性进行绘制
当页面中某些元素的样式发生变化,但是不会影响其在文档流中的位置时,浏览器就会对元素进行重新绘制
什么是响应式设计?响应式设计的基本原理是什么?如何做?
响应式网站设计(Responsive Web design)是一种网络页面设计布局,页面的设计与开发应当根据用户行为以及设备环境(系统平台、屏幕尺寸、屏幕定向等)进行相应的响应和调整,是一个网站能够兼容多个终端,而不是为每一个终端做一个特定的版本。
响应式设计的基本原理是通过媒体查询检测不同的设备屏幕尺寸做处理,为了处理移动端,页面头部必须有meta声明viewport
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no”>
属性对应如下:
- width=device-width: 是自适应手机屏幕的尺寸宽度
- maximum-scale:是缩放比例的最大值
- inital-scale:是缩放的初始化
- user-scalable:是用户的可以缩放的操作
实现响应式布局的方式有如下:
- 媒体查询
- 百分比
- vw/vh
- rem
如果要做优化,CSS提高性能的方法有哪些?
- 内联首屏关键CSS
- 异步加载CSS
- 资源压缩
- 合理使用选择器
- 减少使用昂贵的属性
- 不要使用@import
typeof 与 instanceof 区别
typeof 对于原始数据类型来说,除了null都可以正确的显示类型 instanceof 可以正确显示数据类型, 因为它是通过对象的原型链来进行判断的
typeof与instanceof都是判断数据类型的方法,区别如下:
- typeof会返回一个变量的基本类型,instanceof返回的是一个布尔值
- instanceof 可以准确地判断复杂引用数据类型,但是不能正确判断基础数据类型
而typeof 也存在弊端,它虽然可以判断基础数据类型(null 除外),但是引用数据类型中,除了function 类型以外,其他的也无法判断
对闭包的理解?闭包使用场景
闭包就是可以访问其他函数内部变量的函数
我们通常用它来定义私有化的变量和方法,创建一个闭包最简单的方法就是在一个函数内创建一个函数,闭包让你可以在一个内层函数中访问到其外层函数的作用域
它有三个特性是
- 函数内可以再嵌套函数,
- 内部函数可以访问外部的方法和变量,
- 方法和变量不会被垃圾回收机制回收
闭包使用场景 任何闭包的使用场景都离不开这两点:
- 创建私有变量(好比vue里的data 每个data都是一个闭包所以他们互不干扰)
- 延长变量的生命周期
- setTimeout(原生的setTimeout传递的第一个函数不能带参数,通过闭包可以实现传参效果)
- 回调
- 函数防抖
- 封装私有变量
优缺点:它的优点就是可以实现封装和缓存,缺点就是可能会造成内存泄漏的问题
bind、call、apply 区别?
1、相同点
- 三个都是用于改变this指向;
- 接收的第一个参数都是this要指向的对象;
- 都可以利用后续参数传参。
2、不同点
- call和bind传参相同,多个参数依次传入的;
- apply只有两个参数,第二个参数为数组;
- call和apply都是对函数进行直接调用,而bind方法不会立即调用函数,而是返回一个修改this后的函数。
宏任务与微任务
微任务
一个需要异步执行的函数,执行时机是在主函数执行结束之后、当前宏任务结束之前
常见的微任务有:
- Promise.then/Promise.catch/Promise.finally
- MutaionObserver
- Object.observe(已废弃;Proxy 对象替代)
- process.nextTick(Node.js)
宏任务
宏任务的时间粒度比较大,执行的时间间隔是不能精确控制的,对一些高实时性的需求就不太符合
常见的宏任务有:
- script (可以理解为外层同步代码)
- setTimeout/setInterval
- 调用ajax
- UI rendering/UI事件
- postMessage、MessageChannel
- setImmediate、I/O(Node.js)
对BOM的理解,常见的BOM对象你了解哪些?
BOM (Browser Object Model),浏览器对象模型,提供了内容与浏览器窗口进行交互的对象 window、location、navigator 、screen、history
如何通过js判断一个数组?
- 通过instanceof判断
- 通过constructor判断
- 通过Object.prototype.toString.call()判断
- 通过Array.isArray()判断
JS 对象和数组的遍历方法
一、JS 遍历数组 for 循环遍历数组、使用for ……in 遍历数组、for……of 遍历数组、forEach 遍历数组、map遍历数组
- for…in 遍历(当前对象及其原型上的)每一个key,而 for…of遍历(当前对象上的)每一个value;
- for in 以任意顺序遍历对象的可枚举属性,(最好不要用来遍历数组) 因此当迭代那些访问次序重要的 arrays 时用整数索引去进行 for 循环 (或者使用 Array.prototype.forEach() 或 for…of 循环) 。
- (ES6)for…of 允许你遍历 Arrays(数组), Strings(字符串), Maps(映射), Sets(集合)等可迭代的数据结构等。不能遍历普通对象
- forEach 遍历数组,而且在遍历的过程中不能被终止,必须每一个值遍历一遍后才能停下来
二、JS 遍历对象
- for……in 循环遍历对象、
- Object.keys 遍历对象(for…of不能单独来遍历对象,要结合Object.keys一起使用才行)、
- Object.getOwnPropertyNames(obj) 遍历对象
for循环、map方法和forEach区别以及使用
for循环:在需要对数组进行复杂操作或根据某些条件来修改数组元素时,使用for循环可以更灵活地控制遍历过程。如果需要在遍历过程中跳出循环或根据索引访问数组元素,则应该使用for循环。
map方法:当需要对数组中的每个元素进行相同的操作,并返回新的数组时,使用map方法非常方便。它会自动遍历整个数组并将每个元素传递给回调函数,最终返回一个新的由回调函数返回值组成的数组。
forEach方法:与map方法类似,但是不会返回新的数组。如果只需要对数组进行一些简单的操作,而不需要返回新的数组,那么使用forEach方法就比较合适。它会自动遍历整个数组并将每个元素传递给回调函数,但是不会构建新的数组。
for性能最好,其次是forEach,再者是map。
谈谈this对象的理解
- 作为一个函数调用(function),直接被调用(在非严格模式下,this指向window,在严格模式下,this指向undefined
- 作为一个方法(method)被调用(当函数作为一个对象的某个属性时,我们更加习惯称呼这个函数为方法,当通过方法被调用时,this指向的是方法的拥有者)
- 作为一个构造函数(constructor),被实例化(通过构建函数new关键字生成一个实例对象,此时this指向这个实例对象)
- 通过apply,call,bind方法
对promise的了解
Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有all、reject、resolve这几个方法,原型上有then、catch等方法。
Promise对象封装了一个异步操作并且还可以获取成功或失败的结果,主要是解决回调地狱问题(异步任务比较多且之间有相互依赖的关系,代码可读性差,可维护性差)有三种状态:pending初始状态、fullfilled成功状态、rejected失败状态
缺点:
- 无法取消promise,一旦创建它就会立即执行,不能中途取消
- 如果不设置回调,promise内部抛出的错误就无法反馈到外面
- 若当前处于pending状态时,无法得知目前在哪个阶段
原理:
- 构造一个Promise实例,实例需要传递函数的参数,这个函数有两个形参,分别都是函数类型,一个是resolve,一个是reject
- Promise上还有then方法,这个方法就是指定状态改变时的确定操作,resolve是执行第一个函数,reject是执行第二个函数
promise和async await的区别
1.两者都是处理异步请求的方式
2.promise是es6的语法,async await是es7的新特性
3.async await 是基于promise实现的,不能用于普通函数,它和promise一样都是非阻塞的
优缺点:
1.promise是返回的对象要用then().catch()去处理数据和捕获异常,而且书写方式是链式的,容易造成代码多层堆叠难以维护;async await 则是通过try{}.cathc{}进行捕获直接抛出异常
2.async await 最大的有点是使代码看起来向同步一样,一遇到await就立即先返回结果然后再执行后面的操作;promise.then()的方式返回就可能在请求还没返回时就先执行了外面的操作
数据驱动(MVVM)的理解
MVVM表示的是 Model-View-ViewModel
- Model:模型层,负责处理业务逻辑以及和服务器端进行交互
- View:视图层:负责将数据模型转化为UI展示出来,可以简单的理解为HTML页面
- ViewModel:视图模型层,用来连接Model和View,是Model和View之间的通信桥梁
MVVM和MVC 的区别
MVC 是一种设计模式
M:模型层,是应用程序中用于处理应用程序数据逻辑的部分,模型对象负责在数据库中存取数据。
V:视图层,是应用程序中处理数据显示的部分,视图是依据模型数据创建的
C(Controller): 控制层,是应用程序中处理用户交互的部分,控制器接受用户的输入并调用模型和视图去完成用户的需求,控制器本身不输出任何东西和做任何处理,它只是接收请求并决定调用那个模型构建去处理请求,然后在确定用哪个视图来显示返回的数据。
MVVM
M:模型层,就是业务逻辑相关的数据对象,通常从数据库映射而来,我们可以说是与数据库对应的model。
V:视图层。展示出来的用户界面。
VM: 视图模型层,连接view 和 model 的桥梁。因为 model层中的数据往往是不能直接跟 view 中的控件一一对应上的,所以需要在定义一个数据对象专门对应 view 上的控件,而 viewModel 就是把 model 对象封装成可以显示和接受输入的界面数据对象。
view 和 viewModel 之间通过双向数据绑定建立联系,这样当 view 变化时,会自动更新到 viewModel,反之亦然
Vue 模版编译原理
vue 中的模板 template 无法被浏览器解析并渲染,因为这不属于浏 览器的标准,不是正确的 HTML 语法,所有需要将 template 转化成一 个 JavaScript 函数,这样浏览器就可以执行这一个函数并渲染出对 应的 HTML 元素,就可以让视图跑起来了,这一个转化的过程,就成 为模板编译。模板编译又分三个阶段,解析 parse,优化 optimize, 生成 generate,最终生成可执行函数 render。
- 解析阶段:使用大量的正则表达式对 template 字符串进行解析,将 标签、指令、属性等转化为抽象语法树 AST。
- 优化阶段:遍历 AST,找到其中的一些静态节点并进行标记,方便在 页面重渲染的时候进行 diff 比较时,直接跳过这一些静态节点,优 化 runtime 的性能。
- 生成阶段:将最终的 AST 转化为 render 函数字符串。
vue路由的原理
- 监听地址栏中hashchange事件驱动界面变化
- 用pushState记录浏览器的历史,驱动界面发送变化
hash 模式(核心通过监听url中的hash来进行路由跳转)
history模式(模式核心借用 HTML5 history api,api 提供了丰富的 router 相关属性先了解一个几个相关的api)
- history.pushState 浏览器历史纪录添加记录
- history.replaceState修改浏览器历史纪录中当前纪录
- history.popState 当 history 发生变化时触发
Vue路由的hash模式和history模式有什么区别?
- hash的路由地址上有#号,history模式没有
- 在做回车刷新的时候,hash模式会加载对应页面,history会报错404
- hash模式支持低版本浏览器,history不支持,因为是H5新增的API
- hash不会重新加载页面,单页面应用必备
- history需要后台配置
- history有历史记录,H5新增了pushState和replaceState()去修改历史记录,并不会立刻发送请求
Vue组件之间的通信方式都有哪些
- 通过 props 传递
子组件设置props属性,定义接收父组件传递过来的参数
父组件在使用子组件标签中通过字面量来传递值
- $emit 触发自定义事件(适用场景:子组件传递数据给父组件)
子组件通过emit第二个参数为传递的数值
父组件绑定监听器获取到子组件传递过来的参数
- EventBus(使用场景:兄弟组件传值)
创建一个中央事件总线EventBus
兄弟组件通过emit第二个参数为传递的数值
另一个兄弟组件通过$on监听自定义事件
- provide 与 inject
在祖先组件定义provide属性,返回传递的值
在后代组件通过inject接收组件传递过来的值
- vuex作用相当于一个用来存储共享变量的容器(适用场景: 复杂关系的组件数据传递)
state用来存放共享变量的地方
getter,可以增加一个getter派生状态,(相当于store中的计算属性),用来获得共享变量的值
mutations用来存放修改state的方法。
actions也是用来存放修改state的方法,不过action是在mutations的基础上进行。常用来做一些异步操作
vuex刷新数据会丢失吗?怎么解决
vuex肯定会重新获取数据,页面也会丢失数据
-
把数据直接保存在浏览器缓存里(cookie localstorage sessionstorage)
-
页面刷新的时候,再次请求数据,达到可以动态更新的方法
监听浏览器的刷新书简,在刷新前把数据保存到sessionstorage里,刷新后请求数据,请求到了用vuex,如果没有那就用sessionstorage里的数据
vuex和windows全局变量有什么区别
- vuex做的就是状态管理,主要时管理状态的一个库,把项目中公用的一些数据进行存储,某一个组件更改了vuex中的数据,其他相关的组件也会得到快速更新,但是全局变量可以任意修改,不是很安全
- 全局变量可能操作命名污染,但是vuex不会,每个组件可以根据自己vuex的变量名引用不受影响
- vuex处理复杂的项目,嵌套关系复杂的项目效果很明显,针对于demo或者小项目,全局变量也就够用了
$attrs是为了解决什么问题出现的?
- 主要作用是为了实现批量传递数据。
- provide/inject更适合应用在插件中,主要实现跨级数据传递。
浏览器的渲染过程:
- 解析 HTML 构建 DOM(DOM 树),并行请求 css/image/js
- CSS 文件下载完成,开始构建 CSSOM(CSS 树)
- CSSOM 构建结束后,和 DOM 一起生成 Render Tree(渲染树)
- 布局(Layout):计算出每个节点在屏幕中的位置
- 显示(Painting):通过显卡把页面画到屏幕上
从浏览器地址输入url到显示页面的步骤
- 浏览器根据请求的 url 交给 dns 域名解析,找到真实的 ip, 向服务器发送请求;
- 服务器交给后台处理完成后返回数据,浏览器接收文件( html, js, css,图像等);
- 浏览器对加载到的资源( HTML, JS, CSS等)进行语法解析,建立对应的内部数据结构(如 HTML 的DOM );
- 载入解析到的资源文件,渲染页面,完成
CORS 跨域原理
是跨源AJAX请求的根本解决方法。JSONP只能发GET请求,但是CORS允许任何类型的请求。
vue中的diff算法
diff的过程就是调用名为patch的函数,比较新旧节点,一边比较一边给真实的DOM打补丁
其有两个特点:
- 比较只会在同层级进行, 不会跨层级比较
- 在diff比较的过程中,循环从两边向中间比较
Diff算法的步骤:
- Vue的diff算法是平级比较,不考虑跨级比较的情况。内部采用深度递归的方式+双指针方式比较
- 先比较两个节点是不是相同节点
- 相同节点比较属性,复用老节点
- 先比较儿子节点,考虑老节点和新节点儿子的情况
- 优化比较:头头、尾尾、头尾、尾头
- 比对查找,进行复用
for...in 迭代和 for...of 有什么区别
- 推荐在循环对象属性的时候,使用 for...in,在遍历数组的时候的时候使用for...of。
- for in遍历的是数组的索引,而for of遍历的是数组元素值
- for...of 不能循环普通的对象,需要通过和 Object.keys()搭配使用
- for...in 遍历顺序以数字为先 无法遍历 symbol 属性 可以遍历到公有中可枚举的
- 从遍历对象的角度来说,for···in会遍历出来的为对象的key,但for···of会直接报错。
vue组件的封装
- 建立组件的模板,先把架子搭起来,写写样式,考虑好组件的基本逻辑。
- 准备好组件的数据输入。即分析好逻辑,定好 props 里面的数据、类型。
- 准备好组件的数据输出。即根据组件逻辑,做好要暴露出来的方法。
- 封装完毕了,直接调用即可。
vue自定义指令的原理
组件渲染过程
- 解析模版为render函数(或者在开发环境已完成,vue-loader)
- 触发响应式,监听data属性,getter,setter
- 执行render函数,生成vnode,patch(elem,vnode)
vue路由的钩子函数
首页可以控制导航跳转,beforeEach,afterEach,beforeEnter(单个路由独享守卫),beforeRouteEnter,beforeRouteUpdate,beforeRouteLeave等,一般用于页面title的修改。一些需要登录才能调整页面的重定向功能。
- 路由的钩子函数主要有3个参数to,from,next。
- to:route即将进入的目标路由对象。
- from:route当前导航正要离开的路由。
- next:function一定要调用该方法resolve这个钩子。执行效果依赖next方法的调用参数。可以控制网页的跳转
keep-alive的作用是什么?
keep-alive可以实现组件缓存,当组件切换时不会对当前组件进行卸载
- 包裹动态组件时,会缓存不活动的组件实例,主要用于保留组件状态或避免重新渲染
- 常用的两个属性include/exclude,允许组件有条件的进行缓存
- 两个生命周期activated/deactivated,用来得知当前组件是否处于活跃状态
在Vue中使用插件的步骤
采用ES6的import ... from ...语法或CommonJS的require()方法引入插件
使用全局方法Vue.use( plugin )使用插件,可以传入一个选项对象Vue.use(MyPlugin, { someOption: true })
Vue.use是干什么的?
Vue.use是用来使用插件的。我们可以在插件中扩展全局组件、指令、原型方法等。 会调用install方法将Vue的构建函数默认传入,在插件中可以使用vue,无需依赖vue库
组件写name有啥好处?
增加name属性,会在components属性中增加组件本身,实现组件的递归调用。 可以表示组件的具体名称,方便调试和查找对应的组件。
指令v-el的作用是什么
提供一个在页面上已存在的 DOM元素作为 Vue实例的挂载目标.可以是 CSS 选择器,也可以是一个 HTMLElement 实例,
Generator
是 ES6中新增的语法,和 Promise 一样,都可以用来异步编程。Generator函数可以说是Iterator接口的具体实现方式。Generator 最大的特点就是可以控制函数的执行。
- function* 用来声明一个函数是生成器函数,它比普通的函数声明多了一个*,*的位置比较随意可以挨着 function 关键字,也可以挨着函数名
- yield 产出的意思,这个关键字只能出现在生成器函数体内,但是生成器中也可以没有yield 关键字,函数遇到 yield 的时候会暂停,并把 yield 后面的表达式结果抛出去
- next作用是将代码的控制权交还给生成器函数
scoped
在vue文件中的style标签上,有一个特殊的属性:scoped。
原理:
当一个style标签拥有scoped属性时,它的CSS样式就只能作用于当前的组件,通过该属性,可以使得组件之间的样式不互相污染。
为组件实例生成一个唯一标识,给组件中的每个标签对应的dom元素添加一个标签属性,data-v-xxxx 给中的每个选择器的最后一个选择器添加一个属性选择器,原选择器[data-v-xxxx],如:原选择器为.container #id div,则更改后选择器为.container #id div[data-v-xxxx]
Vue 组件 data 为什么必须是函数
主要是为了防止组件与组件之间声明的变量互相影响。
每个组件都是 Vue 的实例。 组件共享 data 属性,当 data 的值是同一个引用类型的值时,改变其中一个会影响其他
对象为引用类型,当重用组件时,由于数据对象指向同一个data对象,当在一个组件中修改data时,其他重用的组件中的data会同时被修改,而使用返回对象的函数,由于每次返回的都是一个新对象(Object的实例),引用地址不同,则不会出现这个问题
实现一个trim方法
- 通过原型创建字符串的trim()
//去除字符串两边的空白
String.prototype.trim=function(){
return this.replace(/(^\s*)|(\s*$)/g, "");
}
//只去除字符串左边空白
String.prototype.ltrim=function(){
return this.replace(/(^\s*)/g,"");
}
//只去除字符串右边空白
String.prototype.rtrim=function(){
return this.replace(/(\s*$)/g,"");
}
2. 通过函数实现
function trim(str){
return str.replace(/(^\s*)|(\s*$)/g, "");
}
JS中数据类型的判断( typeof,instanceof,constructor,Object.prototype.toString.call())
- typeof 对于原始类型来说,除了 null 都可以显示正确的类型
- instanceof 可以正确的判断对象的类型,因为内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。
- constructor
- Object.prototype.toString.call() 使用 Object 对象的原型方法 toString ,使用 call 进行狸猫换太子,借用Object的 toString 方法
Vue数据更新但页面没有更新的多种情况
-
Vue 无法检测实例被创建时不存在于 data 中的 变量
原因:由于 Vue 会在初始化实例时对 data中的数据执行 getter/setter 转化,所以 变量必须在 data 对象上存在才能让 Vue 将它转换为响应式的。
-
vue也不能检测到data中对象的动态添加和删除
-
数组的时候,不能通过索引直接修改或者赋值,也不能修改数组的长度
-
异步获取接口数据,DOM数据不发现变化
-
循环嵌套层级太深,视图不更新
-
路由参数变化时,页面不更新(数据不更新)
Proxy 相比较于 defineProperty 的优势
Object.defineProperty 是监听对象的字段而非对象本身,因此对于动态插入对象的字段,它无能为了,只能手动为其设置设置监听属性。同时,Object.defineProperty 无法监听对象中数组的变化
这个方法接收三个参数:
1.属性所在的对象
2.属性的名字
3.一个描述符对象(
1.configurable:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性,默认值为false。
2.enumerable:表示能否通过for in循环访问属性,默认值为false
3.writable:表示能否修改属性的值。默认值为false。
4.value:包含这个属性的数据值。默认值为undefined
)
Proxy 叫做代理器,它可以为一个对象设置代理,即监听对象本身,任何访问当前被监听的对象的操作,无论是对象本身亦或是对象的字段,都会被 Proxy 拦截,因此可以使用它来做一些双向绑定的操作。
鉴于兼容性的问题,目前仍然主要是使用 Object.defineProperty 更多,但是随着 Vue/3 的发布,Proxy 应该会逐渐淘汰 Object.defineProperty。
Vue3为什么使用proxy
- proxy补兼容ie浏览器
- proxy对代理对象的监听更加丰富
- proxy代理对象会生成新的对象,不会修改代理对象本身
- proxy可以代理整个对象,defineproperty只代理对象上的某个属性
CSS预编译(Sass、Less、Stylus)
预先编译处理CSS。它扩展了 CSS 语言,增加了变量、Mixin、函数等编程的特性,使 CSS 更易维护和扩展。CSS预编译的工作原理是提供便捷的语法和特性供开发者编写源代码,随后经过专门的编译工具将源码转化为CSS语法。
v-for 与 v-if 的优先级
v-for 比 v-if 优先,如果每一次都需要遍历整个数组,将会影响速度,尤其是当之需要渲染很小一部分的时候。
为什么Vue中的v-if和v-for不建议一起用?
v-for 优先级是比 v-if 高 这时候我们可以看到,v-for 与 v-if 作用再不同标签时候,是先进性判断,再进行列表的渲染 首先,v-for和v-if 不能在同一个标签中使用。
先处理v-for,再处理v-if。 如果同时遇到的时候,应该考虑先用计算属性处理数据,在进行v-for,可以减少循环次数。
为何v-for要用key
- 必须用key,而且不能用index和random
- key是vue中Vnode的唯一标记,通过这个key,我们的diff操作可以更准确,更快捷
- 在diff算法中用tag和key来判断,是否是sameNode
- 可以减少渲染次数,提高渲染性能
vue插槽(slot)的使用
vue的slot分为三种::匿名插槽,具名插槽, 作用域插槽
作用:让父组件可以向子组件指定位置插入 html 结构,也是一种组件间通信的方式,适用于父组 件=>子组件
一.匿名插槽
- 带有插槽 的组件 TipsText.vue(子组件) 作为我们想要插入内容的占位符
二.具名插槽 (给插槽加入name属性就是具名插槽)
三.作用域插槽
Vue的普通Slot以及作用域Slot的区别
- 普通插槽是渲染后做替换的工作。父组件渲染完毕后,替换子组件的内容。
- 作用域插槽可以拿到子组件里面的属性。在子组件中传入属性然后渲染。
Vue如何创建插件
- 新建一个plugins.js的文件(文件名可以不是plugins)
- plugins.js内容:
必须有install()函数,第一参数是Vue的构造函数,剩余参数可自己传入
Javascript 的作用域和作用域链
作用域是定义变量的区域,它有一套访问变量的规则
作用域就是一个变量可以使用的范围,主要分为全局作用域、函数局部作用域和块级作用域
内部函数访问外部函数的变量,会一级一级向上查找父级作用域的变量,采取的是链式查找的方式来决定取哪个值,这种结构称为作用域链(类似于就近原则)
鼠标事件 mouseenter与mouseover区别
- mouseenter: 鼠标进入被绑定事件监听元素节点时触发一次,再次触发是鼠标移出被绑定元素,再次进入时。而当鼠标进入被绑定元素节点触发一次后没有移出,即使鼠标动了也不再触发。
- mouseover: 鼠标进入被绑定事件监听元素节点时触发一次,如果目标元素包含子元素,鼠标移出子元素到目标元素上也会触发。
- mouseenter 不支持事件冒泡 mouseover 会冒泡
vue中 methods,computed, watch 的区别
- computed 是vue中的计算属性,具有缓存性,当他的依赖于值,发生改变的时候才会重新调用
- methods 是没有缓存的,只要调用,就会执行,一般结合事件来使用
- watch 没有缓存性 监听data中的属性 属性值只要发生变化就会执行 可以利用他的特性做一些异步的操作
computed 和 watch 区别
- computed是计算属性,watch是监听,监听的是data中数据的变化
- computed是支持缓存,依赖的属性值发生变化,计算属性才会重新计算,否则用缓存;watch不支持缓存
- computed不支持异步,watch是可以异步操作
- computed是第一次加载就监听,watch是不监听
- computed函数中必须有return,watch不用
cookie与session的区别
- cookie数据存放在客户端上,session数据放在服务器上。
- cookie不是很安全,别人可以分析存放在本地的COOKIE并进行COOKIE欺骗考虑到安全应当使用session。
- session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用COOKIE。
- 单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
- 所以个人建议:
- 将登陆信息等重要信息存放为SESSION
- 其他信息如果需要保留,可以放在COOKIE中
cookies,sessionStorage 和 localStorage 的区别?
- cookie:一个大小不超过4K的小型文本数据,一般由服务器生成,可以设置失效时间;若没有设置时间,关闭浏览器cookie失效,若设置了 时间,cookie就会存放在硬盘里,过期才失效,每次http请求,header都携带cookie
- localStorage:5M或者更大,永久有效,窗口或者浏览器关闭也会一直保存,除非手动永久清除或者js代码清除,因此用作持久数据,不参与和服务器的通信
- sessionStorage关闭页面或浏览器后被清除。存 放数据大小为一般为 5MB,而且它仅在客户端(即浏览器)中保存,不参与和服务器的通信。
相同:都可以用来存储数据。
区别:
- cookie一条数据大小不能超过4KB ,最多不能存储超过20条,如果没有设置过期时间,那么在浏览器关闭后消失。
- sessionStorage是会话存储,一条大小不能超过5M,数量没有限制,关掉页面数据消失。
- localStorage本地存储,一条大小不超过5M,数量没有限制,除非主动删除,否则数据不会消失。
浏览器的本地存储
浏览器的本地存储主要分为Cookie、WebStorage和IndexDB, 其中WebStorage又可以分为localStorage和sessionStorage。
共同点: 都是保存在浏览器端、且同源的
不同点:
cookie数据始终在同源的http请求中携带(即使不需要),即cookie在浏览器和服务器间来回传递。cookie数据还有路径(path)的概念,可以限制cookie只属于某个路径下sessionStorage和localStorage不会自动把数据发送给服务器,仅在本地保存。
存储大小限制也不同, cookie数据不能超过4K,sessionStorage和localStorage可以达到5M sessionStorage:仅在当前浏览器窗口关闭之前有效; localStorage:始终有效,窗口或浏览器关闭也一直保存,本地存储,因此用作持久数据; cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
作用域不同 sessionStorage:不在不同的浏览器窗口中共享,即使是同一个页面; localstorage:在所有同源窗口中都是共享的;也就是说只要浏览器不关闭,数据仍然存在 cookie: 也是在所有同源窗口中都是共享的.也就是说只要浏览器不关闭,数据仍然存在
offset、client、scroll的用法?
- offset系列 经常用于获得元素位置 offsetLeft offsetTop
- client经常用于获取元素大小 clientWidth clientHeight
- scroll 经常用于获取滚动距离 scrollTop scrollLeft
require与import的区别和使用
require与import的区别
- require是CommonJS规范的模块化语法,import是ECMAScript 6规范的模块化语法;
- require是运行时加载,import是编译时加载;
- require可以写在代码的任意位置,import只能写在文件的最顶端且不可在条件语句或函数作用域中
使用:
- require通过module.exports导出的值就不能再变化,import通过export导出的值可以改变;
- require通过module.exports导出的是exports对象,import通过export导出是指定输出的代码;
- require运行时才引入模块的属性所以性能相对较低,import编译时引入模块的属性所所以性能稍高。
虚拟dom
虚拟dom他不并不是真实的 dom ,是根据模板生成一个js对象(使用createElement,方法),根据这个js对象再去生成真实的dom,对复杂的文档DOM结构,提供一种方便的工具,进行最小化的DOM操作 ,是可以快速的渲染和高效的更新元素,提高浏览器的性能。
Virual DOM是用JS对象记录一个dom节点的副本,当dom发生更改时候,先用虚拟dom进行diff,算出最小差异,然后再修改真实dom。
虚拟DOM的缺点:
- 代码更多,体积更大
- 内存占用增大
- 小量的单一的dom修改使用虚拟dom成本反而更高,不如直接修改真实dom快
为什么要用虚拟DOM来描述真实的DOM呢?
创建真实DOM成本比较高,如果用 js对象来描述一个dom节点,成本比较低,另外我们在频繁操作dom是一种比较大的开销。所以建议用虚拟dom来描述真实dom。
Vue为什么要用虚拟Dom
虚拟dom就是用js对象来描述真实Dom,是对真实Dom的抽象
由于直接操作Dom性能低,但是js层的操作效率高,可以将Dom操作转化成对象操作。最终通过diff算法比对差异进行更新Dom
虚拟Dom不依赖真实平台环境,可以实现跨平台
虚拟 DOM 的解析过程
首先对将要插入到文档中的 DOM 树结构进行分析,使用 js 对象将 其表示出来,比如一个元素对象,包含 TagName、props 和 Children 这些属性。然后将这个 js 对象树给保存下来,最后再将 DOM 片段 插入到文档中。
当页面的状态发生改变,需要对页面的 DOM 的结构进行调整的时候, 首先根据变更的状态,重新构建起一棵对象树,然后将这棵新的对象 树和旧的对象树进行比较,记录下两棵树的的差异。
后将记录的有差异的地方应用到真正的 DOM 树中去,这样视图就 更新了。
虚拟DOM的实现原理
虚拟 DOM 的实现原理主要包括以下 3 部分:
- 用 JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象
- diff 算法 — 比较两棵虚拟 DOM 树的差异
- patch 算法(打补丁) — 将两个虚拟 DOM 对象的差异应用到真正的 DOM 树
JavaScript 对象模拟真实 DOM 树,对真实 DOM 进行抽象。vue 是通过 createElement 生成 VNode。
虚拟 DOM 就是用 JS 来描述一个真实的 DOM 节点。而在 Vue 中就存在了一个 VNode 类,通过这个类,我们就可以实例化出不同类型的虚拟 DOM 节点。Vue 中 VNode 的类型:
- 注释节点
- 文本节点
- 元素节点
- 组件节点
- 函数式组件节点
- 克隆节点
虚拟 DOM 其实说白了就是以 JS 的计算性能来换取操作真实 DOM 所消耗的性能。当数据发生变化时,我们对比变化前后的虚拟DOM节点,通过DOM-Diff算法计算出需要更新的地方,然后去更新需要更新的视图。
creatElement()
- context 表示 VNode 的上下文环境,是 Component 类型
- tag 表示标签,它可以是一个字符串,也可以是一个 Component 类型
- data 表示 VNode 的数据,它是一个 VNodeData 类型
- children 表示当前 VNode 的子节点,它是任意类型的
- normalizationType 表示子节点规范的类型,类型不同规范的方法也就不一样,主要是参考 render 函数是编译生成的还是用户手写的
normalizeChildren 方法调用场景分为下面两种:
-
render 函数是用户手写的
-
编译 slot、v-for 的时候会产生嵌套数组
createComponent
createComponent 生成 VNode 的三个关键流程:
- 构造子类构造函数 Ctor
- installComponentHooks 安装组件钩子函数
- 实例化 vnode
vue 初始化页面闪动问题。
能够解决插值表达式闪烁问题,需要在style中设置样式[v-clock]{display:none}
v-if和v-show的区别及使用场景?
- v-if 动态的创建或者销毁元素,为true的时候为显示,为false的时候不显示,要使用v-else必须和v-if紧挨着
- v-show 是控制元素的显示或者隐藏,在我们的标签上会看到有display:block,none
- v-if 有更高的切换消耗,而 v-show 有更高的初始化渲染消耗,一般推荐频繁切换的时候使用 v-show 更好,当我们的判断分支比较多的时候,和首次渲染的时候 使用v-if
nextTick 使用场景和原理
在下次DOM更新循环结束后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的DOM。
使用场景是:可以在created钩子函数中拿到dom节点
- nextTick是一个微任务。
- nextTick中的回调是在下次Dom更新循环结束之后执行的延迟回调
- 可以用于获取更新后的Dom
- Vue中的数据更新是异步的,使用nextTick可以保证用户定义的逻辑在更新之后执行
- nextTick 中的回调是在下次 DOM 更新循环结束之后执行的延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。主要思路就是采用微任务优先的方式调用异步方法去执行 nextTick 包装的方法
nextTick 的 核 心 是 利 用 了 如 Promise 、 MutationObserver 、 setImmediate、setTimeout 的原生 JavaScript 方法来模拟对应的 微/宏任务的实现,本质是为了利用 JavaScript 的这些异步回调任 务队列来实现 Vue 框架中自己的异步回调队列。
javascript 创建对象的几种方式
我们一般使用字面量的形式直接创建对象
- 第一种是工厂模式,工厂模式的主要工作原理是用函数来封装创建对象的细节,从而通过调用函数来达到复用的目的。
- 第二种是构造函数模式。js 中每一个函数都可以作为构造函数,只要一个函数是通过 new 来调用的,那么我们就可以把它称为构造函数。
- 第三种模式是原型模式,因为每一个函数都有一个 prototype 属性,这个属性是一个对象,它包含了通过构造函数创建的所有实例都能共享的属性和方法。
- 第四种模式是组合使用构造函数模式和原型模式,这是创建自定义类型的最常见方式。
- 第五种模式是动态原型模式,这一种模式将原型方法赋值的创建过程移动到了构造函数的内部,通过对属性是否存在的判断,可以实现仅在第一次调用函数时对原型对象赋值一次的效果。
- 第六种模式是寄生构造函数模式,这一种模式和工厂模式的实现基本相同。
Vue中使用了哪些设计模式?
- 工厂模式-传入参数即可创建实例(虚拟DOM根据参数的不同返回基础标签的VNode和组件Vnode)
- 单例模式-整个程序有且仅有一个实例(Vuex和vue-router的插件注册方法install判断如果系统存在实例就直接返回)
- 发布-订阅模式(vue事件机制)
- 观察者模式(响应式数据原理)
- 装饰器模式(@装饰器的用法)
- 策略模式(对象有某个行为,但是在不同的场景中,但是在不同的场景中,该行为有不同的实现方案-比如选项的合并策略)
Javascript拖拽功能事件
- dragstart、drag、dragenter、dragover、dragleave、drop、dragend
- mousedown、mousemove、mouseup (涉及到拖拽效果中的事件)
git基础命令
- git init 把这个目录变成git可以管理的仓库
- git add 不但可以跟单一文件,也可以跟通配符,更可以跟目录。一个点就把当前目录下所有未追踪的文件全部add了
- git commit -m ‘first commit’把文件提交到仓库
- git remote add origin +//仓库地址 //关联远程仓库
- git push -u origin master //把本地库的所有内容推送到远程库上
git 发生冲突的场景?如何解决?
当Git无法自动合并分支时,就必须首先解决冲突,解决冲突后,再提交,合并完成
解决冲突就是把Git合并失败的文件手动编辑为我们希望的内容,再提交
git命令
- git init 初始化git仓库 (mac中Command+Shift+. 可以显示隐藏文件)
- git status 查看文件状态
- git add 文件列表 追踪文件
- git commit -m 提交信息 向仓库中提交代码
- git log 查看提交记录
1.分支明细
(1)主分支(master):第一次向 git 仓库中提交更新记录时自动产生的一个分支。
(2)开发分支(develop):作为开发的分支,基于 master 分支创建。
(3)功能分支(feature):作为开发具体功能的分支,基于开发分支创建
2.分支命令
(1)git branch 查看分支
(2)git branch 分支名称 创建分支
(3)git checkout 分支名称 切换分支
(4)git merge 来源分支 合并分支 (备注:必须在master分支上才能合并develop分支)
(5)git branch -d 分支名称 删除分支(分支被合并后才允许删除)(-D 强制删除)
3.暂时保存更改
(1)存储临时改动:git stash
(2)恢复改动:git stash pop
Http和Https区别
HTTP —— 超文本传输协议
HTTPS —— 超文本传输安全协议
HTTP的URL 以http:// 开头,而HTTPS 的URL 以https:// 开头HTTP是不安全的,而 HTTPS 是安全的HTTP标准端口是80 ,而 HTTPS 的标准端口是443在OSI网络模型中,HTTP工作于应用层,而HTTPS 的安全传输机制工作在传输层HTTP无法加密,而HTTPS 对传输的数据进行加密,证的网络协议,安全性高于HTTP协议。HTTP无需证书,而HTTPS 需要CA机构wosign的颁发的SSL证书,一般免费证书少,因而需要一定费用。
http状态码301和302详解及区别
一般以3XX开头的代表重定向,表示网页发生了转移,需要重定向到对应的地址中去,两者区别是:
301:表示永久性转移(Permanently Moved)
302:表示临时性转移(Temporarily Moved)
实现一个三角形(CSS绘制三角形主要用到的是border属性,也就是边框)
div {
width: 0;
height: 0;
border-top: 100px solid red;
border-right: 100px solid transparent;
}
画一条0.5px的线
采用transform: scale()的方式,该方法用来定义元素的2D 缩放转换(transform: scale(0.5,0.5);)
设置小于12px的字体
在谷歌下css设置字体大小为12px及以下时,显示都是一样大小,都是默认12px。
解决办法: 使用Webkit的内核的-webkit-text-size-adjust的私有CSS属性来解决,只要加了-webkit-text-size-adjust:none;字体大小就不受限制了。但是chrome更新到27版本之后就不可以用了。所以高版本chrome谷歌浏览器已经不再支持-webkit-text-size-adjust样式,所以要使用时候慎用。 使用css3的transform缩放属性-webkit-transform:scale(0.5); 注意-webkit-transform:scale(0.75);收缩的是整个元素的大小,这时候,如果是内联元素,必须要将内联元素转换成块元素,可以使用display:block/inline-block/...; 使用图片:如果是内容固定不变情况下,使用将小于12px文字内容切出做图片,这样不影响兼容也不影响美观。
Vue中如何检测数组的变化?
vue中对数组没有进行defineProperty,而是重写了数组的7个方法。 分别是:
- push
- shift
- pop
- splice
- unshift
- sort
- reverse
因为这些方法都会改变数组本身。
数组里的索引和长度是无法被监控的。
不改变原始数组的方法:
- concat
- join
- slice
- JSON.parse(JSON.stringify(arry))
- map
- some
- every
- filter
vue.mixin的使用场景和原理?
Vue的mixin的作用就是抽离公共的业务逻辑,原理类似对象的继承,当组件初始化的时候,会调用mergeOptions方法进行合并,采用策略模式针对不同的属性进行合并。
如果混入的数据和本身组件的数据有冲突,采用本身的数据为准。
缺点:命名冲突、数据来源不清晰
深拷贝和浅拷贝的区别
深拷贝和浅拷贝都是指的对象的拷贝
1.浅拷贝,只会拷贝基本数据类型的值和实际的引用地址,实际指向还是同一个对象,对基本类型数据修改,原对象也会紧接着修改
常见的浅拷贝:
- Object.assign
- Object.create
- slice
- concat()
- 拓展运算符
2.深拷贝,基本数据类型和所指向的对象都会进行复制,内部实际指向的不是一个对象,所以在做修改时两者不会同时改变
常见的深拷贝方式有:
- _.cloneDeep()
- jQuery.extend()
- 手写循环递归
- JSON.parse(JSON.stringify())
- JSON.stringify()# 的缺点
-
无法处理函数和 undefined
-
无法处理循环引用
-
无法处理一些特殊对象
-
对象的原型链上的属性会丢失
(浅拷贝相当于投屏,电脑屏幕使用的不一样,思维是一样的两者同步操作)
(深拷贝相当于克隆羊,除了长的一样其他的头脑思想等等都是不一样的)
微信小程序的理解?优缺点
小程序是一种不需要下载安装即可使用的应用,它实现了应用“触手可及”的梦想,用户扫一扫或者搜一下即可打开应用
也体现了“用完即走”的理念,用户不用关心是否安装太多应用的问题。应用将无处不在,随时可用,但又无需安装卸载
优点:
- 随搜随用,用完即走:使得小程序可以代替许多APP,或是做APP的整体嫁接,或是作为阉割版功能的承载体
- 流量大,易接受:小程序借助自身平台更加容易引入更多的流量
- 安全
- 开发门槛低
- 降低兼容性限制
缺点:
- 用户留存:及相关数据显示,小程序的平均次日留存在13%左右,但是双周留存骤降到仅有1%
- 体积限制:微信小程序只有2M的大小,这样导致无法开发大型一些的小程序
- 受控微信:比起APP,尤其是安卓版的高自由度,小程序要面对很多来自微信的限制,从功能接口,甚至到类别内容,都要接受微信的管控
请谈谈wxml与标准的html的异同
- 都是用来描述页面的结构
- 都由标签,属性等构成
- 标签名字不一样,且小程序标签更少,单一标签更多
- 多了一些 wx:if 这样的属性以及{{}} 这样的表达式
- WXML仅能在微信小程序开发者工具中预览,而HTML可以在浏览器内预览
- 组件封装不同,WXML对组件进行了重新封装
- 小程序运行在JS Core内,没有DOM树和windiw对象,小程序中无法使用window对象和document对象。
请谈谈WXSS和CSS的异同
都是用来描述页面的样子
- WXSS具有CSS大部分的特性,也做了一些扩充和修改
- WXSS新增了尺寸单位,WXSS在底层支持新的尺寸单位rpx
- WXSS仅支持部分CSS选择器
- WXSS提供全局样式与局部样式
小程序页面之间有哪些(传值)传递数据的方法
- 使用全局遍历实现数据传递
- 页面跳转或重定向时,使用url带参数传递数据
- 使用组件模板 template传递参数
- 使用缓存传递参数
- 使用数据库传递参数
- 给html元素添加data-*属性来传递值,然后通过e.currentTarget.dataset或onload的param参数获取(data- 名称不能有大写字母,不可以存放对象)
- 设置id 的方法标识来传值,通过e.currentTarget.id获取设置的id值,然后通过设置全局对象的方式来传递数据
- 在navigator中添加参数数值
谈谈小程序的双向绑定和vue的异同?
大体相同,但小程序之间this.data的属性是不可以同步到视图的,必须调用this.setData()方法
小程序的生命周期函数
- onLoad()页面加载时触发,只会调用一次,可获取当前页面路径中的参数
- onShow()页面显示/切入前台时候触发,一般用来发送数据请求
- onReady()页面初次渲染完成时触发,只会调用一次,代表页面已可和视图层进行交互
- onHide()页面隐藏/切入后台时触发,如底部tab切换到其他页面或小程序切入后台等
- onUnload()页面卸载时触发,如redirectTO或navigateBack到其他页面时
微信小程序和H5的区别
运行环境不同(小程序在微信运行,h5在浏览器运行) 开发成本不同(h5需要兼容不同的浏览器) 获取系统权限不同(系统级权限可以和小程序无缝衔接) 应用在生成环境的运行速度流程(h5需不断对项目优化来提高用户体验)
微信小程序如何实现下拉刷新
用view代替scroll-view,设置onPullDownRefresh函数实现
bindtap和catchtap的区别
bind事件绑定不会阻止冒泡事件向上冒泡 catch事件绑定可以阻止冒泡事件向上冒泡
wx.navigateTo(),wx.redirectTo(),wx.switchTab(),wx.navigateBack(),wx.reLaunch()的区别
- 在wxml页面中:跳转新页面,在当前页打开,切换到首页Tab
- 在js页面中:分为应用内的页面,和tabBar页面
如果上述跳转遇到跳转失败或者无效的问题,请访问:wx.navigateTo/wx.redirectTo无效
小程序和Vue写法的区别?
- 遍历的时候:小程序wx:for=“list”,而Vue是v-for=“item in list”
- 调用data模型(赋值)的时候:
- 小程序:this.data.item // 调用,this.setDate({item:1})//赋值
- Vue:this.item //调用,this.item=1 //赋值
小程序的发布流程(开发流程)
- 注册微信小程序账号
- 获取微信小程序的AppID
- 下载微信小程序开发者工具
- 创建demo项目
- 去微信公众号配置域名
- 手机浏览
- 代码上传
- 提交审核
- 小程序发布
小程序授权登录流程
授权,微信登录获取code,微信登录,获取iv , encryptedData 传到服务器后台,如果没有注册,需要注册
小程序支付如何实现
- 小程序注册,要以公司的身份去注册一个小程序,才有微信支付权限
- 绑定商户号
- 在小程序填写合法域
- 调用wx.login()获取appid
- 调用
wx.requestPayment(
{
'timeStamp': '',//时间戳从1970年1月1日00:00:00至今的秒数,即当前的时间
'nonceStr': '',//随机字符串,长度为32个字符以下。
'package': '',//统一下单接口返回的 prepay_id 参数值,提交格式如:prepay_id=*
'signType': 'MD5',//签名类型,默认为MD5,支持HMAC-SHA256和MD5。注意此处需与统一下单的签名类型一致
'paySign': '',//签名,具体签名方案参见微信公众号支付帮助文档;
'success':function(res){},//成功回调
'fail':function(res){},//失败
'complete':function(res){}//接口调用结束的回调函数(调用成功、失败都会执行)
})
uniapp实现下拉刷新
需要用到uni.onPullDownRefresh和uni.stopPullDownRefresh
uniapp实现上拉加载
通过onReachBottom(),在此函数内调用分页接口请求数据,用以获取更多的数据
对 TypeScript 的理解?与 JavaScript 的区别
TypeScript 是 JavaScript 的类型的超集,支持ES6语法,支持面向对象编程的概念,如类、接口、继承、泛型等,其是一种静态类型检查的语言,提供了类型注解,在代码编译阶段就可以检查出数据类型的错误,TypeScript在编译阶段需要编译成JavaScript来运行
特性:
- 类型批注和编译时类型检查 :在编译时批注变量类型
- 类型推断:ts 中没有批注变量类型会自动推断变量的类型
- 类型擦除:在编译过程中批注的内容和接口会在运行时利用工具擦除
- 接口:ts 中用接口来定义对象类型
- 枚举:用于取值被限定在一定范围内的场景
- Mixin:可以接受任意类型的值
- 泛型编程:写代码时使用一些以后才指定的类型
- 名字空间:名字只在该区域内有效,其他区域可重复使用该名字而不冲突
- 元组:元组合并了不同类型的对象,相当于一个可以装不同类型数据的数组
类型批注 通过类型批注提供在编译时启动类型检查的静态类型
类型推断 当类型没有给出时,TypeScript 编译器利用类型推断来推断类型
接口简单来说就是用来描述对象的类型 数据的类型有 number、null、string 等数据格式,对象的类型就是用接口来描述的
TypeScript 的主要特点是什么?
- 跨平台:TypeScript 编译器可以安装在任何操作系统上,包括 Windows、macOS 和 Linux。
- ES6 特性:TypeScript 包含计划中的 ECMAScript 2015 (ES6) 的大部分特性,例如箭头函数。
- 面向对象的语言:TypeScript 提供所有标准的 OOP 功能,如类、接口和模块。
- 静态类型检查:TypeScript 使用静态类型并帮助在编译时进行类型检查。因此,你可以在编写代码时发现编译时错误,而无需运行脚本。
- 可选的静态类型:如果你习惯了 JavaScript 的动态类型,TypeScript 还允许可选的静态类型。
- DOM 操作:您可以使用 TypeScript 来操作 DOM 以添加或删除客户端网页元素。
使用 TypeScript 有什么好处?
- TypeScript 更具表现力,这意味着它的语法混乱更少。
- 由于高级调试器专注于在编译时之前捕获逻辑错误,因此调试很容易。
- 静态类型使 TypeScript 比 JavaScript 的动态类型更易于阅读和结构化。
- 由于通用的转译,它可以跨平台使用,在客户端和服务器端项目中。
TypeScript 中的接口是什么?
接口为使用该接口的对象定义契约或结构。 接口是用关键字定义的interface,它可以包含使用函数或箭头函数的属性和方法声明。
interface和type的主要区别
- 类型别名可以用于其他类型(联合类型、元组类型、基本类型(原始值)),interface不支持
- interface可以多次定义并被视为合并所有声明成员,type不支持
- type能使用in关键字生成映射类型,但interface不行
- interface支持同时声明,默认导出,而type必须先声明后导出
-
- interface可以重复声明,type定义后不能重复声明
-
- interface可以通过“extends”来继承接口,这样既高效又不用重新定义。而type只能通过&来实现类似于继承的功能
-
- type 能够表示非对象类型, 而 interface 则只能表示对象类型。
-
可以定义基本类型别名,如type StringType = string
-
可以声明联合类型,如 type paramType = number | string;
-
可以声明元组类型,如type arrType = [string, string, number]
定义对象时严谨的来说,type 是引用,而 interface是定义。
组合方式:interface使用extends来实现继承,type使用&来实现联合类型
扩展方式:interface可以重复声明来扩展,type一个类型只能申明一次
范围不同:type适用于基本类型,interface一般不行
命名方式不一样:interface会创建一个新的类型,type只是给类型起一个别名而已
TypeScript 中的模块是什么?
TypeScript 中的模块是相关变量、函数、类和接口的集合。 你可以将模块视为包含执行任务所需的一切的容器。可以导入模块以轻松地在项目之间共享代码。