for in 和 for of 的区别
通过以下例子助你理解
//1. 循环对象
let obj = {
name: 'hello',
age: 25
}
for (let i in obj){
console.log(i)
// name age
}
for(let i of obj){
console.log(i)
// Uncaught TypeError: obj is not iterable 报错了,因为对象没有部署Symbol.iterator 属性。
}
//2. 循环数组
let arr = ['a','b','c'];
for(let i in arr){
console.log(i) // 0,1,2
}
for(let i of arr){
console.log(i) // a,b,c
}
复制代码
for in 的特点
- for in 比较适合遍历对象。
- 遍历对象返回的都是key值,数组也是,在数组中叫(下标)
for of 的特点
- for of 循环的对象必须部署symbol.iterator属性,否则就会报错。普通对象是没有symbol.iterator属性
- 拥有symbol.iterator属性的对象如下
- 数组Array
- Map
- Set
- String
- argument对象等等
- 拥有symbol.iterator属性的对象如下
- for of获取的值时键值对的值
vue-router里两个模式的区别,用了哪些原生的API
hash 模式
- hash模式的原理是onhashchange事件,可以在window监听hash的变化
window.onhashchange = function(event){
consoel.log(event)// 返回一个
}
复制代码
- hash模式实现的路由,链接后面添加
#+路由
history 模式
- history模式用到的原生API有
window.history.popState('传参','标题','跳转的路由地址')
、windown.history.pushState()
、以及window.history.replaceState('传参','标题','跳转的路由地址')
window.history.pushState
只是改变了后面的路由,页面并没有跳转,也没有重新加载。repalceState
也是一样。window.onpopState
只有在点击浏览器的前进或者后退按钮才会出触发,或者调用history.back()
、forward()
等方法
- history模式实现是链接后面直接加路由,网址更好看。
- history的使用需要后端配合使用,如果后端没有设置,生产环境下会404。
共有的特点 更新视图但是不重新加载页面
- hash虽然出现在url地址中,但它不被包含在HTTP请求里,他是用来指示浏览器的,对服务器端没有任何作用,改变hash不会重新加载页面,咱们可以通过设置onhashchange实现
更新视图但是不重新加载页面
- history中
pushState
和replaceState
这两个方法虽然说修改了浏览器的历史记录栈,虽然当前的url路由改变了,但是不会重新加载页面。这就为了更新视图但不重新加载页面
提供了基础。
使用vue-lazyload 插件实现图片懒加载
- 使用npm下载lazyload插件
npm i vue-lazyload
- 在main.js中引用文件
import vueLazy form 'vue-lazyload' Vue.use(vueLazy,{ preLoad: 1, //提前加载的高度,数字1代表一屏的高度 error: imgUrl, //图片加载失败时显示的图片 loading: imgUrl, //图片加载成功显示的图片 attempt: 2 //图片加载错误后,最大的尝试次数 }) 复制代码
vuex
- 为什么使用vuex,可以简单理解为,组件中的data属性需要共享时,可以使用vuex进行统一的状态管理。
vuex的使用
vuex中默认的五种基本对象
state
- 存储变量,相当于组件中的data
export default new Store({
state:{
count:2
}
})
复制代码
mutations
- 修改state中的变量,并且是同步的,在组件中调用`this.$store.commit('方法名',传参)
- 因为vuex中不建议通过this.$store.state直接修改变量。
export default new Store({
state:{
count:2
},
mutations:{
changeCount(state,n){
state.count += n
}
}
})
mounted(){
this.$store.commit('changeCount',5)
}
//在html中用{{$store.state.count}}
复制代码
actions
- 异步修改state变量,这个的原理通过actions中的方法去调用mutations中的方法去改变state。
- actions内部会接收一个context对象,这个对象里有
{dispatch, commit, getters, state, rootGetters...}
等等方法,actions方法一般是用来调用mutations的,我们可以解构赋值{commit},直接使用。
export default new Store({
state:{
count:2
},
mutations:{
changeCount(state,n){
state.count += n
}
},
actions:{
yiCount(context,n){
}
}
// 项目中一般都是这样写的
actions:{
yiCount({commit},n){
commit('changeCount',5)
}
}
})
mounted(){
this.$store.dispatch('yiCount',5)
}
复制代码
getters
- 它可以根据state中的变量进行其他的计算操作,返回的是一个新的变量,我们可以通过
this.$store.getters.filTodos
调用。但是它不会改变state中的变量。export default new Store({ state:{ count:2, todos:todos: [ { id: 1, text: "你好", done: true }, { id: 2, text: "世界", done: false }, ], }, getters:{ filTodos(state){ state.todos.filter((item)=>{ return item.done }) } } }) //组件中调用 mounted(){ let a = this.$store.getters.filTodos //{ id: 1, text: "你好", done: true }, } 复制代码
flex布局
设置flex布局
- 块级元素
display:flex
- 行内块元素:
display:inline-flex
父级元素设置flex后也叫做flex容器,设置容器属性
设置主轴的方向flex-diretion
- 水平方向
flex-direction:row
:主轴水平方向,从左到右flex-diretion:row-reverse
:主轴方向,从右到左
- 垂直方向
-
flex-diretion:column
:垂直方向,从上到下 -
flex-diretion:column-reverse
:主轴方向,从下往上
-
设置项目是否换行
flex-wrap:nowrap
//默认,如果不换行,当项目宽度超过以后,它的宽度会失效,变成所有项目在一行内平分宽度。flex-wrap:wrap
//换行,第一行在上方flex-wrap:wrap-reverse
//换行第一行在下方
设置项目在主轴的对齐方式,以主轴为水平方向为例
justify-content:flex-start
//默认左对齐justify-content:center
//居中对齐justify-content:flex-end
//右对齐justify-content:space-between
// 左右两个项目贴边对齐,中间的项目间隔相等。justify-content:space-around
//左右两个项目是中间项目之间间隔的一半。
设置交叉轴(垂直)的对齐方式,以垂直方向为例
align-item:flex-start
//从上往下默认align-item:center
//居中align-item:flex-end
//从下往上align-item:baseline
//基线对齐,其实就是项目中所有文字的最底端对齐
设置子元素(项目)的属性
设置排列顺序
- order属性必须是单个添加的才有用,假设
ul>li{order:1}
,所有li项目都是1,它的排列顺序是不会有变化的。假设需要第二个li排在最前面,我们可以设置li:nth-child(2){order:-10}
,order的值越小排序越靠前。order:2
设置项目的放大比例
flex-grow
这个设置项目的比例flex-grow:1
设置项目的缩小比例
- 当空间不足的时候,缩小的比例
flex-shrink:0
// 默认是0
flex-basis默认为auto,项目本身的大小,项目中就用auto就行
flex属性
- flex属性是flex-grow、flex-shrink、flex-basis的缩写。
- 一般都是flex:1 0 auto。
注意
- 使用flex布局的时候,最后对宽度进行一个设置反正就尼玛的设置宽度
垂直居中
<div>
<p></p>
</div>
<style>
div{
display:flex;
justify-content:center;
align-item:center;
}
</style>
复制代码
深拷贝和浅拷贝
浅拷贝
- 浅拷贝就是共用一个地址,只要其中一个的属性值发生改变,这两个都会改变。最外层的堆内存地址是不一样的,但是里面的的地址是一样的,如下obj.b的地址是一样的,所以修改obj.b中的值,所以两个对象都是联动的。
实现一个浅拷贝
let obj = {name:'你好',b:{age:25}}
function shallowClone(obj){
if(obj===null) return null
if(obj instance Date) return new Date(obj)
if(obj instance RegExp) return RegExp(obj)
let newObj = {}
for(var i in obj){
newObj[i] = obj[i]
}
return newObj
}
let a = shallowColne(obj)
a.b.age = 55
console.log(obj) //{name:'你好',b:{age:55}}
复制代码
深拷贝
- 深拷贝开辟两个完全不一样的堆内存,对对象中的所有子对象进行递归拷贝,拷贝前后两个对象互不影响。
实现深拷贝
let obj = {name:'你好',b:{age:25}}
function deep(obj){
let newObj = {}
if(obj === null) return null
if(obj === Date) return new Date(obj)
if(obj === RegExp) return new RegExp(obj)
if(typeof(obj) != 'object') return obj
for (var i in obj){
newObj[i] = deep(obj[i])
}
return newObj
}
复制代码
css画斜线
- 旋转法
div{
border: 1px solid red;
transform: rotate(45deg)
}
复制代码
- 画两个三角形,然后另一个三角形用定位去盖住三角形
div{
width: 0
height: 0
border: 100px solid
border-color: transparent yellow transparent transparent
}
复制代码
两列布局
用calc加浮动
- html 部分
<div class= 'main'> <div class= 'left'></div> <div class= 'right'></div> </div> 复制代码
- css部分
.main{ overflow:hidden width:100% height:100% } .left{ height:100% width:250px float:left background:red } .right{ height:100% width:calc(100% - 250px) float:left background:yellow } 复制代码
右边margin-left,左边浮动
.main{
overflow:hidden
width:100%
height:100%
}
.left{
height:100%
width:250px
float:left
background:red
}
.right{
width:100%
height:100%
margin-left:250px
background:yellow
}
复制代码
左边绝对定位+右边浮动
.main{
overflow:hidden
width:100%
height:100%
}
.left{
height:100%
width:250px
position:absolute
background:red
}
.right{
width:100%
height:100%
float:right
background:yellow
}
复制代码
利用flex布局
.main{
display:flex
width:100%
height:100%
}
.left{
height:100%
width:250px
background:red
}
.right{
height:100%
flex:1
background:yellow
}
复制代码
中间自适应,两边固定
圣杯布局
.main{
position;relative;
padding: 0 250px
}
.left{
height:100%
width:250px
background:red
position:absolute
top:0
left:0
}
.right{
width:250px
height:100%
background:yellow
position:absolute
top:0
right:0
}
复制代码
calc+浮动
.main{
overflow:hidden
width:100%
height:100%
}
.left{
height:100%
width:250px
float:left
background:red
}
.right{
height:100%
width: 250px
float:left
background:yellow
}
.center{
height:100%
float:left
width:calc(100% - 500px)
background:blue
}
复制代码
数组去重的几种方法
循环+indexOf
let arr = [11, 2, 3, 4, 2, 1, 5, 2, 56, 5];
let ary = [];
arr.forEach((item) => {
if (ary.indexOf(item) === -1) {
ary.push(item);
}
});
console.log(ary);//[11, 2, 3, 4, 1, 5, 56]
复制代码
利用对象属性名不重名的特性
let arr = [11, 2, 3, 4, 2, 1, 5, 2, 56, 5];
let ary = {};
let a = [];
arr.forEach((item) => {
ary[item] = 1;
});
Object.keys(ary).forEach((item) => {
a.push(Number(item));
});
console.log(a);//[11, 2, 3, 4, 1, 5, 56]
复制代码
利用set和Array.from
- Set对象存储的对象值都是唯一的
- Array.from将一个类数组,或者属性名是数字且有lenth属性的对象,浅拷贝生成一个新的数组
let arr = [11, 2, 3, 4, 2, 1, 5, 2, 56, 5];
let a = new Set(arr)
let b = Array.from(a)
console.log(b)//[11, 2, 3, 4, 1, 5, 56]
复制代码
常用的ES6
let const
let const var的区别
- let const 声明不会产生变量提升
- let const 不能重复声明
- let const 存在块级作用域
- let var 声明时可以不赋值
模板字符串
名字:${name}
箭头函数
箭头函数和普通函数的区别
- 箭头函数没有argument
- 箭头函数没有this,如果在箭头函数内部写this,它是继承上下文的this
- 箭头函数不能new执行
- 箭头函数没有原型
函数形参默认值
Object.assign
- 合并对象,浅拷贝
let obj = {name:45,age:56}
let a = Object.assign(obj)
a.name = 85
console.log(obj) // {name:85,age:56}
复制代码
Set对象
- 将数组转为对象,而且对象的值是唯一的。通过用来数组去重
解构赋值
解析url,获取传参
let str = "www.baodu.com?name=12&age=13";
let obj = {};
function getData(a) {
let ary = a.split("?");
let b = ary[1].split("&");
console.log(b);
b.forEach((item) => {
let c = item.split("=");
obj[c[0]] = c[1];
});
console.log(obj);
}
getData(str);
复制代码
柯里化
- 柯里化就是闭包的高级版
- add(1)(2)==>3
function add(...arg) {
let a = [...arg];
return function(b) {
a.push(b);
return a.reduce((total, item) => {
return total + item;
});
};
}
console.log(add(1)(2));//3
复制代码
new 一个函数执行时执行步骤
- 先创建一个空对象
- 将this指向这个空对象
- 函数执行,给这个新对象添加属性和方法
- 返回这个新创建的对象(所以构造函数不需要return,如果有return,return的是一个对象,就返回这个对象,如果是个非对象,就返回刚创建的对象)
function fn(obj){ this.name = obj console.log(obj) } new fn() 复制代码
call bind apply
bind
bind的作用
- 是改变当前函数的this,返回一个新的函数,并将this进行改变,不立即执行。
手写bind
- 因为bind必须是所有函数都可以调用,故myBind得加在函数的公共方法
Function.prototype.myBind = function(){
//这里面的this肯定是需要更改的函数,因为fn.myBind(),this == fn
let f = this
return
}
复制代码
连续bind的问题
let obj = { name: 15 };
let obj2 = { age: 5 };
function a() {
console.log(this);
}
let b = a.bind(obj).bind(obj2);
b()// 返回的时第一次bind的this
复制代码
- 因为将a.bind(obj)=a3
- b() == a3.bind(obj2) //这样a3的this指向obj2
- a3() == 将a的this指向obj
call
call的作用
- call的作用是改变this指向,并立即执行函数。
手写call
- 必须是所有函数都可以调用
let obj = {name: 15, age: 16} Function.prototype.myCall(){ let [context,...args] = arguments if(!context){ context = window } context.fuc = this let res = context.fuc(...args) delete context.fuc return res } function fn(...args){ return args.reduce((total,item)=>{ return total+item }) } fn.myCall(obj,1,2,3) 复制代码
apply
apply的作用
- 改变this的指向,并立即执行函数,参数为数组的形式
手写apply
Function.prototype.myApply = function (){
let [contxt,...args] = arguments
context.fuc = this || window
let res = context.fuc(...args)
delete context.fuc
return res
}
复制代码
vue中$nextTick的原理和应用
vue.$nextTick原理,原因
- vue是异步执行dom更新的,一旦观察到数据变化,Vue就会开启一个队列,其实也就是事件循环(Event loop),可以将事件循环理解为一个圆圈,同一时间段内更新的Dom被观察到数据变化后,它会把这些改变Dom操作放到这个队列中(圆圈中),然后执行,实现DOM更新。
- 下面例子直观的表达了vue是异步更新DOM的
<div @click='fn' ref='str'>{{str}}</div> data(){ return { str:35 } } methods:{ fn(){ this.str = '你好' console.log(this.$refs[str].innerHTML)// 35 } } 复制代码
- 下面例子直观的表达了vue是异步更新DOM的
- 为了确定在DOM更新完成之后再去做某些事情,就可以使用Vue.$nextTick(callback),这样回调函数会在DOM更新完成之后执行。
vue.$nextTick(callback)应用
- 最常用的应用是在created钩子函数中操作DOM,由于created钩子函数中,DOM还没有更新,所以需要用$nectTick操作DOM,否则就会报错。
created(){ this.$nextTick(()=>{ console.log(this.$refs[st].innerHTML = '小丑竟是你自己') }) } 复制代码
- 点击事件需要这个DOM做一些操作时
<div @click='fn' ref='str'>{{str}}</div> data(){ return { str:35 } } methods:{ fn(){ this.str = '你好' this.$nextTick(()=>{ console.log(this.$refs[str].innerHTML)// 你好 }) } } 复制代码
proxy 和 defineProperty 的区别
proxy
proxy的优势
- 直接监听对象而非属性
- 直接监听数组的变化
- Proxy的拦截方式更多
- Proxy返回的是一个新的对象,修改值的时候我们可以直接操作这个对象,而Object.defineProperty只能通过遍历对象的属性就行修改。
- 直接实现对象的增加、删除
Object.defineProperty的优势
- 兼容性强
vue3.0.和2.0的区别
- vue3.0重构响应式系统,用Proxy替换了Object.defineProperty,使用的优势如上
- 新增了组合式API(Composition),更好的逻辑复用和组织代码。当然同样支持Options API(选项式API)
- vue3.0的声明周期也发生了改变
- 取消了beforCreat和created声明周期,用setup替换。
- 所有的声明周期都写在setup中。
- 自动按需引入
- 重构了虚拟DOM的实现(跳过静态节点,只处理动态节点),性能得到了很大的提高。
MVVM的原理
- 它的原理就是通过数据劫持(Observer)加发布订阅模式,主要有observer监听器,watcher订阅者,Compile解析器。
- 首先Observer数据劫持,利用Object.defineProperty给每一个数据添加get和set属性,Compile解析器,给属性添加订阅者和绑定更新函数,由于订阅者很多,所以就将他们放到Dep中在属性变化后通知watcher订阅者,将这些订阅者放入Dep中统一管理,当数据发生变化时,通知订阅者执行更新函数触发视图更新。
节流、防抖
节流
- 规定的时间断内函数只触发一次,通过用于页面滚动、发验证码。
let flg = true function throttle(fn,delay=500){ return (...args)=>{ if(!flg) return flg = false setTimeout(()=>{ flg = truw },delay) fn.apply(this,args) } } 复制代码
防抖
- 每次时间触发后需要等待一段时间的执行,若这段时间内再次触发,就会重新计时,触发的时候只触发最后一次。
let timer = null
function debounce(fn,delay=500){
return (...args)=>{
if(timer){
clearTimeout(timer)
}
setTimeout(()=>{
fn.aplly(this,args)
},delay)
}
}
复制代码
Vue中自定义指令
- 自定义指令有全局注册和局部注册两种
全局自定义指令
- html部分
<div v-fous = 'fn'></div> 复制代码
- js部分
<script> Vue.diretive('fous'{ inserted:function(el,fuc){ console.log(el,fuc.value) //el dom元素; fuc.value返回的是fn函数体 } }) methods:{ fn(){ console.log(11111) } } </script> 复制代码
局部自定义指令
export default = {
directiveds:{
fous:{
inserted:function(el,fuc){
console.log(el,fuc.value)
}
}
}
}
复制代码
vue中data为什么一定是一个函数而不是一个对象
- vue中的组件是可以被多次复用的,如果是一个对象,每一次复用都是复用的一个data,这样就会相互影响,如果是一个函数,每一次复用组件都会生成一个新的data实例,互不影响。
FormData和普通对象有什么区别
- FormData一般用来处理表单数据,提交给后台。
- FormData数据的增删改查和普通对象不一样
- FormData增加属性
formDate.append('属性名','属性值')
- FormData获取属性值
formdata.get('属性名')
- FormData修改属性
formData.set('属性名','属性值')
- FormData判断是否有该属性
formData.has('属性名')
- FormData删除属性
formData.delete('属性名')
- FormData增加属性
vue多个页面传参
- vuex 和 内存
异步函数都有哪些
- 事件
- 发布订阅
- axjax
- Promise
- async await
- 定时器
H5和C3的新增属性
H5新增属性
- 语义化标签 header、nav、aside、footer
- 音频video、音频audio
- 画布canvas
- 内存localStorage和sesstionStorage
- 表单的控件,email、url、number、file...
C3新增特性
-
transform转换
-
transition过度
-
border-radius圆角
-
box-shadow 阴影
-
伪类选择器
-
伪元素选择器
-
calc函数
-
animations