• 前端面试题


    1. 前端开发中常见的拖拽排序效果视频:https://www.bilibili.com/video/BV1Jm4y1M79D/?spm_id_from=333.880.my_history.page.click&vd_source=5c584bd3b474d579d0bbbffdf0437c70
    2.axios请求二次封装都做些什么视频:https://www.bilibili.com/video/BV1fg4y1M7pe/?spm_id_from=333.880.my_history.page.click&vd_source=5c584bd3b474d579d0bbbffdf0437c70
    3.Vue axios 前端接口请求封装API视频:https://www.bilibili.com/video/BV18R4y1J7sm/?spm_id_from=333.880.my_history.page.click&vd_source=5c584bd3b474d579d0bbbffdf0437c70
    4.项目上线打包优化:https://www.bilibili.com/video/BV1z34y1T7ez/?spm_id_from=333.788&vd_source=5c584bd3b474d579d0bbbffdf0437c70
    5.使用nginx部署vue项目及常见问题:https://www.bilibili.com/video/BV1x84y1k7qf/?spm_id_from=333.1007.top_right_bar_window_history.content.click&vd_source=5c584bd3b474d579d0bbbffdf0437c70
    6.es6 class的使用参考文章:https://juejin.cn/post/6964312782552432670
    7.图片加水印:https://juejin.cn/post/6844903645155164174(网页加水印)
    https://juejin.cn/post/7236286358389047354
    8.开发中的难点亮点:https://juejin.cn/post/7074573053979525151
    9.react hooks的学习视频:https://www.bilibili.com/video/BV1ZB4y1Z7o8/?spm_id_from=333.337.search-card.all.click&vd_source=5c584bd3b474d579d0bbbffdf0437c70   , https://www.bilibili.com/video/BV1sV411c7u9/?spm_id_from=autoNext&vd_source=5c584bd3b474d579d0bbbffdf0437c70
    10.react开发中,结合useState(list)给数组排序可以使用 lodash这个库来使用。lodash官网:lodash.com   /  lodash.com/docs/
    11.react开发中,className动态添加类名可以加载classnames包:使用方法在下面
    12.vue自定义指令与修饰符文章:https://blog.csdn.net/m0_71485750/article/details/126175776
    13.react全家桶+底层原理:https://www.bilibili.com/video/BV17e411r7TH/?spm_id_from=333.337.search-card.all.click&vd_source=5c584bd3b474d579d0bbbffdf0437c70
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    上述11点,使用classnames包的方法

    1.命令安装classnames包
    npm install classnames
    
    2.在组件中引入
    import classNames from 'classname';
    
    3.在组件内使用, ‘’包裹的是静态的class, 
    {
    	// active是动态的class名,值是判断条件,是否需要加active这个class
    	active: type === item.type
    }包裹的是动态的class
    
    从这样的:nav-item为静态class类名,active为动态class类名
    <span className={`nav-item ${type === item.type && 'active'}`}>span...</span>
    
    变成这样:
    <span className = {classNames('nav-item', {
    	active: type === item.type
    })}>span...</span>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    1、webpack是什么?

    webpack是一个用于现代javascript应用程序的 静态模块打包工具。当webpack处理应用程序时,它会在内部从一个或多个入口点构建一个依赖图,然后将项目中所需的每一个模块组合成一个或多个包(bundles),他们均为静态资源,用于展示内容。

    2、webpack中loader和plugin的作用是什么?

    loader: loader让webpack能够去处理那些非javescript文件(webpack自身只理解javascript)
    plugins:插件(plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量等。

    3、说一下原型链和继承?

    (1)每个构造函数都有一个原型对象,原型对象都包含指向构造函数的指针,而实例都包含一个指向原型对象的内部指针(proto)
    (2)一个对象会指向一个原型,原型对象会有自己的原型,以此类推,构成原型链
    (3)实例使用方法和属性时,会先从构造函数内部找,找不到再去原型对象上找,还找不到就去原型对象的原型上找,直到(原型对象的原型为null) Object.prototype.proto===null,停止寻找
    继承:(4)继承是指能够访问另外一个对象中的方法和属性。

    4、js去重你能想到多少种方法?

    (1)Array.from(new Set(array))
    (2)newArray.filter 返回[item]/newArray.find 返回item项
    (3)newArray.include(旧item) 返回true/false
    (4)使用对象属性名的唯一性来保证不重复 let obj = {} if(!obj[array[i]]) { result[array[i]] = true } Object.keys(obj);
    (5)使用indexOf(item) === -1, newArray.indexOf(arr1[i]) === -1
    (6)使用Map数据结构去重: let map = new Map(); if (map.has(array[i])) {map.set(array[i], true)}

    5、js中this的指向

    (1)全局环境下指向widow,严格模式下undenfind, 函数也指向window。
    (2)对象内部方法的this指向调用这些方法的对象,也就是谁调用就指向谁。
    (3)箭头函数中的this指向于函数作用域所用的对象。
    (4)构造函数中的this是指向实例
    更改this指向:call / apply / bind()方法

    6、promise的用法?你在什么情况下会使用promise?

    用法(Promise对象是一个构造函数,用来生成Promise实例)
    let p = function () {return new Promise((resolve,reject) => {resolve(‘需要返回出去的值’)})}
    p.then(data => {})

    7、node是如何处理高并发的

    (1)事件循环机制:
    Node.js采用事件驱动机制,通过事件轮询的方式实现异步I/O操作。当有异步I/O操作完成时,会将对应的事件加入到事件队列中,由事件循环机制负责调度执行。事件循环机制是Node.js实现高并发的核心,它能够充分利用CPU资源,减少I/O的阻塞等待时间,提高了处理请求的效率。
    (2)非阻塞I/O:
    Node.js采用非阻塞I/O,避免了I/O的阻塞等待时间,从而提高程序的并发性能。非阻塞I/O是指在进行I/O操作时,不会阻塞后续代码的执行,而是在后台等待I/O操作完成后立即返回结果。这种方式可以减少线程切换的开销,提高了整个应用程序的执行效率。
    (3)事件驱动回调函数:
    Node.js采用事件驱动回调函数,使得应用程序能够及时响应用户的请求。通过这种方式,当用户请求进入系统时,会获取一个事件处理器,并注册一个回调函数,当事件处理器产生事件时,会自动调用注册的回调函数进行处理。这种方式能够提高系统的响应速度和处理能力。
    (4)内置异步模块:
    Node.js内置的异步模块也是实现高并发的关键。Node.js提供了各种内置的异步模块,例如HTTP、HTTPS、FS、Net等,这些模块都是通过事件循环机制结合非阻塞I/O实现的,可以在高并发的情况下高效地处理请求。
    (5)Cluster模块:
    Cluster是Node.js中用于多进程处理的模块。该模块可以启用多个子进程来处理请求,从而提高应用程序的并发性能。每个子进程都是独立的,因此可以充分利用CPU资源,提高系统的处理能力。使用Cluster模块可以有效地解决单线程模型下的瓶颈问题,使得系统能够更加高效地处理大量的请求。

    8、介绍一下node中require模块的加载机制

    模块在第一次加载后会被缓存。这也意味着多次调用require()不会导致模块的代码被多次执行。
    (1)内置模块的加载优先级最高:例如,require(‘fs’) 始终返回内置的 fs 模块,即使在 node_modules 目录下有名字相同的包也叫做 fs。

    (2)自定义模块的加载机制:
    使用 require() 加载自定义模块时,必须指定以 ./ 或 …/ 开头的路径标识符。在加载自定义模块时,如果没有指定 ./ 或 …/ 这样的路径标识符,则 node 会把它当作内置模块或第三方模块进行加载。
    同时,在使用 require() 导入自定义模块时,如果省略了文件的扩展名,则 Node.js 会按顺序分别尝试加载以下的文件:
    1.按照确切的文件名进行加载
    2.补全 .js 扩展名进行加载
    3.补全 .json 扩展名进行加载
    4.补全 .node 扩展名进行加载
    5.加载失败,终端报错

    (3)第三方模块的加载机制:如果传递给 require() 的模块标识符不是一个内置模块,也没有以 ‘./’ 或 ‘…/’ 开头,则 Node.js 会从当前模块的父目录开始,尝试从 /node_modules 文件夹中加载第三方模块。
    例如,假设在 ‘C:\Users\itheima\project\foo.js’ 文件里调用了 require(‘tools’),则 Node.js 会按以下顺序查找:

    C:\Users\itheima\project\node_modules\tools
    C:\Users\itheima\node_modules\tools
    C:\Users\node_modules\tools
    C:\node_modules\tools

    (4)目录作为模块:当把目录作为模块标识符,传递给 require() 进行加载的时候,有三种加载方式:
    在被加载的目录下查找一个叫做 package.json 的文件,并寻找 main 属性,作为 require() 加载的入口
    如果目录里没有 package.json 文件,或者 main 入口不存在或无法解析,则 Node.js 将会试图加载目录下的 index.js 文件。
    如果以上两步都失败了,则 Node.js 会在终端打印错误消息,报告模块的缺失:Error: Cannot find module ‘xxx’

    9、闭包的作用是什么?你能举个使用闭包的例子吗?

    (1)延长局部变量的寿命
    (2)使外部能够访问到函数内部的变量
    例子: 如果一个属性是全局变量,不想让人直接访问,局部变量又访问不到时,暴露一个函数让间接访问;

    function(){
      var lives = 50
      window.奖励一条命 = function(){  // 简明起见,用了中文
        lives += 1
      }
      window.死一条命 = function(){
        lives -= 1
      }
    }()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    10、当在浏览器输入url后,发生了些什么?

    (1)URL 解析:浏览器首先对 URL 解析,解析出协议、域名、端口、资源路径、参数等。
    (2)DNS 域名解析:首先需要将一个域名转化为相应的 IP 地址
    (3)建立TCP连接
    (4)发送HTTP请求:当浏览器与服务器建立连接后,就可以进行数据通信过程,浏览器会给服务器发送一个 HTTP 请求报文,请求报文包括请求行、请求头、请求空行和请求体。在请求行中会指定方法、资源路径以及 HTTP 版本,其中资源路径是指定所要操作资源在服务器中的位置,而方法是指定要对这个资源做什么样的操作。
    (5)服务器对请求进行处理并作出响应
    (6)浏览器解析渲染页面
    (7)断开TCP连接
    注意:
    浏览器为了提升性能,在 URL 解析之后,实际会先查询是否有缓存,如果缓存命中,则直接返回缓存资源。
    如果是 HTTPS 协议,在建立 TCP 连接之后,还需要进行 SSL/TLS 握手过程,以协商出一个会话密钥,用于消息加密,提升安全性。

    11、说下vue的生命周期

    Vue的生命周期钩子函数主要包括:

    • 1.beforeCreate(): 在实例初始化之后调用, data和methods都还没有初始化完成, 通过this不能访问
    • 2.created(): 此时data和methods都已初始化完成, 可以通过this去操作, 可以在此发ajax请求
    • 3.beforeMount(): 模板已经在内存中编译, 但还没有挂载到页面上, 不能通过ref找到对应的标签对象
    • 4.mounted(): 页面已经初始显示, 可以通过ref找到对应的标签, 也可以选择此时发ajax请求
    • 5.beforeUpdate(): 在数据更新之后, 界面更新前调用, 只能访问到原有的界面
    • 6.updated(): 在界面更新之后调用, 此时可以访问最新的界面
    • 7.beforeDestroy(): 实例销毁之前调用, 此时实例仍然可以正常工作
    • 8.destroyed(): Vue 实例销毁后调用, 实例已经无法正常工作了
    • 9.deactivated():组件失活, 但没有死亡
    • 10.activated(): 组件激活, 被复用
    • 11.errorCaptured(): 用于捕获子组件的错误,return false可以阻止错误向上冒泡(传递)
    • 我们通常在created()/mounted()进行发送ajax请求,启动定时器等异步任务,而在beforeDestory()做收尾工作,如: 清除定时器操作。

    不过需要注意的是mounted生命周期钩子中并不代表界面已经渲染成功,因为 mounted 不会保证所有的子组件也都一起被挂载。如果你希望等到整个视图都渲染完毕,可以在 mounted 内部使用 vm.$nextTick。
    js面试题:

    <div ref="text"></dev>
    beforeMouted() {
     console.log(this.$refs.text); // 会打印什么
    }
    
    mouted() {
     console.log(this.$refs.text); // 会打印什么
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    12、怎样判断在屏幕的可视化区域

    • offsetTop、scrollTop
    • getBoundingClientRect
    • Intersection Observer
    <body>
      <div class="box1">
        <!-- offsetTop, scrollTop -->
        <!-- getBoundingClientRect -->
        <!-- IntersectionObserver -->
      </div>
      <div class="box2" id="box2">123456</div>
    
      <style>
        .box1 {
          height: 1000px;
        }
      </style>
    </body>
    <script>
      console.log(window.innerHeight)
      console.log(document.getElementById('box2').offsetTop)
      console.log(document.documentElement.scrollTop)
      console.log(document.getElementById('box2').getBoundingClientRect())
    
      // 方法一:offsetTop - scrollTop <= window.innerHeight;
      function isInViewPortOfOne(el) {
        // viewPortHeight 兼容所有浏览器写法
        const viewPortHeight = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
        const offsetTop = el.offsetTop;
        const scrollTop = document.documentElement.scrollTop;
        const top = offsetTop - scrollTop;
        return top <= viewPortHeight;
      }
    
      // 方法二:getBoundingClientRect
      // {
      //   top, // 元素顶部距离屏幕顶部的距离
      //   bottom, // 元素底部距离屏幕顶部的距离
      //   left, // 元素左边距离屏幕左边的距离
      //   right, // 元素右边距离屏幕右边的距离
      //   x,
      //   y,
      //   width,
      //   height, // 元素的宽和高
      // }
      /**
       * 1.top 大于等于0
       * 2.left大于等于0
       * 3.bottom小于等于视窗高度
       * 4.right小于等于视窗宽度
       */
      function isInViewPortOfOne(el) {
        const viewWidth = window.innerWidth || document.document.clientWidth;
        const viewHeight = window.innerHeight || document.document.clientHeight;
        const {
          top,
          right,
          bottom,
          left,
        } = el.getBoundingClientRect();
    
        return (
          top >= 0 &&
          left >= 0 &&
          right <= viewWidth &&
          bottom <= viewHeight
        )
      }
    
      // 以上方法可以实现,但是需要监听浏览器滚动,需要有大量计算
      // 方法三:Intersection Observer 浏览器原生提供的构造函数,接收两个参数,callback和options
      // callback会触发两次,元素刚进入可视区域时,元素完全看不到时
      const intersectionObserver = new IntersectionObserver(function (entries) {
        if (entries[0].intersectionRatio <= 0) return; // 小于0完全不可见,0-1部分可见,大于等于1完全可见
        console.log('已经进入可视区域');
      })
    
      // 开始观察,监听元素
      intersectionObserver.observe(document.getElementById('box2'));
    
      // 停止观察
      intersectionObserver.unobserve(document.getElementById('box2'));
    
      // 关闭观察器
      intersectionObserver.disconnect();
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82

    13、说下如下代码的值

    let a= {
    	name: 'A',
    	fun: function() {
    		console.log(this.name);
    	}
    }
    console.log(a.fun()); // A
    console.log(a.fun.call({name: 'B'})); // B
    let f1 = a.fun();
    console.log(f1); // A
    
    console.log(typeof undefined) // undefined
    console.log(typeof null) // object
    console.log(typeof console.log) // function
    console.log(typeof [1, 2, 3]) // object
    console.log(typeof '123') // string
    console.log(typeof 123) // number
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    13.promise用过什么方法?

    promise.all
    promise.resolve
    promise.reject
    promise.race 与 all的区别
    promise还有async和await
    面试题:Promise.all一个请求失败也能得到其余正确的请求结果

    参考文章:https://blog.csdn.net/qq_43592064/article/details/130829067
    Promise.all默认只要有一个错误就直接返回错误。promise.all中任何一个promise 出现错误的时候都会执行reject,导致其它正常返回的数据也无法使用
    Promise.all(
      [
        Promise.reject({ code: 500, msg: "服务异常" }),
        Promise.resolve({ code: 200, list: [] }),
        Promise.resolve({ code: 200, list: [] })
      ].map(p => p.catch(e => e))
    )
      .then(res => {
        console.log("res=>", res);
      })
      .catch(error => {
        console.log("error=>", error);
      });
    res=> [ { code: 500, msg: '服务异常' },
      { code: 200, list: [] },
      { code: 200, list: [] } ]
    核心内容是map方法,map的每一项都是promise,catch方法返回值会被promise.reslove()包裹,这样传进promise.all的数据都是resolved状态的。
     
    // 使用Promise.all 其中id为69的商品,返回失败,会导致整个Promise接受到reject状态.
    // 所以进行改造, p catch 得到的err  为返回失败抛出的信息, 进行置空
    .map(p => p.catch(err => '')))
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    14.ajax,axios请求应该放在created里还是mounted里?放在creacted里会造成什么影响?

    参考视频
    vue的created和mounted是同步执行,会先执行created里面的同步代码,然后把请求当成微任务挂起(先发送请求padding状态),然后再执行mounted里的同步代码,mounted里的代码执行完毕后,会渲染页面。请求结果才接收到,当收到结果后有更新data里面的数据,那么会再渲染一次。
    看一下代码

    <template>
    	<div>
    		<ul>
    			<li v-for="item in cityList" :key="item.id">{{item.name}}</li>
    		</ul>
    	</div>
    </template>
    <script>
    export default {
    	data() {
    		cityList: [],
    	},
    	created() {
    		conslole.log('created');
    		alert('created'); // 会阻止后续代码运行
    		this.getCityList();
    	},
    	mounted() {
    		conslole.log('mounted');
    		alert('mounted'); // 会阻止后续代码运行
    	},
    	methods: {
    		async getCityList() {
    			const res = await axions({...});
    			this.cityList = res.data.list;
    		}
    	}
    }
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    执行上面代码顺序为:
    conslole.log(‘created’);
    alert(‘created’);
    this.getCityList();发送请求,但是请求状态为padding,挂起等待状态
    再执行mounted的代码
    conslole.log(‘mounted’);
    alert(‘mounted’); // mounted代码执行完毕加载页面,组件首次渲染
    最后this.getCityList();请求执行完毕获取数据,组件重新渲染,刷新页面,所以会刷新两次页面

    另外观点:参考文章:https://blog.csdn.net/dongwei666/article/details/126364290
    总结:如果无需操作dom,可以在created里面进行请求,数据与dom同步渲染,减少渲染次数,但是不可过多请求,否则屏幕将会出现白屏
    如果有dom操作就在mounted里面请求,也不可过多请求,否则渲染次数过多

    15.怎么验证用户有没有登录?路由守卫怎么设置?

    • 直接在配置路由的地方设置beforeEnter()方法
    export default new Router({
    	routes: [
    		{
    			path: '/login',
    			name: 'login',
    			component: Login
    		}, 
    		{
    			path: '/register',
    			name: 'register',
    			component: Register, // component: () => import 'xxx/xx.vue'
    			beforeEnter(to, from, next) {
    				console.log(to);
    				console.log(from);
    				console.log(next);
    				next(); // 放行,必须有,否则跳不到页面
    				next(false); // 禁止跳转路由点击无效
    				if (from.path === '/login') {
    					next(); // 如果从登录页面来的注册页面就放行跳到注册页面
    				} else {
    					// 重定向
    					next('/login'); // 如果不是,重定向到登录页面
    				}
    			}
    		}
    	]
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 使用router.beforeEach()方法
    const router = new Router({
    	router: [
    		{
    			path: '/login',
    			name: 'Login',
    			component: 组件/ import 'xx/xx.vue'
    		}
    	]
    })
    
    router.beforeEach((to,from, next) => {
    	...
    	next();
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    16.说下原型和原型链

    1. 什么是原型?
      在js中,每个构造函数内部都有一个prototype属性,该属性的值是个对象,该对象包含了该构造函数所有实例共享的属性和方法。当我们通过构造函数创建对象的时候,在这个对象中有一个指针,这个指针指向构造函数的prototype的值,我们将这个指向prototype的指针称为原型。或者用另一种简单却难理解的说法是:js中的对象都有一个特殊的[[Prototype]]内置属性,其实这就是原型。(简单来说原型就是对象或者函数下面的prototype属性)

    2. 如何获取对象原型值?

    • 在浏览器上可以使用__proto__,例如a.__proto__
    • 推荐使用Object.getPrototypeOf(a)
    1. 原型链?
      JS的每个函数在创建的时候,都会生成一个属性prototype,这个属性指向一个对象,这个对象就是此函数的原型对象。该原型对象中有个属性为constructor,指向该函数。这样原型对象和它的函数之间就产生了联系。

    17.new关键字做了什么?

    构造函数创建一个实例的过程

    • 创建一个新对象
    • 将构造函数的作用域赋值给新对象(这样this就指向了新对象)
    • 执行构造函数中的代码(为新对象添加实例属性和实例方法)
    • 返回新对象

    18. watch与computed的区别?

    功能上:

    • computed是计算属性,watch是监听一个值的变化,然后执行对应的回调。
    • 是否调用缓存:computed中的函数所依赖的属性没有发生变化,那么调用当前的函数的时候会从缓存中读取,而watch在每次监听的值发生变化的时候都会执行回调。
    • 是否调用return:computed中的函数必须要用return返回,watch中的函数不是必须要用return。
    • computed默认第一次加载的时候就开始监听;watch默认第一次加载不做监听,如果需要第一次加载做监听,添加immediate属性,设置为true(immediate:true)
    • 区别总结:
      computed支持缓存,相依赖的数据发生改变才会重新计算;watch不支持缓存,只要监听的数据变化就会触发相应操作
      computed不支持异步,当computed内有异步操作时是无法监听数据变化的;watch支持异步操作
      computed属性的属性值是一函数,函数返回值为属性的属性值,computed中每个属性都可以设置set与get方法。watch监听的数据必须是data中声明过或父组件传递过来的props中的数据,当数据变化时,触发监听器

    使用场景:
    computed----当一个属性受多个属性影响的时候,使用computed-----购物车商品结算。watch–当一条数据影响多条数据的时候,使用watch-----搜索框.

    19. px, rpx, em, rem有什么不同?

    参考文档:https://zhuanlan.zhihu.com/p/156940153

    • px: 相对长度单位。像素px是相对于显示器屏幕分辨率而言的。
    • rpx: 其实是微信对于rem的一种应用的规定,或者说一种设计的方案,官方上规定屏幕宽度为20rem,规定屏幕宽为750rpx。
      所以在微信小程序中1rem=750/20rpx。
    • em: 相对长度单位。相对于当前对象内文本的字体尺寸。如当前对行内文本的字体尺寸未被人为设置,则相对于浏览器的默认字体尺寸。浏览器默认的字号是16px。所有未经调整的浏览器都符合: 1em=16px。
      em的特点:
      em的值并不是固定的;
      em会继承父级元素的字体大小。
      因为这两个特点,所以我们用em的时候,需要注意三点:
      body选择器中声明Font-size=62.5%;
      将你的原来的px数值除以10,然后换上em作为单位;
      重新计算那些被放大的字体的em数值。避免字体大小的重复声明。
    • rem: rem是相对于根元素,也就是说,我们只需要在根元素确定一个参考值,其他子元素的值可以根据这个参考值来转换。具体这个参考值设置为多少,完全可以根据我们自己的需求来定。
      用法:
     rem用法:以html根元素设置参考值
     html {
            font-size: 10px;
     }
     div {
         font-size: 4rem; /* 40px */
         width: 20rem;  /* 200px */
         height: 20rem;
     }
     p {
         font-size: 2rem; /* 20px */
         width: 10rem;
         height: 10rem;
         border: solid 1px blue;
     }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    20. react中class组件与函数组件有什么不同?

    • 定义方式不同:
      class组件定义:class Xxx extends React.Compont {} 继承React.Component,且需要创建render方法来返回元素。
      函数组件: function Xxx() {} 函数组件名字必须大写
    • class:
    1. 有组件实例
    2. 有生命周期
    3. 有 state 和 setState
    4. 有ref
    • 函数组件:
    1. 没有组件实例
    2. 没有生命周期, 需要使用hook的 useEffect hooks函数组件的缺点: 没法保存state, 如需保存state,则需要使用useRef();
    3. 没有 state 和 setState,只能接收 props
    4. 函数组件是一个纯函数,执行完即销毁,无法存储 state
    5. 没有ref,但可以在函数组件内部使用 ref 属性,只要它指向一个 DOM 元素或 class 组件。

    class 组件存在的问题:
    大型组件很难拆分和重构,变得难以测试
    相同业务逻辑分散到各个方法中,可能会变得混乱
    复用逻辑可能变得复杂,如 HOC 、Render Props
    所以 react 中更提倡函数式编程,因为函数更灵活,更易拆分,但函数组件太简单,所以出现了hook,hook就是用来增强函数组件功能的。

    21. 原生小程序和uniapp小程序中有哪些生命周期钩子

    参考:http://jerryzou.com/posts/cookie-and-web-storage/
    原生小程序生命周期构子:

    • onLoad :页面加载时触发
    • onShow : 页面显示时触发 , 包括页面初次加载 , 从其他页面返回到当前页面
    • onReady : 页面初次渲染完成时触发
    • onHide : 页面隐藏时触发 , 当跳转到其他页面,关闭当前页面触发
    • onUnload:页面卸载时触发,当页面销毁时触发。
    • onPullDownRefresh : 下拉刷新时触发
    • onReachBottom:滚动到页面底部时触发。
    • onShareAppMessage:点击页面转发按钮时触发。
    • onPageScroll:页面滚动时触发。
    • onTabItemTap:点击底部tab栏时触发。

    uniapp小程序生命周期钩子:

    • onLoad:页面加载时触发。
    • onReady:页面初次渲染完成时触发。
    • onShow:页面显示时触发,包括页面初次加载、从其他页面返回到当前页面。
    • onHide:页面隐藏时触发,当跳转到其他页面、关闭当前页面时触发。
    • onUnload:页面卸载时触发,当页面销毁时触发。
    • onPullDownRefresh:下拉刷新时触发。
    • onReachBottom:滚动到页面底部时触发。
    • onShareAppMessage:点击页面转发按钮时触发。
    • onResize:页面尺寸变化时触发。
    • onTabItemTap:点击底部tab栏时触发。

    22. cookie、sessionStorage、localStorage的区别

    • cookie: 由服务器生成,大小限制为4KB左右, cookie在与服务器端通信每次都会携带在HTTP头中,可设置失效时间
    • sessionStorage:在客户端生成,它只是可以将一部分数据在当前会话中保存下来,刷新页面数据依旧存在。但当页面关闭后,sessionStorage 中的数据就会被清空。
    • localStorage:在客户端生成,localStorage除非被清除,否则会永久保存

    三者异同
    cookie 一般由服务器生成,可设置失效时间。如果在浏览器端生成Cookie,默认是关闭浏览器后失效,存放数据大小一般4K左右,而sessionStorage与localStorage大小在5兆左右,在客户端生成,localStorage除非被清除,否则会永久保存,sessionStorage仅在当前会话下有效,关闭页面或浏览器后被清除,cookie在与服务器端通信每次都会携带在HTTP头中,如果使用cookie保存过多数据会带来性能问题,而sessionStorage与localStorage仅在客户端(即浏览器)中保存,不参与和服务器的通信。

    1. cookie由服务端生成,用于标识用户身份;而两个storage用于浏览器端缓存数据
    2. 三者都是键值对的集合
    3. 一般情况下浏览器端不会修改cookie,但会频繁操作两个storage
    4. 如果保存了cookie的话,http请求中一定会带上;而两个storage可以由脚本选择性的提交
    5. 会话的storage会在会话结束后销毁;而local的那个会永久保存直到覆盖。cookie会在过期时间之后销毁。
    6. 安全性方面,cookie中最好不要放置任何明文的东西。两个storage的数据提交后在服务端一定要校验(其实任何payload和qs里的参数都要校验)。

    23. vue3新特性

    参考文章:https://juejin.cn/post/6968094627375087653

    • 创建app实例方式从原来的new Vue()变为通过createApp函数进行创建;这样带来的变化就是以前在全局配置的组件(Vue.component)、指令(Vue.directive)、混入(Vue.mixin)和插件(Vue.use)等变为直接挂载在实例上的方法;我们通过创建的实例来调用,带来的好处就是一个应用可以有多个Vue实例,不同实例之间的配置也不会相互影响
    const app = createApp(App)
    app.use(/* ... */)
    app.mixin(/* ... */)
    app.component(/* ... */)
    app.directive(/* ... */)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 周期函数钩子变化:新增setup钩子函数,在beforeCreate之前执行,将beforeDestroy改名为beforeUnmount,destroyed改名为unmounted
    • vue3新增了生命周期钩子,我们可以通过在生命周期函数前加on来访问组件的生命周期:
    onBeforeMount
    onMounted
    onBeforeUpdate
    onUpdated
    onBeforeUnmount
    onUnmounted
    onErrorCaptured
    onRenderTracked
    onRenderTriggered
    
    使用:
    import { onBeforeMount, onMounted } from "vue";
    export default {
      setup() {
        console.log("----setup----");
        onBeforeMount(() => {
          // beforeMount代码执行
        });
        onMounted(() => {
          // mounted代码执行
        });
      },
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    响应式API:

    • ref/reactive

    24. 怎么让元素垂直居中

    知道父元素高度的:

    • 方法一:使用transform来位移元素
    <body>
      <div class="box">
        <div class="box-child">123456</div>
      </div>
    
      <style>
        .box {
          position: relative;
          width: 300px;
          height: 300px;
        }
    
        .box-child {
          position: absolute;
          left: 50%;
          top: 50%;
          transform: translate(-50%, -50%);
        }
      </style>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 方法二:使用display: flex布局
    <body>
      <div class="box">
        <div class="box-child">123456</div>
      </div>
    
      <style>
        .box {
          display: flex;
          justify-content: space-around/center; // space-around/center都可以
          align-items: center;
          width: 300px;
          height: 300px;
        }
      </style>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 方法三:表格,display: table-cell;此元素会作为一个表格单元格显示 类似于td th
    <body>
      <div class="box">
        <div class="box-child">123456</div>
      </div>
    
      <style>
        .box {
          display: table-cell;
          text-align: center;
          vertical-align: middle;
          width: 300px;
          height: 300px;
        }
    
        .box-child {
          vertical-align: middle;
          display: inline-block;
        }
      </style>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 方法四:使用postion和margin:auto来设置

    注意:此方法需要设置子元素宽高,width,height

    <body>
      <div class="box">
        <div class="box-child">123456</div>
      </div>
    
      <style>
        .box {
          position: relative;
          width: 300px;
          height: 300px;
        }
    
        .box-child {
          position: absolute;
          width: 50px;
          height: 50px;
          left: 0;
          right: 0;
          top: 0;
          bottom: 0;
          margin: auto;
        }
      </style>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 方法五:子元素设置display: inline-block,父元素设置text-align: center且line-height等于height
      将子元素设为行内块元素,父元素设置左右居中,同时通过让父元素的line-height属性等于height属性实现子元素上下居中。
    <body>
      <div class="box">
        <div class="box-child">123456</div>
      </div>
    
      <style>
        .box {
          width: 100vw;
          height: 100vh;
          line-height: 100vh;
          text-align: center;
        }
    
        .box-child {
          display: inline-block;
        }
      </style>
    </body>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    25.如何渲染10万条数据?

    • 虚拟列表的方式,getBoundingClientRect判断滚动条是往上还是往下,只渲染可视区域
    • 时间分片:window.requestAnimationFrame和document.createDocumentFragment
    <script>
      <ul id="box"></ul>
    
      const ul = document.getElementById('box');
      const totalNum = 1000000;
      const onceNum = 20;
      const page = totalNum / onceNum
      let index = 0;
    
      function loop(curTotal, curIndex) {
        if (curTotal <= 0) {
          return false;
        }
    
        const pageCount = Math.min(curTotal, onceNum);
        window.requestAnimationFrame(() => {
          let fragment = document.createDocumentFragment();
          for (let i = 0; i < pageCount; i++) {
            let li = document.createElement('li');
            li.innerText = curIndex + i + ':' + ~~(Math.random() * total);
            fragment.appendChild(li)
          }
          ul.appendChild(fragment);
          loop(curTotal - pageCount, curIndex + pageCount);
        })
      }
      loop(totalNum, index);
    </script>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    26.localStorage与sessionStorage的大小是多大?超出了怎么办?indexedDB有了解吗?

    大小都在5MB左右
    localstorage存储不是5m 是每个域5m 超了申请其他的域/修改ng配置 postmessge通信往其他域上存取,或者清除不需要的存储,压缩或减少体积,或者使用indexedDB
    indexedDB参考文章:
    https://juejin.cn/post/7026900352968425486
    https://juejin.cn/post/7249386837369159735?from=search-suggest

    27.keep-alive有了解吗?

    keep-alive作为一种vue的内置组件,主要作用是缓存组件状态。当需要组件的切换时,不用重新渲染组件,避免多次渲染,就可以使用keep-alive包裹组件。
    参考文章:https://juejin.cn/post/7091490734041219086

    28.协商缓存,强缓存有了解吗?

    • 强缓存:浏览器不会像服务器发送任何请求,直接从本地缓存中读取文件并返回Status Code: 200 OK
      在这里插入图片描述
      在这里插入图片描述

    200 form memory cache : 不访问服务器,一般已经加载过该资源且缓存在了内存当中,直接从内存中读取缓存。浏览器关闭后,数据将不存在(资源被释放掉了),再次打开相同的页面时,不会出现from memory cache。
    200 from disk cache: 不访问服务器,已经在之前的某个时间加载过该资源,直接从硬盘中读取缓存,关闭浏览器后,数据依然存在,此资源不会随着该页面的关闭而释放掉下次打开仍然会是from disk cache。
    优先访问memory cache,其次是disk cache,最后是请求网络资源

    • 协商缓存: 向服务器发送请求,服务器会根据这个请求的request header的一些参数来判断是否命中协商缓存,如果命中,则返回304状态码并带上新的response header通知浏览器从缓存中读取资源;
      在这里插入图片描述
      参考文章:https://juejin.cn/post/6844903838768431118

    29. DNS域名解析是在哪一步操作?

    1. 浏览器先检查自身缓存中有没有被解析过的这个域名对应的IP地址,如果有解析结束,同时域名被缓存的时间也可通过TTL属性来设置。
    2. 如果浏览器缓存中没有命中(没有),浏览器会检查操作系统缓存中有没有对应的已解析的结果。而操作系统也有一个域名解析的过程,在windows中可通过C盘里面一个叫做hosts的文件来设置,如果你在这里指定一个域名对应的IP地址,那浏览器会首先使用这个IP地址。但是这种操作系统级别的域名解析过程也被很多黑客利用,通过修改你的hosts文件里的内容吧特定的域名解析到他指定的IP地址还是那个,造成所有的域名劫持。所以在window7中将hosts文件设置成了readonly,防止恶意篡改
    3. 如果还没有命中域名,才会真正的请求本地域名服务器(LDNS)来解析和这个域名,这个服务器一般在你的城市的某个角落,距离不是很远,而且这台服务器的性能很好,一般都会缓存域名解析结果,大约80%的域名解析到这里就完成了。浏览器(主机)向其本地域名服务器进行的是递归查询。
    4. 本地域名服务器采用迭代查询,它先向下一个根域名服务器查询
    5. 根域名服务器如果有查询的IP的值则返回,没有命中,则告诉本地域名服务器,下一次查询的顶级域名服务器的IP的值
    6. 本地域名服务器向收到的顶级域名服务器进行查询
    7. 顶级域名服务器如果有查询的IP地址则返回,没有命中,则告诉本地域名服务,下一次查询的权限域名服务器的IP的地址
    8. 本地域名服务器向权限域名服务器进行查询
    9. 权限域名服务器告诉本地域名服务器,所查询的IP地址
    10. 本地域名服务器最后把查询的结果告诉浏览器(主机)。

    原文链接:https://blog.csdn.net/qq_37288477/article/details/86582130

    30. script上的defer, async有什么区别?

    • 二者都是异步去加载外部JS文件
    • async是在外部JS加载完成后,浏览器空闲时,Load事件触发前执行;而Defer是在JS加载完成后,整个文档解析完成后执行。
    • defer更像是将script标签放在body之后的效果,但是它由于是异步加载JS文件,所以可以节省时间。
      参考文章: https://zhuanlan.zhihu.com/p/30898865

    31.低代码有了解吗?

    参考文章:https://zhuanlan.zhihu.com/p/559966882

    32.浏览器渲染优化

    • (1)针对javascript:javascript会阻塞HTML的解析,也会阻塞css的解析。因此我们可以对javascript的加载方式进行改变来进行优化:
    1. 尽量将javascript文件放在body的最后
    2. body中间尽量不要写<script>标签
    3. <script>标签的引入资源方式有三种,一种就是我们常用的直接引入,还有两种就是使用async属性和defer属性来异步引入,
    两者都是去异步加载外部的js文件,不会阻塞dom的解析(尽量使用异步加载),三者的区别如下:
     *script立即停止页面渲染去加载资源文件,当资源加载完毕后立即执行js代码,js代码执行完毕后继续渲染页面;
     *async是在下载完成之后,立即异步加载,加载好后立即执行,多个带async属性的标签,不能保证加载的顺序;
     *defer是在下载完成后,立即异步加载。加载好后,如果dom树还没构建好,则先等dom树解析好再执行;如果dom树已经准备好,
     则立即执行。多个带defer属性的标签,按照顺序执行。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • (2)针对css:使用css有三种方式:使用link,@import,内联样式,其中link和@import都是导入外部样式。它们之间的区别:
     *link: 浏览器会派发一个新等线程(http线程)去加载资源文件,于此同时GUI渲染线程会继续向下渲染代码
     *@import: GUI渲染线程会暂时停止渲染,去服务器加载资源文件,资源文件没有返回之前不会继续渲染(阻碍浏览器渲染)
     *style: GUI直接渲染
     外部样式如果长时间没有加载完毕,浏览器为了用户体验,会使用浏览器的默认样式,确保首次渲染的速度。所有css一般写在heard中,让浏览器尽快发送请求去获取css样式。所以,再开发过程中,导入外部样式使用link,而不用@import。如果css少,尽可能采用内嵌样式,直接写在style标签中。
    
    • 1
    • 2
    • 3
    • 4
    • (3)针对DOM树,CSSOM树:可以通过以下几种方式来减少渲染的时间:
    *HTML文件的代码层级尽量不要太深
    *使用语义化的标签,来避免不标准语义化的特殊处理
    *减少CSS代码的层级,因为选择器是从左向右进行解析的
    
    • 1
    • 2
    • 3
    • (4)减少回流与重绘
    *操作DOM树时,尽量在低代码层级的DOM节点进行操作
    *不要使用table布局,一个小的改动可能会使整个table进行重新布局
    *使用css的表达式
    *不要频繁操作元素的样式,对于静态页面,可以修改类名,而不是样式
    *使用absolute或者fixed,使元素脱离文档流,这样他们发生变化就不会影响其他元素
    *避免频繁操作DOM,可以创建一个文档片段docmentFragment,在它上面应用所有DOM操作,最后再把它添加到文档中
    *将元素先设置display:none,操作结束后再把它显示出来。因为display属性为none的元素上进行的DOM操作不会引发回流和重绘。
    *将DOM的多个读操作(或者写操作)放在一起,而不是读写操作穿插着写。这得益于浏览器的渲染队列机智
    
    浏览器针对页面的回流与重绘,进行了自身的优化-----渲染队列
    浏览器会将所有的回流,重绘的操作放在一个队列中,当队列中的操作到了一定的数量或者到了一定的时间间隔,浏览器就会对队列进行批处理。这样就会让多次的回流,重绘变成一次回流重绘。
    将多个读操作(或写操作)放在一起,就会等所有的读操作进入队列之后执行,这样,原本应该是触发多次回流,变成了只触发一次回流。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
  • 相关阅读:
    论文详解 GLENet 增强型3D目标检测网络
    前端使用H5中draggable实现拖拽排序效果
    PHP WebShell 免杀
    Python实操案例五
    同学苹果ios的ipa文件应用企业代签选择签名商看看这篇文章你再去吧
    【slowfast 损失函数改进】深度学习网络通用改进方案:slowfast的损失函数(使用focal loss解决不平衡数据)改进
    2023网络钓鱼状况报告:ChatGPT等工具致网络钓鱼电子邮件数量激增1265%
    【Kafka】ZooKeeper启动失败报错java.net.BindException: Address already in use: bind
    一个基于NetCore开发的前后端分离CMS系统
    LeetCode每日一题——672. 灯泡开关 Ⅱ
  • 原文地址:https://blog.csdn.net/weixin_41166682/article/details/132765137