一、深拷贝浅拷贝
1.定义
(1)浅拷贝:针对基础数据类型拷贝的是值针对引用数据类型拷贝的是内存中的引用地址
(1)深拷贝:在堆内存中重新开辟一个存储空间,完全克隆一个一模一样的对象;
2.如何实现
浅拷贝:(1)直接赋值(2)object.assign(3)解构赋值
深拷贝:(1)写一个递归赋值的方法(2)JSON.parse(JSON.stringify())
二、箭头函数和普通函数的区别
1.声明方式不同
箭头函数使用箭头定义,普通函数使用function关键字定义
2.箭头函数都是匿名函数
3.箭头函数不能用作构造函数,不能被new关键字调用
4.箭头函数的this指向不同
普通函数谁调用他的this就指向谁,箭头函数的this指向父级作用域,且箭头函数的this指向永远不会变,使用call、apply、bind也不会改变
5.普通函数有arguments对象,箭头函数有...rest
6.箭头函数没有原型prototype
三、https和http的区别
1.安全性不同
http是明文传输数据,https加上SSL协议组合形成的一种加密传输协议比http要安全
2.响应速度不同
http更快,只需要三次握手,3个包
https需要三次握手和SSL握手,一共需要12个包
所以http响应速度比https快
3.端口
http用的是80端口,https用的是443端口
4.消耗资源
https是构建在SSL之上的http协议,所以会消耗更多服务器资源
5.展示方式
http在一些主流浏览器中会被标记为不安全,如果网站配备了增强级SSL证书,会被浏览器地址栏变为“绿色地址栏。
6. 费用不同
https需为网站购买和配置ssl证书,会产生一定的费用。
四、grid网格布局
1.display:grid
2.grid-template-columns:1fr 1fr 1fr
平均分
grid-template-columns:repeat(3,100px)
grid-template-columns:minmax 1fr 1fr
3.grid-row-gap 属性、grid-column-gap 属性以及 grid-gap 属性设置单元格之中的间隙
4.grid-auto-flow 属性可以设置row,column
5.justify-items 属性、align-items 属性以及 place-items 属性
五、get和post的区别
1.url的区别
get,参数url可见;
post,url参数不可见
2.数据传输上
get,通过拼接url进行传递参数;
post,通过body体传输参数
3.传输数据的大小
get一般传输数据大小不超过2k-4k(根据浏览器不同,限制不一样,但相差不大)
post请求传输数据的大小根据php.ini 配置文件设定,也可以无限大。
4.post请求能发送更多的数据类型(get请求只能发送ASCII字符)
5.请求过程也不同
get一个TCP包
post两个TCP包
get会把header和data一块发到服务器,服务器返回200
post先发header,服务器发100 continue之后,再发data,服务器响应200
6.安全性不同,post更安全
六、promise用法
1.Promise 是异步编程的一种解决方案,其实是一个构造函数,自己身上有resolve、reject、race、all、allSettled、any这几个方法,原型上有then、catch、finally等方法。
2.Promise
对象有以下两个特点。
(1)对象的状态不受外界影响,有三种状态,pending(进行中)、resolved(已完成)、rejected(已失败)。只有异步操作的结果,可以决定当前是哪一种状态,任何其他操作都无法改变这个状态。这也是Promise
这个名字的由来,它的英语意思就是“承诺”,表示其他手段无法改变。
(2)一旦状态改变,就不会再变,任何时候都可以得到这个结果
3.promise原型链上有什么方法
原型上有then、catch,finally等方法。
(1).then()
方法可以处理 Promise
被接受或拒绝的情况。执行resolve的回调,then方法可以接受两个参数,第一个对应resolve的回调,第二个对应reject的回调。
(2).catch就是用来捕获异常的,也就是和then方法中接受的第二参数rejected的回调是一样的
(3).finally在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。
4.race和all方法
(1)all方法,该方法提供了并行执行异步操作的能力,并且在所有异步操作执行完后并且执行结果都是成功的时候才执行回调。接收方法的数组,返回promise对象放进一个数组给then
(2)那么race方法就是相反的,谁先执行完成就先执行回调。先执行完的不管是进行了race的成功回调还是失败回调,其余的将不会再进入race的任何回调
七、http状态码
1xx | 信息,表示临时响应并需要请求者继续执行操作 |
---|---|
2xx | 成功,操作被成功接收并处理 |
3xx | 表示要完成请求,需要进一步操作。 通常,这些状态代码用来重定向 |
4xx | 客户端错误,请求包含语法错误或无法完成请求 |
5xx | 这些状态代码表示服务器在尝试处理请求时发生内部错误。 这些错误可能是服务器本身的错误,而不是请求出错 |
---|
1.状态码200:状态码200表示服务器响应成功
2.状态码302:代表临时跳转,临时重定向
3.状态码301 :状态码301和状态码302相似,不同的是状态码301往往代表的是永久性的重定向
4.状态码403:状态码403代表请求的服务器资源权限不够
5.状态码404:状态码404代表服务器上没有该资源
6.状态码500:状态码500代表程序错误
八、原型和原型链
1.原型链:在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对象共有的特点。即:对象具有属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,__proto__属性的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(父对象)里找,一直找,直到__proto__属性的终点null,再往上找就相当于在null上取值,会报错。通过__proto__属性将对象连接起来的这条链路即我们所谓的原型链。
2.原型:函数这个特殊的对象,除了和其他对象一样有上述__proto__属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)(prototype属性是函数所独有的),prototype属性的作用就是让该函数所实例化的对象们都可以找到公用的属性和方法
3.constructor:原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数(__proto__和constructor属性是对象所独有的)。constructor属性的含义就是指向该对象的构造函数。
九、vue组件间通信
1.父子
(1)父传子:a.直接传用props接收
(2)子传父:a.使用$refs直接访问子组件实例b.子组件中使用$emit触发上级函数c.$parents和$childern
2.兄弟
(1)通过父组件pros和$emit的形式
(2)vuex
(3)eventbus
3.多级传递
(1)eventbus
(2)provide和inject
(3)vuex
(4)$attrs和$liseners
十、Cookie,Session,localStorage的区别
1.存储大小不同,cookie一般4k,sessionstorage和localStorage一般5M
2.有效期:sessionStorage:仅在当前浏览器窗口关闭之前有效;localStorage:始终有效,窗口或浏览器关闭也一直保存,因此用作持久数据;cookie:只在设置的cookie过期时间之前有效,即使窗口关闭或浏览器关闭
3.作用域不同:作用域不同,sessionStorage不在不同的浏览器窗口中共享,即使是同一个页面;localstorage在所有同源窗口中都是共享的;cookie也是在所有同源窗口中都是共享的
4.支持的数据类型:cookie中只能保管ASCII字符串,并需要通过编码方式存储为Unicode字符或者二进制数据。session中能够存储任何类型的数据,包括且不限于string,integer,list,map等。
十一、你常用的ES6新语法
1.箭头函数
2.解构赋值
3.模板字符串
4.展开运算符
5.解构赋值
十二、async和await的用法
1.async 作为一个关键字放到函数的前面,用于表示函数是一个异步函数,该函数的执行不会阻塞后面代码的执行
2.await是等待,只能放到async函数里面,在后面放一个返回promise对象的表达式
3.async声明的函数的返回本质上是一个Promise,async函数内部会返回一个Promise对象,then方法回调函数的参数
4.await的本质是可以提供等同于”同步效果“的等待异步返回能力的语法糖,用await声明的Promise异步返回,必须“等待”到有返回值的时候,代码才继续执行下去
5.async 函数内部的实现原理是resolved,如果函数内部抛出错误, 则会导致返回的 Promise 对象状态变为 reject 状态,promise 对象有一个catch 方法进行捕获,被 catch 方法回调函数接收到
十三、js中如何判断数据类型
1.typeof
(1)基本数据类型中:Number,String,Boolean,undefined 以及引用数据类型中Function ,可以使用typeof检测数据类型,分别返回对应的数据类型小写字符。
(2)基本数据类型中:null 。引用数据类型中的:Array,Object,Date,RegExp。不可以用typeof检测。都会返回小写的object
2.constructor
constructor是prototype对象上的属性,指向构造函数。根据实例对象寻找属性的顺序,若实例对象上没有实例属性或方法时,就去原型链上寻找,因此,实例对象也是能使用constructor属性的。
因为constructor属性在构造函数的原型里,并且指向构造函数,那我们就可以利用constructor属性来判断一个实例对象是由哪个构造函数构造出来的,也可以说判断它属于哪个类。
但有一点我们是要注意的,当我们将Person.prototype设置为等于一个以对象字面量形式创建的新对象时,constructor属性不再指向Person。 因为上述做法把Person默认的prototype覆盖掉,指向Person的constructor就不复存在。
function Person () {}
var person1 = new Person()
Person.prototype = {
name: 'Jim',
age: '21'
}
var person2 = new Person()
console.log(person1)
console.log(person2)
console.log(person1.constructor)
console.log(person2.constructor)
打印结果如下
访问person2时,Person.prototype里已经没有了constructor属性,所以会继续沿着原型链往上找到Person.prototype.prototype中的constructor属性,它是指向Object的,因此person2.constructor指向Object。
var num = 123;
var str = 'abcdef';
var bool = true;
var arr = [1, 2, 3, 4];
var json = {name:'wenzi', age:25};
var func = function(){ console.log('this is function'); }
var und = undefined;
var nul = null;
var date = new Date();
var reg = /^[a-zA-Z]{5,20}$/;
var error= new Error();
function Person(){
}
var tom = new Person();
// undefined和null没有constructor属性
console.log(
tom.constructor==Person,
num.constructor==Number,
str.constructor==String,
bool.constructor==Boolean,
arr.constructor==Array,
json.constructor==Object,
func.constructor==Function,
date.constructor==Date,
reg.constructor==RegExp,
error.constructor==Error
);
//所有结果均为true
3.使用Object.prototype.toString.call()检测对象类型
4.instanceof
基本数据类型只有通过对应类型构造函数创建出来成对象形式,才会是对应类型构造函数实例(true),直接写基本数据类型值则不是(false),毕竟上面有说到instanceof是用来判断左侧是不是右侧的实例对象,你连对象类型都不是怎么可能为true呢;引用类型可以直接作为左侧实例对象继承自右侧构造函数,返回值为true,如上面数组。
function Person () {}
Person.prototype = {
name: 'Jim',
age: '21'
}
var person = new Person()
console.log(person instanceof Person) //true
console.log(person.constructor === Person) //false
可见Person.prototype对象被重写并不影响instanceof的判断,因为instanceof是根据原型链来判断构造函数的,只要对象实例的原型链不发生变化,instanceof便可以正确判断
十四、关于nextTick()的理解
首先记住:nextTick所指定的回调会在浏览器更新DOM完毕之后再执行。
在我自己做的一个单页面应用中,我有一个需求,当从后端请求回数据后,马上就对页面进行更新。比如,我要点击操作里的删除操作,前端删除数据后就向后端发请求,后端删除数据后返回数据,如果我们想马上显示到页面上,应该怎么做呢?
可能好多人会像我第一次做那样,比如我这个页面是用 v-for 遍历data这个数据显示出来的,可能好多人就会直接把前端返回的数据直接重新赋值给data。但是这样是绝对不行的!这样只会导致数据其实是变了,但是视图是不会变的,因为vue更新dom是异步的,无法通过同步代码赋值后马上去更新页面。所以即使删除成功了页面也不会显示出来。即使显示删除成功,页面也不会更新。
十五、vue2和vue3的区别
1.vue2和vue3双向数据绑定原理发生了改变
vue2 的双向数据绑定是利用ES5 的一个 API Object.definePropert()
对数据进行劫持 结合 发布订阅模式的方式来实现的。
vue3 中使用了 es6 的 Proxy
API 对数据代理。
2.Fragments 碎片化节点 (Fragments)就是说在组件可以拥有多个根节点
3.Vue2与Vue3 最大的
区别 — Vue2使用选项类型API(Options API)对比Vue3合成型API(Composition API)
4.data
- ref一般用于定义普通数据类型和dom节点,使用 .value去取值 ( toRefs 结构数据,变成响应式数据)
- reactive一般用于定义复杂数据类型,使用的时候,直接取值即可
5.生命周期钩子 — Lifecyle Hooks
6.setup 函数中的 props 是响应式的,当传入新的 prop 时,它将被更新
7.setup()内使用响应式数据时,需要通过.value获取
8.父子间传值
子组件
props
//子组件
<template>
<div>
<button @click="sendFun">send</button>
</div>
</template>
<script setup>
import { defineEmits } from "vue";
const emits = defineEmits(['sendMsg'])
const sendFun = () => {
emits('sendMsg', '我是子组件数据')
}
</script>
emit
//子组件
<template>
<div>
{{ parentMsg }}
</div>
</template>
<script setup>
import { toRef, defineProps } from "vue";
const props = defineProps(["msg"]);
console.log(props.msg) //父组件信息
let parentMsg = toRef(props, 'msg')
</script>
十六、js中class类和继承
1.使用extend继承
2. 用static声明静态方法,不用实例化或者继承可以调用
3.类里面可以用getter 和 setter访问和设置属性
4.用下划线 _
前缀来表示一个属性或方法是私有的,不应该在类的外部被访问或重写
5.继承的时候子类中有constructor需要用super调用保证了父类中constructor的正常初始化
6.继承的类可以扩展父类的功能和属性,实例化就是将类实例了一份
十七、vue2路由守卫
1,全局路由守卫
(1)全局前置路由守卫
import VueRouter from 'vue-router'
const router = new VueRouter({
routes: [
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "Login" */ '../components/Login')
}
]
})
// 全局前置路由守卫,表示在每次切换路由之前调用,针对所有的路由
router.beforeEach((to, from, next)=>{ // to表示去哪个路由,from表示来自哪个路由,next表示放行
// 可加判断条件进行放行
if(to.path !== '/login'){ // 判断要去的路由条件
if(localStorage.getItem('school') !== 'atguigu'){
// 缓存中这个参数如果不是'atguigu'则进入登录重新登陆
// 登录成功把这个值存储在缓存中
next('/login')
} else{
next()
}
}
else{
next()
}
})
export default router
(2)全局后置路由守卫
import VueRouter from 'vue-router'
const router = new VueRouter({
routes: [
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "Login" */ '../components/Login'),
meta: {title: '登录'}
}
]
})
// 全局后置路由守卫,表示在每次切换路由之后调用,针对所有的路由
router.afterEach((to, from)=>{ // to表示去哪个路由,from表示来自哪个路由,注意这里没有next
document.title = to.meta.title || '测试网站' // 切换网页标题
})
export default router
2.独享路由守卫
import VueRouter from 'vue-router'
const router = new VueRouter({
routes: [
{
path: '/login',
name: 'Login',
component: () => import(/* webpackChunkName: "Login" */ '../components/Login'),
meta: {fangxing: true},
// 独享路由守卫,独享路由守卫只有前置的,没有后置的
beforeEnter: (to, from, next) => {
if(to.meta.fangxing){
next()
}
}
}
]
})
export default router
3.组件内路由守卫
// 通过路由规则,进入该组件时被调用 beforeRouteEnter(to, from, next){},
// 通过路由规则,离开该组件时被调用 beforeRouteLeave(to, from, next){}
4.路由的工作模式
1.hash 模式(默认,兼容性好)
hash模式在浏览器地址栏中会出现 “#”,在做网络刷新请求时,“#”后面的不会当作网络地址去请求服务器。
2.history 模式(兼容性略差)
histroy模式在浏览器地址栏中不会出现 “#”,但是在做刷新网络请求时就会出错,如果要想解决这一问题,就要后端配合
5.路由的跳转方式
1.使用<router-link>标签进行跳转
<router-link to="/path">Link Text</router-link>
(2)编程式路由跳转
使用$router.push()方法进行跳转
this.$router.push('/path');
使用$router.replace()方法进行跳转,此方法和$router.push()方法相似,但是不会保留浏览器的历史记录。
this.$router.replace('/path');
使用$router.go()方法进行历史记录跳转
// 后退一步
this.$router.go(-1);
// 前进一步
this.$router.go(1);
(3).命名式路由跳转(name)
<router-link :to="{name:'shop',query:{city:cityObj}}">购物车</router-link>
...
//路由配置
{
path:'/shop',
//该path路径不能少。因为命名式路由跳转是通过name找到该path
name:'shop',
component:Shop
}
6.路由传参和接收参数
1.params类似post,跳转页面,url后面不会拼接参数,但是刷新页面参数会消失 query类似get,跳转页面,url后面会拼接参数,类似于?id=1,非重要性的可以这样传,重要性参数不建立用query传参。
2.取参this.$route.params.id
取参:this.$route.query.id
3.params传参需要在路由配置文件中(route/index.js)加占位符
写法:在path后对要传的参数前加冒号
十八、缓存路由组件keep-alive
路由组件在不展示时会进行销毁处理
用<keep-alive>标签包裹后,即使不展示,也不会被销毁