面试题前端

字符串转数组

1、split方法
const text = "abc";
const chars = text.split('');
console.log(chars);
//['a', 'b', 'c']```
2、展开运算符
const text = "abc????";
const chars = [ ...text ];
console.log(chars);
//["a", "b", "c", "????"]
3、解构赋值
const text = "abc????";
const [ ...chars ] = text;
console.log(chars);
//["a", "b", "c", "????"]
4、Array.from
const text = "abc????";
const chars = Array.from(text);
console.log(chars);
//["a", "b", "c", "????"]

数组转字符串

1、toString()方法
var a = [1,2,3,4,5,6,7,8,9,0];  //定义数组
var s = a.toString();  //把数组转换为字符串
console.log(s);  //返回字符串“1,2,3,4,5,6,7,8,9,0”
console.log(typeof s);  //返回字符串string,说明是字符串类型
2、join()方法
var a = [1,2,3,4,5];  //定义数组
var s = a.join("==");  //指定分隔符
console.log(s);  //返回字符串“1==2==3==4==5”
3、toLocalString() 
var a = [1,2,3,4,5];  //定义数组
var s = a.toLocalString();  //把数组转换为本地字符串
console.log(s);  //返回字符串“1,2,3,4,5,6,7,8,9,0”

let,var,const区别

var定义的变量可以修改,如果不初始化会输出undefined
// var 的情况
console.log(foo); // 输出undefined
var foo = 2;
没有块的概念,可以跨块访问, 不能跨函数访问
let定义的变量,只能在块作用域里访问,不能跨块访问,也不能跨函数访问。
// let 的情况
console.log(bar); // 报错ReferenceError
let bar = 2;
const用来定义常量,使用时必须初始化(即必须赋值),只能在块作用域里访问,而且不能修改。
 const person = {
     name : 'jiuke',
     sex : '男'
 }
 person.name = 'test'
对象是引用类型的,person中保存的仅是对象的指针,这就意味着,const仅保证指针不发生改变,修改对象的属性不会改变对象的指针,所以是被允许的。也就是说const定义的引用类型只要指针不发生改变,其他的不论如何改变都是允许的。

数组操作

1、push() 添加
let arr = [1,2,3,4,5]
console.log(arr.push(5))   // 6
console.log(arr) // [1,2,3,4,5,5]
2、pop()
从后面删除元素,只能是一个,返回值是删除的元素
let arr = [1,2,3,4,5]
console.log(arr.pop())     // 5
console.log(arr)  //[1,2,3,4]
3、shift()
前面删除元素,只能删除一个 返回值是删除的元素
let arr = [1,2,3,4,5]
console.log(arr.shift())  // 1
console.log(arr)   // [2,3,4,5]
4 unshift()
从前面添加元素, 返回值是添加完后的数组的长度
let arr = [1,2,3,4,5]
console.log(arr.unshift(2))    // 6
console.log(arr)  //[2,1,2,3,4,5]
5、splice(i,n)
删除从i(索引值)开始之后的那个元素。返回值是删除的元素
let arr = [1,2,3,4,5]
console.log(arr.splice(2,2))     //[3,4]
console.log(arr)    // [1,2,5]

数据基本类型和引用类型

基本数据类型有:Number,String,Boolean,null,Undefined,Symbol,BigInt
引用数据类型:Object,Array,Function,Date,RegExp
基本数据类型的数据直接存储在栈中;而引用数据类型的数据存储在堆中,在栈中保存数据的引用地址,这个引用地址指向的是对应的数据,以便快速查找到堆内存中的对象。

获取对象的键值和键名

1、使用Object.values快速获取对象键值

let obj = {
    a: 1,
    b: 2
};
let values = Object.values(obj) // [1, 2]
2、使用Object.keys快速获取对象键名

let obj = {
    a: 1,
    b: 2
};
let keys = Object.keys(obj) // ['a', 'b']

字符串出现的第一次的位置

indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。

父组子件传值

父组件:<child :inputName="name">
子组件:
(1)props: {
   inputName: String,
   required: true
  }
(2)props: ["inputName"]
2.子组件向父组件传值$emit
子组件:

 <span>{undefined{childValue}}</span>

 <!-- 定义一个子组件传值的方法 -->

  <input type="button" value="点击触发" @click="childClick">


 export default {
  data () {
   return {
    childValue: '我是子组件的数据'
   }
  },
  methods: {
   childClick () {  
    this.$emit('childByValue', this.childValue)
   }
  }
 }
父组件
<!-- 引入子组件 定义一个on的方法监听子组件的状态-->
<child v-on:childByValue="childByValue"></child>
methods: {
   childByValue: function (childValue) {
    // childValue就是子组件传过来的值
    this.name = childValue
   }
  }
}
不同组件之间传值,通过eventBus

父组件调用子组件方法
父组件: 在子组件中加上ref即可通过        this.$refs.mychild.parentHandleclick("嘿嘿嘿");调用
<template>
  <div>
    <button @click="clickParent">点击</button>
    <child ref="mychild"></child>
  </div>
</template>
 
<script>
  import Child from './child';
  export default {
    name: "parent",
    components: {
      child: Child
    },
    methods: {
      clickParent() {
        this.$refs.mychild.parentHandleclick("嘿嘿嘿");
      }
    }
  }
</script>

子组件调用父组件的方法
 this.$parent.fatherMethod();
方法二:当两个组件之间没有关联关系的时候,可以用下边的方法
1) 在main。js中声明一个事件总线,$bus是自己随便起的名字,这样的做法,可以在所有的实例中都有$bus
new Vue({
  beforeCreate(){
    Vue.prototype.$bus = this;

  },
  render: h => h(App),
}).$mount('#app')
(2)A页面 
test(){
      this.$bus.$emit('test1',this)
    },
(3)B页面
  mounted(){
        this.$bus.$on('test1',(data)=>{
            console.log('test1111',data)
        })
    },
    beforeDestroy() {
        console.log('test被销毁')
       this.$bus.off('test1')
    }

v-show和v-if的区别

相同点:v-show和v-if都能控制元素的显示和隐藏。
不同点:
实现本质方法不同
v-show本质就是通过设置css中的display设置为none,控制隐藏
v-if是动态的向DOM树内添加或者删除DOM元素

箭头函数和普通函数的区别?箭头函数可以当做构造函数 new 吗?

箭头函数是普通函数的简写,但是它不具备很多普通函数的特性
第一点,this指向问题,箭头函数的this指向它定义时所在的对象,而不是调用它的对象
不会进行函数提升
没有arguments对象,不能使用arguments,如果要获取参数的话可以使用rest运算符
没有yield属性,不能作为生成器Generator使用
不能new
没有自己的this,不能调用call和apply
没有prototype,new关键字内部需要把新对象的_proto_指向函数的prototype
  async function async1() {
   console.log('async1 start')
   await async2()
   console.log('async1 end')
  }
  async function async2() {
   console.log('async2')
  }
  async1()
  console.log('script start')

//执行到await时,如果返回的不是一个promise对象,await会阻塞下面代码(当前async代码块的代码),会先执行async外的同步代码(在这之前先看看await中函数的同步代码,先把同步代码执行完),等待同步代码执行完之后,再回到async内部继续执行
//执行到await时,如果返回的是一个promise对象,await会阻塞下面代码(当前async代码块的代码),会先执行async外的同步代码(在这之前先看看await中函数的同步代码,先把同步代码执行完),等待同步代码执行完之后,再回到async内部等promise状态达到fulfill的时候再继续执行下面的代码
//所以结果为
//async1 start
//async2
//script start
//async1 end

宏任务和微任务都有哪些

宏任务:script、setTimeOut、setInterval、setImmediate
setInterval方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭
setImmediate()是将事件插入到事件队列尾部,主线程和事件队列的函数执行完成之后立即执行setImmediate指定的回调函数
微任务:promise.then,process.nextTick、Object.observe、MutationObserver
注意:Promise是同步任务
执行顺序
执行宏任务script,
进入script后,所有的同步任务主线程执行
所有宏任务放入宏任务执行队列
所有微任务放入微任务执行队列
先清空微任务队列,
再取一个宏任务,执行,再清空微任务队列
依次循环

js事件总线

1同步任务
 只有前一个任务执行完毕,才能执行下一个任务
2异步任务    
 无需等待,分开执行

vue r o u t e r 和 router和 routerroute的区别

route相当于当前正在跳转的路由对象。。可以从里面获取name,path,params,query等
router为VueRouter的实例,相当于一个全局的路由器对象,里面含有很多属性和子对象,例如history对象。。。经常用的跳转链接就可以用this.$router.push,和router-link跳转一样
$router.go(-1)返回上一层页面不刷新页面问题
router.push( ... ) =>跳转到某个子页面,并在history中添加一条记录
router.repalce( ... ) =>替换当前的页面,其实也可以理解为跳转,和push的区别就是不会在history中添加记录
router.go(number) =>刚才提到的history,在go()中被使用,跳转到上一页就go(-1),跳转到下一页就go(1),当然实现跳转的前提都是history中有记录。 this.$router.go(0);会刷新页面

vue 路由钩子

全局钩子
前置守卫:router.beforeEach;
后置守卫:router.afterEach;
全局解析守卫:router.beforeResolve;
路由独享守卫
beforeEnter
组件内钩子
beforeRouteEnter:执行时间 ==> 渲染该组件的对应路由被 confirm 之前;
beforeRouteUpdate:执行时间 ==> 
当前路由已经改变,但是依然渲染该组件时;
beforeRouteLeave:执行时间 ==> 导航离开该组件的对应路由时

谈谈对盒子模型的理解

包含了元素内容(content)、内边距(padding)、
边框(border)、外边距(margin)几个要素

在这里插入图片描述

h5新特性

用于绘画的 canvas 元素
用于媒介回放的 video 和 audio 元素
对本地离线存储的更好的支持
新的特殊内容元素,比如 article、footer、header、nav、section
新的表单控件,比如 calendar、date、time、email、url、search

垂直居中的方法

{
display: flex;
align-items: center;
justify-content: center;
}

.box1{
    display: table-cell;
    vertical-align: middle;
    text-align: center;        
}
绝对定位和0
.box4 span{
  width: 50%; 
  height: 50%; 
  background: #000;
  overflow: auto; 
  margin: auto; 
  position: absolute; 
  top: 0; left: 0; bottom: 0; right: 0; 
}
display:flex和margin:auto
.box8{
    display: flex;
    text-align: center;
}
.box8 span{margin: auto;}


字符串中出现次数最多的字母和出现的次数

  var str = "asdasddsfdsfadsfdghdadsdfdgdasd";
    var str1 = str.split("");
    console.log(str1);
    var newStr = {};
       // 数组去重 和计算出现的次数
    str1.forEach(function(item) {
      if (newStr[item]) {
      console.log(newStr[item])
        newStr[item]++;
      } else {
        newStr[item] = 1;
      }
    });
          console.log(newStr)

    var max = 0;
    var strkey = null;
    for (var key in newStr) {
      if (newStr[key] > max) {
        max = newStr[key];
        strkey = key;
      }
    }
    console.log("最多的字符是" + strkey);
    console.log("出现的次数是" + max);

改变this指向问题

call常用做继承
apply经常和数组有关系,比如想使用Math里面的函数
bind不调用函数,但还想改变this指向,比如在定时器里面改变this指向
        var o = {
            name: "andy"
        }
        function fn(a, b) {
            console.log(this); //指向 对象o
            console.log(a + b);
        };
        fn.call(o, 1, 2);
       
        var o = {
      name: "andy"
    };

    function fn(a, b) {
      console.log(this); //指向 对象o
      console.log(a + b);
    }
    fn.apply(o, [1, 2]); 
         var btns = document.querySelectorAll("button");
        for (var i = 0; i < btns.length; i++) {
            btns[i].onclick = function() {
                this.disabled = true;
                setTimeout(function() {
                        this.disabled = false;
                    }.bind(this), 2000) //bind 里面的this指向的是btn
            }
        }

路由重新定向


{ path: '/home', redirect: { name: 'homepage' } }

路由懒加载

vue异步组件
  component: resolve => require(['@/components/home'],resolve)
组件懒加载方案二 路由懒加载(使用import)
const Home =  () => import(/* webpackChunkName: 'ImportFuncDemo' */ '@/components/home')
webpack提供的require.ensure()
 component: r => require.ensure([], () => r(require('@/components/home')), 'demo')


vuex批量获取state的值

  import { mapState } from 'vuex';
computed: {
   ...mapState({
    add: state => state.add,
    counts: state => state.counts
  })
 ...mapState([
    'add',
    'counts'
  ])
  }
    import { mapActions } from 'vuex';
 // mapActions 使用方法一 将 this.commonActionGet() 映射为 this.$store.dispatch('commonActionGet')
      ...mapActions(['commonActionGet', 'commonActionGetJSON', 'commonActionPost', 'commonActionPostJSON'])
      /*
       // 第二种方式
       ...mapActions({
         'commonActionGet': 'commonActionGet',
         'commonActionGetJSON': 'commonActionGetJSON',
         'commonActionPost': 'commonActionPost',
         'commonActionPostJSON': 'commonActionPostJSON'
       })
      */
  import { mapMutations } from 'vuex';
 // mapMutations 使用方法1
      ...mapMutations(['ADD']), // 会将 this.ADD 映射成 this.$store.commit('ADD') 
      */
      // mapMutations 使用方法2
      ...mapMutations({
        'ADD': 'ADD'
      })

为什么 v-for 会要有key?

因为在 vue 中会有一个 diff 算法,
假如子节点 AB 调换了位置,
它会比较 key 值,会直接调换,而不是一个销毁重新生成的过程

vue 常见的性能优化

spa 使用 keep-alive

key 的使用

v-if 和v-show

v-if 不要和 v-for 一起使用

v-for 的优先级要早于 v-if,如果一起使用的话,会先遍历在判断 v-if,
会造成性能问题;
使用Object.freeze()方式冻结data中的属性,从而阻止数据劫持

组件销毁的时候会断开所有与实例联系,但是除了addEventListener
,所以当一个组件销毁的时候需要手动去removeEventListener

图片懒加载

路由懒加载

防抖节流

长列表固定个数

为减少重新渲染和创建dom节点的时间,采用虚拟dom

用递归写一个函数,这个函数每5秒执行一次,然后100次后停止

   fn(i) {
      var tezt = setTimeout(() => {
        i++;
        this.fn(i);
        console.log(i, "i__");
      }, 5000);
      if (i >= 100) {
        console.log("进入了");
        clearTimeout(tezt);
      }
    },
        this.fn(0);

拦截器

在这里插入代码片
// 添加请求拦截器
axios.interceptors.request.use(function (config) {
    // 在发送请求之前做些什么
    return config;
  }, function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  });
// 添加响应拦截器
axios.interceptors.response.use(function (response) {
    // 对响应数据做点什么
    return response;
  }, function (error) {
    // 对响应错误做点什么
    return Promise.reject(error);
  });
稍后移除拦截器,可以这样:
const myInterceptor = axios.interceptors.request.use
(function () {/*...*/});
axios.interceptors.request.eject(myInterceptor);
可以为自定义 axios 实例添加拦截器
const instance = axios.create();
instance.interceptors.request.use(function () {/*...*/});

什么是原型?什么是原型链?如何理解

原型分为隐式原型和显式原型,每个对象都有一个隐式原型,
它指向自己的构造函数的显式原型。每个构造方法都有一个显式原型。
__proto__是隐式原型;prototype是显式原型
所有实例的__proto__都指向他们构造函数的prototype
所有的prototype都是对象,自然它的__proto__指向的是Object()的prototype
所有的构造函数的隐式原型指向的都是Function()的显示原型
Object的隐式原型是null

多个__proto__组成的集合成为原型链(概念类似于作用域链)
instanceof 就是判断某对象是否位于某构造方法的原型链上。

ElementUI 修改默认样式的几种办法

(一)内嵌法修改样式
通过:style修改,用于局部组件块:
(二):class引用修改样式
通过:class修改,用于局部组件块:
(三)import导入修改样式
通过import导入样式文件,若在main.js中导入css 
则表示全局引用。既可以用于局部组件块也可以用于全局组件:

vue中父子组件的生命周期

渲染的过程
父beforeCreate->父created->父beforeMount->
子beforeCreate->子created->子beforeMount->子mounted->父mounted
子组件更新过程
父beforeUpdate->子beforeUpdate->子updated->父updated
父组件更新过程
父beforeUpdate->父updated
销毁过程
父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

定位

static	默认值。没有定位,元素出现在正常的流中
relative	生成相对定位的元素,相对于其正常位置进行定位。
absolute	生成绝对定位的元素,相对于 static 定位以外的第一个父元素进行定位。
fixed	生成绝对定位的元素,相对于浏览器窗口进行定位。
inherit	规定应该从父元素继承 position 属性的值。
2、偏移量(offset)
top	定位元素和定位位置的上边距离
bottom	定位元素和定位位置的下边距离
left	定位元素和定位位置的左侧距离
right	定位元素和定位位置的右侧距离

清除浮动的4种方式

产生浮动的原因 父级对象盒子不能被撑开
<div class="clear">额外标签法</div>
.clear{
        clear:both;
    }
父级添加overflow方法
.fahter{
    width: 400px;
    border: 1px solid deeppink;
    overflow: hidden;
}

.clearfix:after{/*伪元素是行内元素 正常浏览器清除浮动方法*/
        content: "";
        display: block;
        height: 0;
        clear:both;
        visibility: hidden;
    }
    .clearfix{
        *zoom: 1;/*ie6清除浮动的方式 *号只有IE6-IE7执行,其他浏览器不执行*/
    }
 
<body>
    <div class="father clearfix">
        <div class="big">big</div>
        <div class="small">small</div>
        <!--<div class="clear">额外标签法</div>-->
    </div>
    <div class="footer"></div>
</body>
使用before和after双伪元素清除浮动

跨域问题

1】设置document.domain解决无法读取非同源网页的 Cookie问题
因为浏览器是通过document.domain属性来检查两个页面是否同源,因此只要通过设置相同的document.domain,两个页面就可以共享Cookie(此方案仅限主域相同,子域不同的跨域应用场景。)
// 两个页面都设置
document.domain = 'test.com';
2】JSONP
3】跨文档通信 API:window.postMessage()
4】CORS
nginx代理跨域 

slot 插槽

1、slot (父组件 在子组件<slot> </slot>处插入内容)
//子组件 : (假设名为:ebutton)
<template>
  <div class= 'button'>
      <button></button>
      <slot></slot>    
     //slot 可以放在任意位置。(这个位置就是父组件添加内容的显示位置)
  </div> 
</template>
父组件中的<ebutton></ebutton> 中添加内容,是不会在页面上渲染的
<template>
  <div class= 'app'>
     <ebutton> 
     <span slot>
        测试
      </span>
    </ebutton>
  </div>
</template>

2、编译作用域 (父组件 在子组件<slot> </slot>处插入 data)
子组件
<template>
  <div class= 'button'>
      <button></button>
      <slot></slot>      
       //slot 可以放在任意位置。(这个位置就是父组件添加内容的显示位置)
  </div> 
</template>
父组件
<template>
  <div class= 'app'>
     <ebutton> {{ parent }}</ebutton>
  </div>
</template>

new Vue({
  el:'.app',
  data:{
    parent:'父组件'
  }
})
直接传入子组件内的数据是不可以的。
因为:父级模板里的所有内容都是在父级作用域中编译的;
子模板里的所有内容都是在子作用域中编译的。
3、后备内容 (子组件<slot> </slot>设置默认值)
所谓的后背内容,其实就是slot的默认值,
有时我没有在父组件内添加内容,那么 slot就会显示默认值,如:

//子组件 : (假设名为:ebutton)
<template>
  <div class= 'button'>
      <button>  </button>
      <slot> 这就是默认值 </slot>
  </div>
</template>
4、具名插槽 (子组件 多个<slot ></slot> <slot></slot> 
对应插入内容)
当然 vue 为了方便,书写 v-slot:one 的形式时,可以简写为 #one

//子组件 : (假设名为:ebutton)
<template>
  <div class= 'button'>
      <button>  </button>
      <slot name= 'one'> 这就是默认值1</slot>
      <slot name='two'> 这就是默认值2 </slot>
      <slot name='three'> 这就是默认值3 </slot>
  </div>
</template>
父组件通过v-slot : name 的方式添加内容:
//父组件:(引用子组件 ebutton)
<template>
  <div class= 'app'>
     <ebutton> 
     <template v-slot:one> 这是插入到one插槽的内容 </template>
     <template v-slot:two> 这是插入到two插槽的内容 </template>
  <template v-slot:three> 这是插入到three插槽的内容 </template>
     </ebutton>
  </div>
</template>
5、作用域插槽 ( 父组件 在子组件 <slot> </slot> 处使用子组件 data)
<template>
  <div class= 'button'>
      <button>  </button>
      <slot name= 'one' :value1='child1'> 这就是默认值1</slot>    //绑定child1的数据
      <slot :value2='child2'> 这就是默认值2 </slot>  //绑定child2的数据,这里我没有命名slot
  </div>           
</template>

new Vue({
  el:'.button',
  data:{
    child1:'数据1',
    child2:'数据2'
  }
})

//父组件:(引用子组件 ebutton)
<template>
  <div class= 'app'>
     <ebutton> 

        // 通过v-slot的语法 将插槽 one 的值赋值给slotonevalue 
        <template v-slot:one = 'slotonevalue'>  
           {{ slotonevalue.value1 }}
        </template>

        // 同上,由于子组件没有给slot命名,默认值就为default
        <template v-slot:default = 'slottwovalue'> 
           {{ slottwovalue.value2 }}
        </template>

     </ebutton>
  </div>
</template>


首先在子组件的slot上动态绑定一个值( :key='value')
然后在父组件通过v-slot : name = ‘values ’的方式将这个值赋值给 values
最后通过{{ values.key }}的方式获取数据

Vue 中的修饰符

表单修饰符 .lazy 累贼
.trim
过滤首尾的空格,中间的是不会过滤的。
.stop
一键阻止事件冒泡,
.prevent 
用于阻止事件的默认行为,
.number
限制输入数字或者输入的东西转换成
.self
事件是从事件绑定的元素本身触发时才触发回调
.once
只能用一次,绑定了事件以后只能触发一次,第二次就不会触发。
capture
从上面我们知道了事件的冒泡,其实完整的事件机制是:捕获阶段--目标阶段--冒泡阶段,默认的是事件触发是从目标开始往上冒泡,当我们加了这个 .capture 以后我们就反过来了,事件触发从包含这个元素的顶层开始往下触发。
passive
监听元素滚动事件的时候
native
注意:使用.native修饰符来操作普通HTML标签是会令事件失效的
Sync  森克
v-bind.sync 用在一个字面量的对象上

什么是闭包?闭包的作用?闭包的应用

闭包的本质就是在一个函数内部创建另一个函数
闭包有3个特性:
①函数嵌套函数
②函数内部可以引用函数外部的参数和变量
③参数和变量不会被垃圾回收机制回收
好处

①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突

②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)

③匿名自执行函数可以减少内存消耗

坏处

①其中一点上面已经有体现了,就是被引用的私有变量不能被销毁
,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完
变量后手动为它赋值为null;

②其次由于闭包涉及跨域访问,所以会导致性能损失,
我们可以通过把跨作用域变量存储在局部变量中
,然后直接访问局部变量,来减轻对执行速度的影响

什么是DOM事件流?什么是事件委托

利用冒泡原理(子向父一层层穿透),把事件绑定到父元素中,以实现事件委托
DOM事件流
分为三个阶段
捕获阶段
目标阶段
冒泡阶段
在addeventListener()的第三个参数(useCapture)设为true,
就会在捕获阶段运行,默认是false冒泡

Vue双向绑定

vue.js是采用数据劫持结合发布者-订阅者模式的方式,
通过Object.defineProperty()来劫持
各个属性的setter,getter,在数据变动时发布消息给订阅者,

css3的新特性

1、圆角效果;2、图形化边界;
3、块阴影与文字阴影;4、使用RGBA实现透明效果;
5、渐变效果;6、使用“@Font-Face”实现定制字体;
7、多背景图;8、文字或图像的变形处理;
9、多栏布局;10、媒体查询等。

MVVM的理解

低耦合:视图(View)可以独立于Model变化和修改,
一个ViewModel可以绑定到不同的"View"上,
当View变化的时候Model可以不变,当Model变化的时候View也可以不变

可重用性:你可以把一些视图逻辑放在一个ViewModel里面,
让很多view重用这段视图逻辑

独立开发:开发人员可以专注于业务逻辑和数据的开发(ViewModel),
设计人员可以专注于页面设计,
使用Expression Blend可以很容易设计界面并生成xml代码
可测试:界面素来是比较难于测试的,而现在测试可以针对ViewModel来写

HTML、CSS、JavaScript之间的关系

html是页面的结构层,css是表现层,javascript则是页面的行为层。

jquery和vue的区别是什么

Vue做到了数据和视图完全分离开,
它首先把值和js对象进行绑定,然后修改js对象的值,
Vue框架就会自动把dom的值就行更新。
对数据进行操作不再需要引用相应的dom对象,
他们通过Vue对象实现数据和视图的相互绑定。

jQuery则是要先使用选择器($)来选取dom对象,
然后对dom对象进行操作(如赋值、取值、事件绑定等)。
vue侧重数据绑定,可以应用于复杂数据操作的后台页面。
如:表单填写页面
jquery侧重样式操作,动画效果等;
可以应用于一些html5的动画页面,一些需要js来操作页面样式的页面中。

Vue-loader的作用

Vue Loader 是一个 webpack 的 loader,
它允许你以一种名为单文件组件 (SFCs)的格式撰写 Vue 组件
解析和转换 .vue 文件,提取出其中的逻辑代码 script、
样式代码 style、以及 HTML 模版 template,
再分别把它们交给对应的 Loader 去处理。

js–回流和重绘

回流:
回流是布局或者几何属性需要改变就称为回流。
回流是影响浏览器性能的关键因素,
因为其变化涉及到部分页面(或是整个页面)的布局更新。
一个元素的回流可能会导致了其所有子元素以及
DOM中紧随其后的节点、祖先节点元素的随后的回流。

重绘:
重绘是由于节点的几何属性发生改变或者由于样式发生改变但不会影响布局
。例如outline, visibility, color、background-color等,
重绘的代价是高昂的,因为浏览器必须验证DOM树上其他节点元素的可见性。
什么时候会发生回流呢?
1、添加或删除可见的DOM元素
2、元素的位置发生变化
3、元素的尺寸发生变化(包括外边距、内边框、边框大小、高度和宽度等)
4、内容发生变化,比如文本变化或图片被另一个不同尺寸的图片所替代。
5、页面一开始渲染的时候(这肯定避免不了)
6、浏览器的窗口尺寸变化(因为回流是根据视口的大小来计算元素的位置和大小的)

而重绘是指在布局和几何大小都不变得情况下,比如次改一下background-color,或者改动一下字体颜色的color等。

注意:回流一定会触发重绘,而重绘不一定会回流

如何减少回流和重绘
1、CSS优化法
(1)使用 transform 替代 top
(2)使用 visibility 替换 display: none 
,因为前者只会引起重绘,后者会引发回流(改变了布局
(3)避免使用table布局,可能很小的一个小改动会造成整个 table 的重新布局。
(4)尽可能在DOM树的最末端改变class,回流是不可避免的,
但可以减少其影响。尽可能在DOM树的最末端改变class
,可以限制了回流的范围,使其影响尽可能少的节点。
(5)避免设置多层内联样式,CSS 选择符从右往左匹配查找,避免节点层级过多。
(6)将动画效果应用到position属性为absolute或fixed的元素上,
避免影响其他元素的布局,这样只是一个重绘,而不是回流,
同时,控制动画速度可以选择 requestAnimationFrame,详见探讨 requestAnimationFrame。
(7)避免使用CSS表达式,可能会引发回流。
(8)将频繁重绘或者回流的节点设置为图层,
图层能够阻止该节点的渲染行为影响别的节点,例如will-change、video、iframe等标签,浏览器会自动将该节点变为图层。
(9)CSS3 硬件加速(GPU加速),使用css3硬件加速,
可以让transform、opacity、filters这些动画不会引起回流重绘 。
但是对于动画的其它属性,比如background-color这些,还是会引起回流重绘的,不过它还是可以提升这些动画的性能。

2、JavaScript优化法
(1)避免频繁操作样式,最好一次性重写style属性,或者将样式列表定义为class并一次性更改class属性。
(2)避免频繁操作DOM,创建一个documentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中。
(3)避免频繁读取会引发回流/重绘的属性,如果确实需要多次使用,就用一个变量缓存起来

什么是防抖?什么是节流?

防抖
n秒后在执行该事件,若在n秒内被重复触发,则重新计时
情景:文本框输入搜索(连续输入谜面多次请求接口)
节流
n秒内只运行一次,若在n秒内重复触发,只有一次生效
情景:鼠标不断点击触发,规定n秒内多次点击只有一次生效

px、rem、em的区别与联系

1. px是固定的像素,一旦设置了就无法因为适应页面大小而改变。
2. em和rem相对于px更具有灵活性,他们是相对长度单位,
意思是长度不是定死了的,更适用于响应式布局。
3.总之em相对于父元素,rem相对于根元素。

http 状态码

200 OK:表示从客户端发送给服务器的请求被正常处理并返回;
204 No Content:表示客户端发送给客户端的请求得到了成功处理,但在返回的响应报文中不含实体的主体部分(没有资源可以返回);

206 Patial Content:表示客户端进行了范围请求,并且服务器成功执行了这部分的GET请求,响应报文中包含由Content-Range指定范围的实体内容。

3xx (5种)

301 Moved Permanently:永久性重定向,表示请求的资源被分配了新的URL,之后应使用更改的URL;

302 Found:临时性重定向,表示请求的资源被分配了新的URL,希望本次访问使用新的URL;

       301与302的区别:前者是永久移动,后者是临时移动(之后可能还会更改URL)

303 See Other:表示请求的资源被分配了新的URL,应使用GET方法定向获取请求的资源;

      302与303的区别:后者明确表示客户端应当采用GET方式获取资源

304 Not Modified:表示客户端发送附带条件(是指采用GET方法的请求报文中包含if-Match、If-Modified-Since、If-None-Match、If-Range、If-Unmodified-Since中任一首部)的请求时,服务器端允许访问资源,但是请求为满足条件的情况下返回改状态码;

307 Temporary Redirect:临时重定向,与303有着相同的含义,307会遵照浏览器标准不会从POST变成GET;(不同浏览器可能会出现不同的情况);

4xx (4种)

400 Bad Request:表示请求报文中存在语法错误;

401 Unauthorized:未经许可,需要通过HTTP认证;

403 Forbidden:服务器拒绝该次访问(访问权限出现问题)

404 Not Found:表示服务器上无法找到请求的资源,除此之外,也可以在服务器拒绝请求但不想给拒绝原因时使用;

5xx (2种)

500 Inter Server Error:表示服务器在执行请求时发生了错误,也有可能是web应用存在的bug或某些临时的错误时;

503 Server Unavailable:表示服务器暂时处于超负载或正在进行停机维护,无法处理请求;

http和https之间的区别

http无状态无连接,而且是明文传输,不安全,默认连接80端口
https 是有不可否认性的,可以保证对方身份的真实性,
默认端口是443端口,加密传输,而且会保证数据的完整性

封装Vue组件的步骤

 Vue.component注册组件
 在其他组件使用 标签名



混入 (mixin)

创建
export const myMinxin = {
    data() {
        return {
            num: 1
        }
    },
    create() {
        this.hellow();
    },
    methods:{
        hellow() {
            console.log('hello');
        }
    }
}
引用
import {myMinxin} from "./assets/js/mixin.js"
 mixins: [myMinxin],


HTML文件第一行是什么

<!DOCTYPE> 声明不是 HTML 标签;它是指示
 web 浏览器关于页面使用哪个 HTML 版本进行编写的指令。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值