只能输入3的倍数
什么是深拷贝?浅拷贝 ?
1.浅拷贝:浅拷贝是拷贝引用,拷贝后的引用都是指向同一个对象的实例,彼此之间的操作会互相影响。
//这里的赋值仅仅只是把obj1的内存地址指向了obj。var obj={name:'zhangsan',age:24}var obj1=obj;
console.log(obj1.name);//zhangsan
//改变obj1中name的值,obj中name的值也跟着发生改变
obj1.name='lisi';
console.log(obj.name)//lisi
consloe.log(obj1.mane)//lisi
像上面这种直接赋值的方式就是浅拷贝,此时会发现,obj1的值发生改变,原来的obj也会跟着发生改变。但是很多情况下我们想要的不是这种情况,仅仅只是把原对象的值拷贝过来当改变obj1时,obj并不需要跟着改变。此时,就需要用到了深拷贝。
2.深拷贝:在堆中重新分配内存,并且把源对象所有属性都进行新建拷贝,以保证深拷贝的对象的引用图不包含任何原有对象或对象图上的任何对象,拷贝后的对象与原来的对象是完全隔离,互不影响。
//深拷贝就是不紧复制对象的基本类,同时也复制原对象中的对象.//就是说完全是新对象产生的,新对象所指向的不是原来对像的地址。
function deepCopy(a, b) {
var b = b || {};
for (var i in a) {
if (typeof a[i] === 'object') {
b[i] = (a[i].constructor === Array) ? [] : {};
deepCopy(a[i], b[i]);
} else {
b[i] = a[i];
}
}
return b;
}
var arr =['zhangsan','lisi','wangwu'];var newArr=deepCopy(arr,newArr);
console.log(arr[1]);//lisi
console.log(newArr[1]);//lisi
newArr[1]='zhaoliu';
console.log(arr[1]);//lisi
console.log(newArr[1]);//zhaoliu
数组去重?
方法一:
双层循环,外层循环元素,内层循环时比较值
如果有相同的值则跳过,不相同则push进数组
Array.prototype.distinct = function(){
var arr = this,
result = [],
i,
j,
len = arr.length;
for(i = 0; i < len; i++){
for(j = i + 1; j < len; j++){
if(arr[i] === arr[j]){
j = ++i;
}
}
result.push(arr[i]);
}
return result;
}
var arra = [1,2,3,4,4,1,1,2,1,1,1];
arra.distinct(); //返回[3,4,2,1]
方法二:利用splice直接在原数组进行操作
双层循环,外层循环元素,内层循环时比较值
值相同时,则删去这个值
注意点:删除元素之后,需要将数组的长度也减1.
Array.prototype.distinct = function (){
var arr = this,
i,
j,
len = arr.length;
for(i = 0; i < len; i++){
for(j = i + 1; j < len; j++){
if(arr[i] == arr[j]){
arr.splice(j,1);
len--;
j--;
}
}
}
return arr;
};
var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,56
优点:简单易懂
缺点:占用内存高,速度慢
方法三:利用对象的属性不能相同的特点进行去重
Array.prototype.distinct = function (){
var arr = this,
i,
obj = {},
result = [],
len = arr.length;
for(i = 0; i< arr.length; i++){
if(!obj[arr[i]]){ //如果能查找到,证明数组元素重复了
obj[arr[i]] = 1;
result.push(arr[i]);
}
}
return result;
};
var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,56
方法四:数组递归去重
运用递归的思想
先排序,然后从最后开始比较,遇到相同,则删除
Array.prototype.distinct = function (){
var arr = this,
len = arr.length;
arr.sort(function(a,b){ //对数组进行排序才能方便比较
return a - b;
})
function loop(index){
if(index >= 1){
if(arr[index] === arr[index-1]){
arr.splice(index,1);
}
loop(index - 1); //递归loop函数进行去重
}
}
loop(len-1);
return arr;
};
var a = [1,2,3,4,5,6,5,3,2,4,56,4,1,2,1,1,1,1,1,1,56,45,56];
var b = a.distinct();
console.log(b.toString()); //1,2,3,4,5,6,45,56
方法五:利用indexOf以及forEach
Array.prototype.distinct = function (){
var arr = this,
result = [],
len = arr.length;
arr.forEach(function(v, i ,arr){ //这里利用map,filter方法也可以实现
var bool = arr.indexOf(v,i+1); //从传入参数的下一个索引值开始寻找是否存在重复
if(bool === -1){
result.push(v);
}
})
return result;
};
var a = [1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,3,3,2,3,3,2,2,1,23,1,23,2,3,2,3,2,3];
var b = a.distinct();
console.log(b.toString()); //1,23,2,3
方法六:利用ES6的set
Set数据结构,它类似于数组,其成员的值都是唯一的。
利用Array.from将Set结构转换成数组
function dedupe(array){
return Array.from(new Set(array));
}
dedupe([1,1,2,3]) //[1,2,3]
拓展运算符(...)内部使用for...of循环
let arr = [1,2,3,3];
let resultarr = [...new Set(arr)];
console.log(resultarr); //[1,2,3]
下面给大家补充介绍合并数组并去重的方法
一、concat()方法
思路:concat() 方法将传入的数组或非数组值与原数组合并,组成一个新的数组并返回。该方法会产生一个新的数组。
function concatArr(arr1, arr2){
var arr = arr1.concat(arr2);
arr = unique1(arr);//再引用上面的任意一个去重方法
return arr;
}
二、Array.prototype.push.apply()
思路:该方法优点是不会产生一个新的数组。
var a = [1, 2, 3];
var b = [4, 5, 6];
Array.prototype.push.apply(a, b);//a=[1,2,3,4,5,6]
//等效于:a.push.apply(a, b);
//也等效于[].push.apply(a, b);
function concatArray(arr1,arr2){
Array.prototype.push.apply(arr1, arr2);
arr1 = unique1(arr1);
return arr1;
}
排序?
(1)选择排序(从小到大)
1)思想:选择排序,让数组中的每一个数,依次与后面的数进行比较,如果前面的数大于后面的数,就进行位置的交换。这种说法或许有些人看不明白。换个说法,选择排序:第一个数依次与
后面的数比较,第一次比较完之后最小的数在最前面 。
不理解的看看图应该就差不多了,真不明白就和明白的人讨论讨论吧。
2)代码
import java.util.Arrays;
/**
* 练习排序-选择排序
* @author Administrator
*
*/
public class Dome2 {
public static void main(String[] args) {
//数组
int[] arr = {5,3,7,2,6,7,6,5,4,1,9,8};
//第一次循环,是确定一个数依次和后面数的比较的数。
for (int i = 0; i < arr.length -1 ; i++) {
//这个是和第一个数的比较的数
for (int j = i+1; j < arr.length; j++) {
//定义一个临时的变量,用来交换变量
int temp ;
if(arr[i]>arr[j]){
temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
//打印最后的排序结果
System.out.println(Arrays.toString(arr));
}
}
(2)冒泡排序(从小到大)
1)思想:相邻两个数进行比较,第一波比较后,最大的数在最后。(每比较完之后,后面的数就减少一个比较 )
2)代码
import java.util.Arrays;
/**
* 练习排序--冒泡排序
* @author Administrator
*
*/
public class Dome2 {
public static void main(String[] args) {
//数组
int[] arr = {5,3,7,2,6,7,6,5,4,1,9,8};
//外部循环
for(int i=0;i<arr.length-1;i++){
//相连两个数的索引是利用内部循环
for(int index=0;index<arr.length-1;index++){
//同样利用中间变量,注意区分与选择排序的区分
if(arr[index]>arr[index+1]){
int temp=arr[index];
arr[index]=arr[index+1];
arr[index+1]=temp;
}
}
}
System.out.println(Arrays.toString(arr));
}
}
Vue路由拦截?
点击登录的时候向后台发送一个请求,后台会返回一个状态,把这个状态存到本地存储里,利用导航守卫的生命周期()中的参数to(即将进入的路径) from(从哪个路径来,到那个路径去),把想要跳转的路径放在一个数组里,把他的name属性放在from中,如果有的话,跳转到相应的页面,如果没有的话,跳转到登录页面 ;
Vue组件通信?
分三种 父传子 子传父 兄弟传参
父传子 就是props向下传递 事件向上传递 父组件通过props给子组件下发数据
子传父 子组件通过$emit接收父组件传递过来的自定义事件名和数据
兄弟传参 先子传父 再父传子
需要定义一个公共组件 作为仓库来传值 不然路由组件达不到传值效果
Vue生命周期?
beforeCreate:表示组件实例刚刚被创建,组件属性计算之前,如data属性等
created:表示组件实例创建完成,属性已经绑定但是页面上的dom元素还未生成,$el属性还不存在
beforeMount:表示组件模板编译和挂载之前
mounted:表示组件模板编译和挂载之后
beforeUpdate:表示组件更新之前
updated:表示组件更新之后
beforeDestroy:表示组件销毁之前
destroyed:表示组件组件销毁之后
React生命周期?
react生命周期函数
这个问题要考察的是组件的生命周期
一、初始化阶段:
getDefaultProps:获取实例的默认属性
getInitialState:获取每个实例的初始化状态
componentWillMount:组件即将被装载、渲染到页面上
render:组件在这里生成虚拟的DOM节点
componentDidMount:组件真正在被装载之后
二、运行中状态:
componentWillReceiveProps:组件将要接收到属性的时候调用
shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回false,接收数据后不更新,阻止render调用,后面的函数不会被继续执行了)
componentWillUpdate:组件即将更新不能修改属性和状态
render:组件重新描绘
componentDidUpdate:组件已经更新
三、销毁阶段:
componentWillUnmount:组件即将销毁
双向数据绑定原理:Vue:通过Object.defineProperty实现数据劫持:先创建一个Observe监听器劫持所有的属性,如果属性有变化就通知订阅者;然后watcher收到属性的变化,就触发相关的方法函数,从而更新视图
.Object.defineProperty() 这个方法重新定义了对象获取属性值(get)和设置属性值(set)的操作来实现的。
总体来说vue-router里面提供了三大类钩子
全局钩子
某个路由独享的钩子
组件内构子
而且其中三种钩子都涉及到了三个参数
分别为
To:Route即将要进入的目标 路由对象
From:route 当前导航正要离开的路由
Next:function 一定要调用该方法来resolve这个钩子,执行效果依赖next方法的调用参数
一:全局守卫(全局路由钩子)router.beforeEach 注意使用全局路由钩子一定要调用next
()
二:路由内独享的守卫(路由内钩子)beforeEnter守卫 你可以在路由配置上直接定义beforeEnter守卫
组件内的守卫(组件内钩子)
最后你可以在组件中直接定义一下路由导航守卫
beforeRouteEnter
在渲染该组件的对应路由被confirm前调用
不能获取组件实列 this,因为当守卫执行前,组件实列还没有被创建
beforeRouteUpdate 2.2版本新增
在当前路由改变,但是该组件被重复时调用
举例来说,对于一个带有动态参数的路径/foo/:id,在/foo/1和/foo/2之间跳转时由于会渲染同样的foo组件,因此组件实例会被复用,而这个钩子就会在这个情况下调用
可以访问组件实例
beforeRouteleave
导航离开该组件的对应路由时调用 可以访问组件实列
4题 拖拽的基本原理就是根据鼠标的移动来移动被拖拽的元素。鼠标的移动也就是x、y坐标的变化;元素的移动就是style.position的 top和left的改变。当然,并不是任何时候移动鼠标都要造成元素的移动,而应该判断鼠标左键的状态是否为按下状态,是否是在可拖拽的元素上按下的。
vue项目的优化
所谓的基础优化是任何项目都想要做的,基本上的话都是从html css js 是第一步要优化的点分别对应文件内的<template/>,<style>,<script>
1. 语义化标签,避免乱嵌套,合理命名属性
2. vue通过数据驱动视图,主要注意以下几点
· 答:v-show,v-if 用哪个?在我来看要分两个维度去思考问题,第一个维度是权限问题,只要涉及到权限相关的展示无疑要用 v-if,第二个维度在没有权限限制下根据用户点击的频次选择,频繁切换的使用 v-show,不频繁切换的使用 v-if,这里要说的优化点在于减少页面中 dom 总数,我比较倾向于使用 v-if,因为减少了 dom 数量,加快首屏渲染,至于性能方面我感觉肉眼看不出来切换的渲染过程,也不会影响用户的体验。
· 不要在模板里面写过多的表达式与判断 v-if="isShow && isAdmin && (a || b)",这种表达式虽说可以识别,但是不是长久之计,当看着不舒服时,适当的写到 methods 和 computed 里面封装成一个方法,这样的好处是方便我们在多处判断相同的表达式,其他权限相同的元素再判断展示的时候调用同一个方法即可。
· 循环调用子组件时添加 key,key 可以唯一标识一个循环个体,可以使用例如 item.id 作为 key,假如数组数据是这样的 ['a' , 'b', 'c', 'a'],使用 :key="item" 显然没有意义,更好的办法就是在循环的时候 (item, index) in arr,然后 :key="index"来确保 key 的唯一性。
Style
· 将样式文件放在 vue 文件内还是外?讨论起来没有意义,重点是按模块划分,我的习惯是放在 vue 文件内部,方便写代码是在同一个文件里跳转上下对照,无论内外建议加上 <style scoped> 将样式文件锁住,目的很简单,再好用的标准也避免不了多人开发的麻烦,约定命名规则也可能会冲突,锁定区域后尽量采用简短的命名规则,不需要 .header-title__text 之类的 class,直接 .title 搞定。
· 为了和上一条作区分,说下全局的样式文件,全局的样式文件,尽量抽象化,既然不在每一个组件里重复写,就尽量通用,这部分抽象做的越好说明你的样式文件体积越小,复用率越高。建议将复写组件库如 Element 样式的代码也放到全局中去。
· 不使用 float 布局,之前看到很多人封装了 .fl -- float: left 到全局文件里去,然后又要 .clear,现在的浏览器还不至于弱到非要用 float 去兼容,完全可以 flex,grid 兼容性一般,功能其实 flex 布局都可以实现,float 会带来布局上的麻烦,用过的都知道不相信解释坑了
Script
· 多人开发时尽量保持每个组件 export default {} 内的方法顺序一致,方便查找对应的方法。我个人习惯 data、props、钩子、watch、computed、components。
· data 里要说的就是初始化数据的结构尽量详细,命名清晰,简单易懂,避免无用的变量,isEditing 实际可以代表两个状态,true 或 false,不要再去定义 notEditing 来控制展示,完全可以在模板里 {{ isEditing ? 编辑中 : 保存 }}
· props 父子组件传值时尽量 :width="" :heigth="" 不要 :option={},细化的好处是只传需要修改的参数,在子组件 props 里加数据类型,是否必传,以及默认值,便于排查错误,让传值更严谨。
· 钩子理解好生命周期的含义就好,什么时间应该请求,什么时间注销方法,哪些方法需要注销。简单易懂,官网都有写。
· metheds 中每一个方法一定要简单,只做一件事,尽量封装可复用的简短的方法,参数不易过多。如果十分依赖 lodash 开发,methed 看着会简洁许多,代价就是整体的 bundle 体积会大,假如项目仅仅用到小部分方法可以局部引入 loadsh,不想用 lodash 的话可以自己封装一个 util.js 文件
· watch 和 computed 用哪个的问题看官网的例子,计算属性主要是做一层 filter 转换,切忌加一些调用方法进去,watch 的作用就是监听数据变化去改变数据或触发事件如 this.$store.dispatch('update', { ... })
打包优化
解决方法很简单,打包 vender 时不打包 vue、vuex、vue-router、axios 等,换用国内的 bootcdn 直接引入到根目录的 index.html 中。
在 webpack 里有个 externals,可以忽略不需要打包的库
externals: {
'vue': 'Vue',
'vue-router': 'VueRouter',
'vuex': 'Vuex',
'axios': 'axios'
}
vue列表渲染性能优化的原理
答:vue是一个高效的mvvm框架,这得益于作者已经帮我们框架内部做了足够的优化,
网友评论