简单回顾(vue + js)

1、forEach与for循环的区别

forEach没有返回值,无法中断,不支持循环中添加删除操作,只适用于进行集合或数组遍历

2、弹性和布局

1、实现:父元素为弹性盒,内部有三个子元素,设置子元素水平方式对齐,并且第一个元素占20%,第二个元素占30%,第三个元素占剩余空间

水平方式对齐:flex-direction:row
设置占比:第一个元素 flex:2;第二个元素 flex:3;第三个元素 flex:5

2、说一下flex是哪三个属性的集合

flex-grow:设置或检索弹性盒子的扩展比率

让第二个元素的宽度为其他元素的三倍:
div:nth-of-type(1) {flex-grow: 1;}
div:nth-of-type(2) {flex-grow: 3;}
div:nth-of-type(3) {flex-grow: 1;}

flex-basis:设置或检索弹性盒伸缩基准值

设置第二个弹性盒元素的初始长度为 80 像素:
div:nth-of-type(2) {flex-basis: 80px;}

flex-basis:设置弹性盒子的收缩比例
计算:自身宽-溢出值flex-shrink值自身宽/总权重值
总权重=子元素flex-shrink值*自身宽之和

3、数据类型以及深浅拷贝

1、如何判断是深拷贝还是浅拷贝?
2、怎么进行深浅拷贝?
3、数据类型分为哪两种?分别包含哪些?
4、这两种数据类型如何在栈堆中的存储?
参考链接:https://www.cnblogs.com/echolun/p/7889848.html

4、es6中的map与set

1、 set:数组去重,是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key
2、map:一组键值对的结构,具有极快的查找速度。解决的JavaScript只能以字符串为键的问题

5、es6与node中的模块导入导出区别

  • es6
    导入:import 模块名 from " "
    导出:使用export default 和export 向外暴露成员
    【注意1】:使用export暴露的成员,只能 使用{}的方式来 接收,这种形式,叫做按需导出
    同时,如果某些成员,在import的时候不需要,则可以不在{}中定义
    【注意2】:使用export导出的成员,必须严格按照导出时的名称,使用{}接收。
    如果非要给导出的非默认模块起别名,使用 as 起别名
  • node
    导入:使用 var 名称 = require(‘模块标识符’) 来导入
    导出:使用module.export 和 exports来暴露成员

6、vue中路由的跳转以及传参params、query

  • <router-link to = "路径">
  • this.$ router.push():常用来传参
  1. query引入方式:params只能用name来引入路由,而query 要用path引入
       created(){  //生命周期里接收参数
            this.id = this.$route.query.id,  //接受参数关键代码 【注意!!!】接受的时候是 **route**!!!
            console.log(this.id)  
      }
  1. query传递方式:类似于我们ajax中get传参,在浏览器地址栏中显示参数,params则类似于post,在浏览器地址栏中不显示参数
       this.$router.push({  //核心语句    
           path:'/select',   //跳转的路径
           query:{           //路由传参时push和query搭配使用 ,作用时传递参数
           id:this.id , 
           }
        })
  • this.$router.replace{path:‘/’ } 【类似第二条】
  • params是路由的一部分,必须要有。query是拼接在url后面的参数,没有也没关系。
    params一旦设置在路由,params就是路由的一部分,如果这个路由有params传参,但是在跳转的时候没有传这个参数,会导致跳转失败或者页面会没有内容。

7、vuex、localstorage、sessionstorage区别?cookie大小、特点

  • 区别:
  1. vuex存储在内存,localstorage(本地存储)则以文件的方式存储在本地,永久保存,sessionstorage( 会话存储 ) ,临时保存。
  2. localStorage和sessionStorage只能存储字符串类型,对于复杂的对象可以使用ECMAScript提供的JSON对象的stringify和parse来处理
  • 应用场景:vuex用于组件之间的传值,localstorage,sessionstorage则主要用于不同页面之间的传值。

  • 永久性:当刷新页面(这里的刷新页面指的是 --> F5刷新,属于清除内存了)时vuex存储的值会丢失,sessionstorage页面关闭后就清除掉了,localstorage不会。
    【注】:对于不变的数据可以用localstorage可以代替vuex,但是当两个组件共用一个数据源(对象或数组)时,如果其中一个组件改变了该数据源,希望另一个组件响应该变化时,localstorage,sessionstorage无法做到,原因就是区别1。

  • cookie:会随着http发给服务器

  1. 有大小限制,4kb
  2. 数量限制:50条
  3. 会话级存储,随着页面的关闭清空
  4. cookie可以跨越同域名下的多个网页,但不能跨越多个域名使!用
  5. 使用场景:(1)保存用户登录状态;(2)跟踪用户行为;(3)定制页面;(4)创建购物车 …等等

8、vuex的五个核心属性

https://www.cnblogs.com/y896926473/p/6709733.html

  • 什么是vuex?
    Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。
    每一个 Vuex 应用的核心就是 store(仓库)。“store”基本上就是一个容器,它包含着你的应用中大部分的状态 (state)。
  • 核心属性
  1. state => 基本数据
  2. getters => 从基本数据派生的数据 ,getters接收state作为其第一个参数,接受其他 getters 作为第二个参数,如不需要,第二个参数可以省略如下例子:
  3. mutations => 提交更改数据的方法,同步!异步需要使用action ;
    每个 mutation 都有一个字符串的 事件类型 (type) 和 一个 回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数,提交载荷作为第二个参数。(提交荷载在大多数情况下应该是一个对象),提a交荷载也可以省略的。
  4. actions => 像一个装饰器,包裹mutations,使之可以异步。 Action 类似于 mutation,不同在于:
    actioan 提交的是 mutation,而不是直接变更状态。
    action 可以包含任意异步操作
  5. modules => 模块化Vuex

9、vue父子组件的传值

  • 父给子传
  1. 父组件给子组件传值1
    父组件在调用子组件的地方,添加一个自定义的属性,属性的值就是需要传递给子组件的值,如果需要传递的值是一个变量,或者是 boolean,或者是 number 类型,需要使用绑定属性
    在子组件定义的地方,添加一个选项 props,方式一 props 的值为数组,元素为自定义的属性名
    可以在子组件中通过 自定义的属性名就可以拿到父组件传递的数据
  2. 父组件给子组件传值2
    在子组件定义的地方,添加一个选项 props,方式二 props 的值是一个对象 key 为自定义属性名,value 为数据类型
    团队合作 提高代码的严谨性,如果类型不对,会有警告信息出现,但是不会阻止你的代码的渲染
  3. 父组件给子组件传值3
    在子组件定义的地方,添加一个选项 props,方式三 props 的值是一个对象,key 是自定义的属性名,value 为一个对象,这个对象的 key 分别为 type 和 default,表示数据类型和默认值,如果数据类型是对象和数组,默认值必须为函数,其余直接赋值
  • 子组件给父组件传值
    在父组件调用子组件的地方,给它绑定一个自定义的事件,事件的执行是由父组件执行,记住不加()
    在子组件定义的地方,在需要传值的函数内部,执行 this.$emit(‘自定义的事件名’,‘传递的值’)
    组件的传值,需要符合单向的数据流 —父给子传 — 如果组件需要子给父传,则需要慎重考虑
  • 子组件调用父组件的方法:this.$parent.event

10、抖动、节流

  • 场景:resize/scroll 触发统计事件、拖拽时的mousemove事件 等等
  • 函数防抖:函数执行过一次后,在等待某时间段内不能再次执行;在等待时间内触发此函数,则重新计算等待时间。
    通过调用debounce ( [dɪ’baʊns] 敌棒死), 返回一个闭包函数。
    封装:
<script>
    var n = 0;
    function debounce (method, wait, flag) {
        var timer = null;
        var context, args, result, timestamp;
        var later = function () {
            var oDate = new Date();
            var last = oDate.getTime() - timestamp; // 计算第一次时间戳与当前时间戳的差值。
            if (last < wait && last >= 0 ) { // 在等待时间内触发此函数,重新计时。
                timer = setTimeout(later, wait - last);
            } else {
                timer = null;
                if (!flag) { // 限制flag 为true时,执行回调函数。
                    result = method.apply(context, args);
                    if (!timer) {
                        context = args = null
                    }
                }
            }
        }

        return function () {
            var oDate = new Date();
            var callNow = flag && !timer; // 代表第一次调用立即执行。

            timestamp = oDate.getTime(); // 记录下当前时间戳
            context = this;
            args = arguments;
            if (!timer) { // 第一次触发时,timer为空,进入此分支
                timer = setTimeout(later, wait);
            }
            if (callNow) { // 第一次触发且flag为true,进入此分支
                result = method.apply(context, args);
                context = args = null
            }
            return result;
        }
    }
    window.onscroll = debounce (function () {
        console.log(1)
    }, 500, false)
</script>
 flag为true时,连续事件触发时,只会在第一次触发的时候执行回调。
 flag为false时,连续事件触发时,只会在最后一次触发的时候执行回调。
  • 节流:当持续触发事件时,保证一定时间段内只调用一次事件处理函数。节流通俗解释就比如我们水龙头放水,阀门一打开,水哗哗的往下流,秉着勤俭节约的优良传统美德,我们要把水龙头关小点,最好是如我们心意按照一定规律在某个时间间隔内一滴一滴的往下滴。
    实现方法:时间戳和定时器
<script>
    var n = 0;
    function resizeHandler () {
        console.log(n++)
    }
    function throttle (method, context) {
        clearTimeout(method.timer)
        method.timer= setTimeout(function () {
            method.call(context)
        }, 500)
    }
    window.onresize = function () {
        throttle(resizeHandler, window)
    }
</script>

11、在移动端项目中,使用flex布局,在测试的时候遇到过哪些兼容问题?怎么解决的?(测试时,由于手机型号不同,适配不同,会出现的一些兼容问题以及解决方法)

https://blog.csdn.net/hzxOnlineOk/article/details/87858281

12、跨域问题

解决跨域办法:jsonp跨域、跨域资源共享(cors)、nodejs中间件代理跨域、nginx反向代理
vue中:使用node + webpack + webpack-dev-server,在开发环境下,由于vue渲染服务和接口代理服务都是 webpack-dev-server 同一个,所以页面与代理接口之间不在跨域。
jsonp原理:动态创建script标签,再请求一个带参网址实现跨域同行

  1. 原生实现:
 <script>
  var script = document.createElement('script');
  script.type = 'text/javascript';

  // 传参一个回调函数名给后端,方便后端返回时执行这个在前端定义的回调函数
  script.src = 'http://www.daxihong.com:8080/login?user=admin&callback=jsonCallback';
  document.head.appendChild(script);

  // 回调执行函数
  function jsonCallback(res) {
      alert(JSON.stringify(res));
  }
 </script>
 服务器端返回如下(返回即执行全局函数)
 jsonCallback({"status": 0, "user": "admin"})
  1. jquery实现
$.ajax({
  url: 'http://www.domain2.com:8080/login',
  type: 'get',
  dataType: 'jsonp',  // 请求方式为jsonp
  jsonpCallback: "handleCallback",    // 自定义回调函数名
  data: {}
})

13、vue双向绑定原理

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

14、回调函数

可以作为参数,被其他函数调用

  • 异步回调:在发起一个异步任务的同时指定一个函数,在异步任务完成时会自动的调用这个函数。
  • 为什么要异步回调?
    需要获取异步任务的执行结果,但是又不应该让其阻塞(降低效率),即想要高效的获取任务的执行结果。之前在使用线程池或进程池提交任务时,如果想要处理任务的执行结果则必须调用result函数或是shutdown函数,而它们都是是阻塞的,会等到任务执行完毕后才能继续执行,这样一来在这个等待过程中就无法执行其他任务,降低了效率,所以需要一种方案,即保证解析结果的线程不用等待,又能保证数据能够及时被解析,该方案就是异步回调。
  • 常用:ajax、axios请求异步回调

15、闭包

  • 概念:闭包就是能够读取其他函数内部变量的函数。由于函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成“定义在一个函数内部的函数”(然后将这个内部的函数 return 返回出来)。
    所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
  • 特点:
  1. 闭包读取函数内部变量
  2. 让这些变量的值始终保持在内存中。不会在函数调用后被清除
  • 缺点
  1. 由于在写变量在内存中始终存在,所以会造成内存消耗过大,影响性能
  2. 造成内存泄漏。
  • 【注】闭包可以使得函数内部的值可以在函数外部进行修改。所有,如果你把父函数当作对象(object)使用,把闭包当作它的公用方法(Public Method),把内部变量当作它的私有属性(private value),这时一定要小心,不要随便改变父函数内部变量的值。

16、vue.js的两个核心

数据驱动和组件系统

17、前端页面性能优化

  • CSS放在页面最上部(head标签中),JS 文件放在页面最下面
    浏览器会在下载完成全部 CSS 之后 才对整个页面进行渲染, 因此最好的做法是将CSS 放在页面最上面(是将CSS放在head中),让浏览器尽快下载CSS。
    js 文件则相反,浏览器在加载 js 后,立即执行,有可能会阻塞整个页面,造成页面显示缓慢,因此 js 最好放在页面最下面。但是,如果页面解析时就需要用到 js文件,这时放到底部就不合适了。
  • 尽可能少的设置全局变量。
  • 尽量减少DOM 操作
  • 不要再标签中设置样式,最好 外部引用 CSS文件。
  • 减少http 请求,合理设置 HTTP 缓存;(最有效的办法)
    【原因】 http协议是无状态的应用层协议,意味着每次 http 请求都需要建立通信链路、进行数据传输,而在服务器端,每个 http 都需要启动独立的线程去处理。这些通信和服务的开销都很昂贵,减少 http 请求的数目可有效提高访问性能。
  1. 减少http 的主要手段是 合并 CSS 、 合并 js 、 合并图片(多张图片合并成一张)。
  2. 设置HTTP 缓存: 缓存的力量是强大的,恰当的缓存设置可以大大的减少 HTTP请求。
  3. 如果可以的话,尽可能的将外部的脚本、样式进行合并,多个合为一个。另外, CSS、 Javascript、Image 都可以用相应的工具进行压缩,压缩后往往能省下不少空间。
  • 使用浏览器缓存
    对一个网站而言,CSS、js、logo、图标这些静态资源文件更新的频率都比较低,而这些文件几乎是每次 http 请求都需要的,如果将这些文件缓存在浏览器中,可以极好的改善性能。 通过设置 http 头中 的 cache-control 和 expires 的属性,可设定浏览器缓存,缓存时间可以是数天,甚至是几个月。
  • 如果遇到大的文件,可以将文件放置在一个定时器中 ,利用异步操作,等其他的文件加载完成后,再加载 定时器中的文件。
  • CSS Sprites:合并 CSS 图片
  • 图片的懒加载
    这条策略实际上并不一定能减少 HTTP 请求数,但是却能在某些条件下,或者页面刚加载时 减少 HTTP 请求数。对于图片而言,在页面刚加载的时候 ,可以只加载第一屏,当用户继续往后滚屏的时候,才加载后续的图片。
  • 减少 cookie 传输 ,尽量使用 localStorage 存储 本地数据
    一方面,cookie 包含在每次请求和响应中,太大的 cookie 会严重影响数据传输,因此哪些数据需要写入cookie 需要慎重考虑,尽量减少 cookie 中传输的数据量。
  • 将 Image 进行压缩。
  • 18、如何中断forEach循环

使用 try…catch来终止循环

let arr = [1, 2, 3]
try {
	arr.forEach(item => {
		if (item === 2) {
			throw('循环终止')
		}
		console.log(item)
	})
} catch(e) {
	console.log('e: ', e)
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uMUrZYNr-1575273502332)(en-resource://database/1648:0)]

19、判断一个数据在数组中是否存在?

  • javascript的indexOf()方法
    var arr_data = [1,2,3];
    arr_data.indexOf(1); //如果存在返回值的下标,不存在返回-1

  • jquery的$.inArray()方法
    $.inArray(1, arr_data); //如果存在返回值的下标,不存在返回-1

  • arr.find()
    数组实例的find()用于找出第一个符合条件的数组元素。它的参数是一个回调函数,所有的数组元素依次遍历该回调函数,直到找出第一个返回值为true的元素,然后返回该元素,否则返回undefined。
    注意:find()对于空数组,函数是不会执行的。find()并没有改变数组的原始值

   arr.find(function(value) { 
      if(value === 要查找的值) { 
          //则包含该元素    
   }})
  • arr.findIndex()返回第一个符合条件的数组元素的位置,如果所有的元素都不符合条件,则返回-1.

注意:find(),findIndex()弥补了index的不足:(即判断NAN)

    [NaN].indexOf(NaN) // -1
    [NaN].findIndex(y => Object.is(NaN, y))// 0
  • for循环和if判断

20、数组拍平

例:var arr = [1,2,[3,4,5,[6,7,8],9],10,[11,12]]

  1. 递归实现:
function fn(arr){
    let arr1 = []
     arr.forEach((val)=>{
         if(val instanceof Array){
             arr1 = arr1.concat(fn(val))
         }else{
             arr1.push(val)
         }
      })
      return arr1
 }
  1. reduce实现
function fn(arr){
    return arr.reduce((prev,cur)=>{
        return prev.concat(Array.isArray(cur)?fn(cur):cur)
    },[])
}
  1. flat
arr.flat(Infinity)
  1. 扩展运算符
function fn(arr){
    let arr1 = [];
    let bStop = true;
    arr.forEach((val)=>{
        if(Array.isArray(val)){
            arr1.push(...val);
            bStop = false
        }else{
            arr1.push(val)
        }
    })
    if(bStop){
        return arr1;
    }
    return fn(arr1)
}
  1. toString
let arr1 = arr.toString().split(',').map((val)=>{
           return parseInt(val)
       })
       console.log(arr1)
  1. apply
function flatten(arr){
    while(arr.some(item => Array.isArray(item))){
          arr =  [].concat.apply([],arr);
    }
     return arr;
}

猜你喜欢

转载自blog.csdn.net/BookstoreSpirit/article/details/103296869