当前位置:   article > 正文

2022前端面试学习笔记_2022前端面试课程

2022前端面试课程

目录

做了一份前端面试复习计划,保熟~ - 掘金

1、MVVM和MVC的区别

2、JS中的基础类型(6种+2种ES6新增)

3、JS中==和===区别

4、JS中的深拷贝浅拷贝区别

5、原型、构造函数和实例的理解

6、什么是闭包   闭包解决了什么问题  闭包导致了什么问题

7、call、apply、bind实现

8、如何理解JS中的this关键词(3点)

9、跨域问题 (5点+1实际经验)

10、宏任务  微任务

11、!important>style>id>class

12、p和div都是块级元素  区别是什么 (3点)

13、盒子模型

14、清除浮动方式  区别 (4种)

14-1、BFC(创建BFC 3种)

14-2、左侧固定+右侧自适应布局方法(5种)

15、重绘  回流   区别

15-1、防抖  节流

16、vue store 存储 dispatch 和 commit的区别

17、水平垂直居中(5点)

18、flex布局  flex:1;(3点)

19、响应式布局(6点)

20、输入url到页面显示  过程 (6步)

20-1、http状态码

20-2 DNS系统

21、web前端优化策略 (6点)

22、package.json文件作用  内容

23、webpack(裂了)

24、es6(10点)

24-1 var let const  区别(3点)

24-2 使用箭头函数注意点(3点)

24-3 模板字符串

24-4 forEach、for in、for of 区别

25、快速排序

25-1、数组扁平化 

26、get post区别 (5点)

27、cookie优缺点

28、new关键字执行过程(原型链)

29、判断数组类型(4种)

29-1、数组方法

29-1、数组去重

30、babel(没看完)

31、vue组件通讯

32、父子组件生命周期执行顺序

33、v-if 和 v-show 的区别

33-1、display:none、visibility:hidden 和 opacity:0 之间的区别?

34、Vue2.0 响应式数据的原理

35、vue-router 路由钩子函数是什么 执行顺序是什么

36、vue-router 动态路由是什么 有什么问题

36-1、vue-router 组件复用导致路由参数失效怎么办?

37、谈一下对 vuex 的个人理解

38、你都做过哪些 Vue 的性能优化

39、keep-alive 使用场景和原理

Vue.set 方法原理

Vue 修饰符有哪些

鼠标按钮修饰符

键盘修饰符

v-bind修饰符

40、Vue 模板编译原理

41、Vue双向绑定理解

42、首屏加载

43、为什么data属性是一个函数而不是一个对象

44、Vue实例挂载的过程

45、vue.nextTick()

46、mixin  混入

47、Observable

48、diff操作

49、TS

Vue+Vue3.0

50、async  defer

51、Promise.all

52、类数组转数组

53、动画属性

54、DOCTYPE有什么作用?标准模式与混杂模式如何区分?它们有何意义?

55、常见的浏览器内核有哪些?

56、HTML5的文件离线储存怎么使用,工作原理是什么

57、websocket

58、JS继承(6种)

59、watch跟computed区别

60、手写axios

61、小程序

62、IE浏览器兼容问题处理

63、gitlab-ci

64、vue原理题

65、回调地狱怎么处理

66、H5新增

67、块状/内联元素

68、css能继承的属性

69、值类型和引用类型区别

70、class的类型实际是函数、本质是null

71、promise

算法

正则了解

shell了解


做了一份前端面试复习计划,保熟~ - 掘金

1、MVVM和MVC的区别

MVVM,Model-View-ViewModel,即模型-视图-视图模型。

【模型】指后端传递的数据, 【视图】指所看到的的页面。

【视图模型】是MVVM的核心,分为两个方向:1、【模型】->【视图】=》数据绑定 2、【视图】->【模型】=》DOM事件监听。两个方向都实现:双向绑定。总结:【视图】和【模型】之间不能直接通信,需要通过viewModel实现。

MVC,Model-View-controller,即模型-视图-控制器。

MVVM框架:VUE,在vue中:Model指的是js中的数据,比如对象、数组等。View指的是页面视图。viewModel指的是vue实例化对象。

从图中可以看出,当执行 new Vue() 时,Vue 就进入了初始化阶段,一方面Vue 会遍历 data 选项中的属性,并用 Object.defineProperty 将它们转为 getter/setter,实现数据变化监听功能;另一方面,Vue 的指令编译器Compile 对元素节点的指令进行解析,初始化视图,并订阅Watcher 来更新视图, 此时Wather 会将自己添加到消息订阅器中(Dep),初始化完毕。当数据发生变化时,Observer 中的 setter 方法被触发,setter 会立即调用Dep.notify(),Dep 开始遍历所有的订阅者,并调用订阅者的 update 方法,订阅者收到通知后对视图进行相应的更新。因为VUE使用Object.defineProperty方法来做数据绑定,而这个方法又无法通过兼容性处理,所以Vue 不支持 IE8 以及更低版本浏览器。另外,查看vue原代码,发现在vue初始化实例时, 有一个proxy代理方法,它的作用就是遍历data中的属性,把它代理到vm的实例上,这也就是我们可以这样调用属性:vm.aaa等于vm.data.aaa。

50行代码的MVVM,感受闭包的艺术 - 掘金

2、JS中的基础类型(6种+2种ES6新增)

ES5中,6种基础类型:Number,String,Boolan,undefined,Null,Symbol ,BigInt。

ES6中,新增一种Symbol 。这种类型的对象永不相等,即始创建的时候传入相同的值,可以解决属性名冲突的问题,做为标记。新增BigInt 可以表示任意大小的整数。

3、JS中==和===区别

==相同,===严格相同。

4、JS中的深拷贝浅拷贝区别

深拷贝实现方法有两种:

1)JSON.stringify/parse

2)利用递归来实现每一层都重新创建对象并赋值

function deepClone(source){
  const targetObj = source.constructor === Array ? [] : {}; // 判断复制的目标是数组还是对象
  for(let keys in source){ // 遍历目标
    if(source.hasOwnProperty(keys)){
      if(source[keys] && typeof source[keys] === 'object'){ // 如果值是对象,就递归一下
        targetObj[keys] = source[keys].constructor === Array ? [] : {};
        targetObj[keys] = deepClone(source[keys]);
      }else{ // 如果不是,就直接赋值
        targetObj[keys] = source[keys];
      }
    } 
  }
  return targetObj;
}
  1. const deepCopy = function (src) {
  2.     if (src instanceof Array) {
  3.         return src.map(e => deepCopy(e));
  4.     } else if (src instanceof Object) {
  5.         const target = {};
  6.         Object.keys(src).forEach(key => {
  7.             if (src[key] instanceof Date) {
  8.                 target[key= new Date(src[key].getTime());
  9.             } else if (src[key] instanceof Object) {
  10.                 target[key= deepCopy(src[key]);
  11.             } else {
  12.                 target[key= src[key];
  13.             }
  14.         });
  15.         return target;
  16.     }
  17.     return src;
  18. };

5、原型、构造函数和实例的理解

function Person() {

}
// 虽然写在注释里,但是你要注意:
// prototype是函数才会有的属性
Person.prototype.name = 'Kevin';
var person1 = new Person();
var person2 = new Person();
console.log(person1.name) // Kevin
console.log(person2.name) // Kevin

https://github.com/mqyqingfeng/blog/issues/2

6、什么是闭包   闭包解决了什么问题  闭包导致了什么问题

根据MDN中文的定义,闭包的定义如下:

在JavaScript中,每当创建一个函数,闭包就会在函数创建的同时被创建出来。可以在一个内层函数中访问到其外层函数的作用域。

也可以这样说:

闭包是指那些能够访问自由变量的函数。自由变量是指在函数中使用的,但既不是函数参数也不是函数的局部变量的变量。闭包=函数+函数能够访问的自由变量

闭包就是能够读取其他函数内部变量的一个函数。

简单的说闭包是解决了函数内变量暴露给函数外访问。
就是为了解决突破函数作用域的限制才有了闭包这种概念。

闭包可能导致内存泄露,即函数执行完成后内部变量引闭包存在原因还可访问

例:

function print(fn) {

        const a = 200;

         fn();

}

const a = 100;

function fn() {

        console.log(a);

}

print(fn); //100

闭包:自由变量的查找,是在函数定义的地方,向上级作用域查找。不是在执行的地方。

7、call、apply、bind实现

call

call()方法在使用一个指定的this值和若干个指定的参数值的前提下调用某个函数或方法。

var obj = {

        value: "123".

};

function fn() {

        console.log(this.value);

}

fn.call(obj); //123

通过call方法我们做到了以下两点:

1)call改变了this的指向,指向到obj。

2)fn函数执行了。

自己写call方法:

var obj = {

        value: "123",

        fn: function () {

                console.log(this.value);

        },

};

obj.fn(); //123

这时候 this 就指向了 obj ,但是这样做我们手动给 obj 增加了一个 fn 属性,这显然是不行的,不用担心,我们执行完再使用对象属性的删除方法(delete)不就行了

obj.fn = fn;

obj.fn();

delete obj.fn;

根据这个思路,我们可以写出来:

  1. var obj = {
  2.         value"vortesnail",
  3.       };
  4. function fn(t) {
  5.         console.log(this.value);
  6.         console.log(t)
  7.       }
  8.       Function.prototype.myCall = function (context) {
  9.         console.log(111,context);
  10.         var obj2 = {
  11.           value"test"
  12.         }
  13.         // 判断调用对象
  14.         if (typeof this !== "function") {
  15.           throw new Error("Type error");
  16.         }
  17.         // 首先获取参数
  18.         console.log(333,[...arguments]);
  19.         let args = [...arguments].slice(1);
  20.         console.log(222,args);
  21.         let result = null;
  22.         // 判断 context 是否传入,如果没有传就设置为 window
  23.         context = context || window;
  24.         // 将被调用的方法设置为 context 的属性
  25.         // this 即为我们要调用的方法
  26.         console.log(444, this);
  27.         context.fn = this;
  28.         console.log(555, this);
  29.         // 执行要被调用的方法
  30.         result = context.fn(...args);
  31.         // 删除手动增加的属性方法
  32.         delete context.fn;
  33.         // 将执行结果返回
  34.         return result;
  35.       };
  36.       fn.myCall(obj,"test");   
  37.         //  vortesnail  
  38.         // test

call、apply、bind传参格式不同

 

obj.myFun.call(db,'成都','上海');     // 德玛 年龄 99  来自 成都去往上海
obj.myFun.apply(db,['成都','上海']);      // 德玛 年龄 99  来自 成都去往上海  
obj.myFun.bind(db,'成都','上海')();       // 德玛 年龄 99  来自 成都去往上海
obj.myFun.bind(db,['成都','上海'])();   // 德玛 年龄 99  来自 成都, 上海去往 undefined

8、如何理解JS中的this关键词(3点)

  1. this 就是你 call 一个函数时,传入的 context。(结合7刚开始例子理解)
  2. 如果你的函数调用形式不是 call 形式,请按照「转换代码」将其转换为 call 形式(函数的context就是调用函数的对象本身,如果没有对象则是window,结合第1条)。
  3. 箭头函数里面没有 this 的定义。

9、跨域问题 (5点+1实际经验)

所谓同源是指,域名,协议,端口均相同,只要有一个不同,就是跨域。

1)前端方法就用jsonp  只支持get请求  不支持post请求

为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

原理:动态创建一个script标签。利用script标签的src属性不受同源策略限制,因为所有的src属性和href属性都不受同源策略的限制,可以请求第三方服务器资源内容

2)CORS response 添加 header,可以用工具Charles   或者代码里加

  //*表示支持所有网站访问,也可以额外配置相应网站
  resp.setHeader("Access-Control-Allow-Origin", "*");

        使用抓包工具Charles等,修改header,可进行跨域调试。

3)nginx反向代理转发

4)vue项目中proxy代理

5)跨文档通信 API:window.postMessage(‘message内容’,'域名')。 window.addEventListener('message', function(e))监听

// 父窗口打开一个子窗口
var openWindow = window.open('http://test2.com', 'title');
 
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test2.com');

// 监听 message 消息
window.addEventListener('message', function (e) {
  console.log(e.source); // e.source 发送消息的窗口
  console.log(e.origin); // e.origin 消息发向的网址
  console.log(e.data);   // e.data   发送的消息
},false);

6)之前pdf处理过,把插件传到了内网,解决跨域问题

10、宏任务  微任务

  • 宏任务:DOM 渲染后触发,如 setTimeoutsetIntervalDOM 事件script
  • 微任务:DOM 渲染前触发,如 Promise.thenMutationObserver 、Node 环境下的 process.nextTick

微任务在DOM渲染前触发,宏任务在DOM渲染后触发

同步任务->微任务->宏任务

11、!important>style>id>class

!important > 行内 > id选择器 > 属性选择器 = 类选择器 = 伪元素选择器 > 标签选择器 = 伪类选择器(::after)

12、p和div都是块级元素  区别是什么 (3点)

        1、标签不同

        2、p有行间距

        3、页面框架布局使用div,文章内容段落用p

13、盒子模型

CSS3 中的盒模型有以下两种:标准盒模型IE(替代)盒模型

两种盒子模型都是由 content + padding + border + margin 构成,其大小都是由 content + padding + border 决定的,但是盒子内容宽/高度(即 width/height)的计算范围根据盒模型的不同会有所不同:

标准盒模型的宽度:content;

IE(替代)盒模型:content+padding+border;

可以通过 box-sizing 来改变元素的盒模型:

box-sizing: content-box :标准盒模型(默认值)。

box-sizing: border-box :IE(替代)盒模型。

14、清除浮动方式  区别 (4种)

1)添加带clear:both;属性的空元素;

2)容器添加overflow:hidden;通过触发BFC方式,实现清除浮动;

3)容器添加浮动;

4):after伪元素;

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

14-1、BFC(创建BFC 3种)

块级格式上下文,它是 CSS 视觉渲染的一部分,用于决定块级盒的布局及浮动相互影响范围的一个区域。

创建 BFC 的方式:

  • 绝对定位元素(position 为 absolute 或 fixed )。
  • 行内块元素,即 display 为 inline-block (inline-block,table-cell,table-caption,table,fle)。
  • overflow 的值不为 visible (scroll,hidden,auto,inherit)。

14-2、左侧固定+右侧自适应布局方法(5种)

1)左侧宽度固定+float:left;右侧div  width自动填充;

2)左侧宽度固定+float:left;右侧overflow:hidden;触发BFC,不会重叠;

3)flex布局:左侧宽度固定,右侧flex:1;

4)绝对定位:父容器position:relative;左侧固定宽度+position:absolute;右侧margin-left:左侧宽度;

5)绝对定位:父容器position:relative;左侧固定宽度;右侧position:absolute;+left:左侧宽度;

15、重绘  回流   区别

回流这一阶段主要是计算节点的位置和几何信息

最终,我们通过构造渲染树和回流阶段,我们知道了哪些节点是可见的,以及可见节点的样式和具体的几何信息(位置、大小),那么我们就可以将渲染树的每个节点都转换为屏幕上的实际像素,这个阶段就叫做重绘节点。

15-1、防抖  节流

1)防抖

JavaScript 专题之跟着 underscore 学防抖

防抖的原理就是:你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行,总之,就是要等你触发完事件 n 秒内不再触发事件,我才执行,真是任性呐!

1、immediate 是否立即执行一次

2、clearTimeout  若setTimeout未执行,则阻止。timeout不会变空,是执行次数。

  1. function debounce(func, wait, immediate) {
  2. let timeout;
  3. console.log(timeout); //第一次执行这里,后面不执行了
  4. return function () {
  5. console.log(2, timeout); //第二次开始 只执行这里,上面不执行了
  6. let context = this;
  7. let args = arguments;
  8. if (timeout) clearTimeout(timeout);
  9. if (immediate) {
  10. let callNow = !timeout;
  11. //在这里重新开始计时,期间只要触发了就重新开始计时
  12. timeout = setTimeout(function () {
  13. //等到wait过后,把timeout变成null,再次触发debounce时会立即执行func
  14. timeout = null;
  15. }, wait);
  16. if (callNow) func.apply(context, args);
  17. } else {
  18. timeout = setTimeout(function () {
  19. func.apply(context, args);
  20. }, wait);
  21. }
  22. };
  23. }

 2)节流

JavaScript 专题之跟着 underscore 学节流

节流的原理很简单:

如果你持续触发事件,每隔一段时间,只执行一次事件。

关于节流的实现,有两种主流的实现方式,一种是使用时间戳,一种是设置定时器。

  1. function throttle(func, wait) {
  2. var timeout, context, args, result;
  3. var previous = 0;
  4. var later = function() {
  5. previous = +new Date();
  6. timeout = null;
  7. func.apply(context, args)
  8. };
  9. var throttled = function() {
  10. var now = +new Date();
  11. //下次触发 func 剩余的时间
  12. var remaining = wait - (now - previous);
  13. context = this;
  14. args = arguments;
  15. // 如果没有剩余的时间了或者你改了系统时间
  16. if (remaining <= 0 || remaining > wait) {
  17. if (timeout) {
  18. clearTimeout(timeout);
  19. timeout = null;
  20. }
  21. previous = now;
  22. func.apply(context, args);
  23. } else if (!timeout) {
  24. timeout = setTimeout(later, remaining);
  25. }
  26. };
  27. return throttled;
  28. }

16、vue store 存储 dispatch 和 commit的区别

dispatch:含有异步操作。写在action内,action可以直接执行异步。

commit:同步操作。写在mutations内,mutations只能执行同步任务。

17、水平垂直居中(5点)

1)子元素positon:absolute;left:50%;top:50%;transform: translate(-50%, -50%);

2)利用绝对定位,子元素所有方向都为 0 ,将 margin  设置为 auto ,由于宽高固定,对应方向实现平分,该方法必须盒子有宽高

position: absolute; top: 0; left: 0; right: 0; bottom: 0px; margin: auto; height: 100px; width: 100px;

3)利用绝对定位,设置 left: 50% 和 top: 50% 现将子元素左上角移到父元素中心位置,然后再通过 margin-left  和 margin-top  以子元素自己的一半宽高进行负值赋值。该方法必须定宽高

position: absolute; left: 50%; top: 50%; width: 200px; height: 200px; margin-left: -100px; margin-top: -100px;

4)flex:display: flex; justify-content: center; align-items: center;

5)grid布局;

18、flex布局  flex:1;(3点)

  • flex-grow: 1 :该属性默认为 0 ,如果存在剩余空间,元素也不放大。设置为 1  代表会放大。
  • flex-shrink: 1 :该属性默认为 1 ,如果空间不足,元素缩小。
  • flex-basis: 0% :该属性定义在分配多余空间之前,元素占据的主轴空间。浏览器就是根据这个属性来计算是否有多余空间的。默认值为 auto ,即项目本身大小。设置为 0%  之后,因为有 flex-grow  和 flex-shrink  的设置会自动放大或缩小。在做两栏布局时,如果右边的自适应元素 flex-basis  设为 auto  的话,其本身大小将会是 0 。​

19、响应式布局(6点)

1)媒体查询  @media screen and (max-width: 320px)

2)百分比布局

3)rem

4)视口单位  vw,vh,vmin(vw和vh中的较小值),vmax(vw和vh中的较大值)

5)图片响应式:使用max-width(图片自适应)、使用srcset、使用background-image

6)Flex弹性布局、grid网格布局、Columns栅格系统   以及以上结合使用。

20、输入url到页面显示  过程 (6步)

1)域名解析

        输入 URL 后解析出协议、主机、端口、路径等信息,并构造一个 HTTP 请求。

        DNS 域名解析

2)TCP三次握手

        由 TCP 的自身特点可靠传输决定的。客户端和服务端要进行可靠传输,那么就需要确认双方的接收和发送能力。第一次握手可以确认客户端的发送能力,第二次握手,确认了服务端的发送能力和接收能力,所以第三次握手才可以确认客户端的接收能力。不然容易出现丢包的现象。

3)http 请求

4)服务器接收到请求后并返回 HTTP 报文

5)浏览器得到HTTP报文后,开始渲染页面

6)断开TCP链接

20-1、http状态码

1)1XX信息性状态码

2)200成功

3)302重定向  304客户的缓存资源是最新的,要客户使用缓存

4)400发送了错误请求  401没权限  404找不到资源

5)500服务器内部错误 502网关故障 504网关超时

20-2 DNS系统

        DNS 即域名系统,全称是 Domain Name System。当我们在浏览器输入一个 URL 地址时,浏览器要向这个 URL 的主机名对应的服务器发送请求,就得知道服务器的 IP,对于浏览器来说,DNS 的作用就是将主机名转换成 IP 地址

21、web前端优化策略 (6点)

1)减少http请求

2)减少DNS查找

3)CSS放顶部,JS放最底

4)JS、CSS、图片、第三方库 cdn 引入

5)图片压缩

6)webpack:terser-webpack-plugin压缩 JS 代码

                        css-minimizer-webpack-plugin压缩 CSS 代码

                        html-webpack-plugin压缩 HTML 代码

                        compression-webpack-plugin开启gzip压缩

22、package.json文件作用  内容

package.json 文件其实就是对项目或者模块包的描述,里面包含许多元信息。比如项目名称,项目版本,项目执行入口文件,项目贡献者等等。npm install 命令会根据这个文件下载所有依赖模块。

npm init  可自动创建,也可手动创建

23、webpack(裂了)

1、webpack作用

        1)模块打包

        2)变异兼容

        3)能力扩展(按需加载、代码压缩等)

24、es6(10点)

        1)let、const  块级作用域

        2)箭头函数

        3)import  export

        4)Set结构  类似数组  数据唯一  没有重复值

        5)Map结构  类似数组  数据是键值对

        6)...展开运算符

        7)async、await
  使用 async/await, 搭配promise,可以通过编写形似同步的代码来处理异步流程, 提高代码的简洁性和可读性
  async 用于申明一个 function 是异步的,而 await 用于等待一个异步方法执行完成

        8)Promise  异步编程

        9)Symbol

        10)解构赋值

        11)for  of结构

        let arr = [11,22,33,44,55];
        let sum = 0;
        for(value of arr){
            sum += value;
        }

24-1 var let const  区别(3点)

        1)var是全局,let、const是块级作用域

        2)var可以在声明的上面访问变量

        3)const声明之后必须赋值,不可改变

24-2 使用箭头函数注意点(3点)

        1)箭头函数里面没有 this 对象,

              此时的 this 是外层的 this 对象,即 Window

        2)没有argument对象

        3)不能用作构造函数,所以代表着不能使用new命令

24-3 模板字符串

        基本的字符串格式化。将表达式嵌入字符串中进行拼接。用${}来界定

24-4 forEach、for in、for of 区别

        1)forEach  专门遍历数组   

                数组遍历:arr.forEach((item, index) => { arr[index] == item })

                对象遍历:Object.keys(obj).forEach(key = > { obj[key] })

        2)for in 一般循环对象或json  循环出的key

        3)for of  对象数组都可,循环出value

  • forEach 和 map 的区别;
    • map 不写 return,默认返回 undefined,返回一个数组长度的 undefined 的数组;
    • forEach 中断循环
      • 用数组的方法,return false;
      • 数组的 api,使用 some 或者 every 实现
      • 使用 for 循环或者 for in 代替
      • 使用 throw 抛出异常
  • 遍历对象的方式
    • for in:主要用来遍历对象(for keys in obj)
      • 遍历自身和继承的可枚举属性(延续原型链遍历出对象的原型属性)
      • 有什么问题:要使用 hasOwnProperty 判断,只处理自身的,不处理继承的
    • for of: ES6 新增的,遍历所有数据结构的统一的方法
      • 只要部署了 Symbol.iterator 属性,就被视为具有 iterator 接口,就可以用 for…of 循环遍历它的成员
      • 包括数组、Set 和 Map 结构、某些类似数组的对象(比如 arguments 对象、DOM NodeList 对象)、Generator 对象,以及字符串
    • Object.keys:返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)
    • Object.getOwnPropertyNames(obj):返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)
    • Object.getOwnPropertySymbols()
    • Reflect.ownKeys(obj)遍历:返回一个数组,包含对象自身的所有属性,不管属性名是 Symbol 或字符串,也不管是否可枚举

25、快速排序

  1. function sortArray(nums) {
  2. quickSort(0, nums.length - 1, nums);
  3. return nums;
  4. }
  5. function quickSort(start, end, arr) {
  6. if (start < end) {
  7. const mid = sort(start, end, arr);
  8. quickSort(start, mid - 1, arr);
  9. quickSort(mid + 1, end, arr);
  10. }
  11. }
  12. function sort(start, end, arr) {
  13. const base = arr[start];
  14. let left = start;
  15. let right = end;
  16. while (left !== right) {
  17. while (arr[right] >= base && right > left) {
  18. right--;
  19. }
  20. arr[left] = arr[right];
  21. while (arr[left] <= base && right > left) {
  22. left++;
  23. }
  24. arr[right] = arr[left];
  25. }
  26. arr[left] = base;
  27. return left;
  28. }

25-1、数组扁平化 

1).flat()方法  arr.flat(Infinity);

  1. Array.prototype.flat = function() {
  2. return this.toString() //"1,2,3,4"
  3. .split(",") //["1", "2", "3", "4"]
  4. .map(item => +item);//[1, 2, 3, 4]
  5. };
  6. console.log([1,[2,[3,4]]].flat())//[1, 2, 3, 4]

2)...扩展运算符+.concat()连接

  1. function flat(arr, depth = 1) {
  2. if (depth > 0) {
  3. // 以下代码还可以简化,不过为了可读性,还是....
  4. return arr.reduce((pre, cur) => {
  5. return pre.concat(Array.isArray(cur) ? flat(cur, depth - 1) : cur);
  6. }, []);
  7. }
  8. return arr.slice();
  9. }

 arr.reduce(func)        累加器

26、get post区别 (5点)

  • 缓存的角度,GET 请求会被浏览器主动缓存下来,留下历史记录,而 POST 默认不会。
  • 编码的角度,GET 只能进行 URL 编码,只能接收 ASCII 字符,而 POST 没有限制。
  • 参数的角度,GET 一般放在 URL 中,因此不安全,POST 放在请求体中,更适合传输敏感信息。
  • 幂等性的角度,GET 是幂等的,而 POST 不是。(幂等表示执行相同的操作,结果也是相同的)
  • TCP 的角度,GET 请求会把请求报文一次性发出去,而 POST 会分为两个 TCP 数据包,首先发 header 部分,如果服务器响应 100(continue), 然后发 body 部分。(火狐浏览器除外,它的 POST 请求只发一个 TCP 包)

上面所说的post会比get多一个tcp包其实不太严谨。多发的那个expect 100 continue header报文,是由客户端对httppostget的请求策略决定的,目的是为了避免浪费资源,如带宽,数据传输消耗的时间等等。所以客户端会在发送header的时候添加expect 100去探探路,如果失败了就不用继续发送data,从而减少了资源的浪费。所以是否再发送一个包取决于客户端的实现策略,和get/post并没什么关系。有的客户端比如fireFox就只发送一个包。

27、cookie优缺点

缺点

        1)浏览器cookie个数限制   IE6 20个,IE7、fireFox  50个,chrome、safari无限制

        2)cookie大小4M

        3)安全性不够

        4)每次随http请求发送,造成不必要负担

优点

        1)数据持久

        2)简单易控

28、new关键字执行过程(原型链)

1)首先创建一个空对象。

2)根据原型链,设置空对象的_proto_为构造函数的prototype。

3)构造函数的this指向了这个对象,并执行了构造函数代码。

4)判断函数的返回值类型,如果是引用类型,就返回这个引用类型的对象。

29、判断数组类型(4种)

1)Array.isArray(arr); // true

2)arr.__proto__ === Array.prototype; // true

3)arr instanceof Array; // true

4)Object.prototype.toString.call(arr); // "[object Array]"

29-1、数组方法

会改变原来数组的:
pop()—删除数组的最后一个元素并返回删除的元素。
push()—向数组的末尾添加一个或更多元素,并返回新的长度。
shift()—删除并返回数组的第一个元素。
unshift()—向数组的开头添加一个或更多元素,并返回新的长度。
reverse()—反转数组的元素顺序。
sort()—对数组的元素进行排序。
splice()—用于插入、删除或替换数组的元素。 返回的是含有被删除的数组
································································································
不会改变原来数组的:
concat()—连接两个或更多的数组,并返回结果。
every()—检测数组元素的每个元素是否都符合条件。
some()—检测数组元素中是否有元素符合指定条件。
filter()—检测数组元素,并返回符合条件所有元素的数组。
indexOf()—搜索数组中的元素,并返回它所在的位置。
join()—把数组的所有元素放入一个字符串。
toString()—把数组转换为字符串,并返回结果。
lastIndexOf()—返回一个指定的字符串值最后出现的位置,在一个字符串中的指定位置从后向前搜索。
map()—通过指定函数处理数组的每个元素,并返回处理后的数组。
slice()—选取数组的的一部分,并返回一个新数组。
valueOf()—返回数组对象的原始值。

29-1、数组去重

1)ES6 Set去重

  1. let arr = [1,0,0,2,9,8,3,1];
  2. function unique(arr) {
  3. return Array.from(new Set(arr))
  4. }
  5. console.log(unique(arr)); // [1,0,2,9,8,3]  
  6. or
  7.      console.log(...new Set(arr)); // [1,0,2,9,8,3]

 2)双重for循环,再利用数组的splice方法去重  ES5常用

  1. var arr = [1, 5, 6, 0, 7, 3, 0, 5, 9,5,5];
  2. function unique(arr) {
  3. for (var i = 0, len = arr.length; i < len; i++) {
  4. for (var j = i + 1, len = arr.length; j < len; j++) {
  5. if (arr[i] === arr[j]) {
  6. arr.splice(j, 1);
  7. j--; // 每删除一个数j的值就减1
  8. }
  9. } return arr;
  10. }
  11. console.log(unique(arr)); // 1, 5, 6, 0, 7, 3, 9

3)利用数组的sort排序方法去重(相邻元素对比法)

  1. var arr = [5,7,1,8,1,8,3,4,9,7];
  2. function unique( arr ){
  3. arr = arr.sort();
  4. console.log(arr);
  5. var arr1 = [arr[0]];
  6. for(var i=1,len=arr.length;i<len;i++){
  7. if(arr[i] !== arr[i-1]){
  8. arr1.push(arr[i]);
  9. }
  10. }
  11. return arr1;
  12. }
  13. console.log(unique(arr))l; // 1, 1, 3, 4, 5, 7, 7, 8, 8, 9

4)利用数组的filter方法去重 

  1. var arr = [1,2,8,9,5,8,4,0,4];
  2. /*
  3. 模拟: 原始数组:[1,2,8,9,5,8,4,0,4]
  4. 索引值:0,1,2,3,4,5,6,7,8
  5. 伪新数组:[1,2,8,9,5,8,4,0,4]
  6. 使用indexOf方法找到数组中的元素在元素在中第一次出现的索引值
  7. 索引值:0,1,2,3,4,2,6,7,6
  8. 返回前后索引值相同的元素:
  9. 新数组:[1,2,8,9,5,4,0]
  10. */
  11. function unique( arr ){
  12. // 如果新数组的当前元素的索引值 == 该元素在原始数组中的第一个索引,则返回当前元素
  13. return arr.filter(function(item,index){
  14. return arr.indexOf(item,0) === index;
  15. });
  16. }
  17. console.log(unique(arr)); // 1, 2, 8, 9, 5, 4, 0

30、babel(没看完)

不容错过的 Babel7 知识 - 掘金

前端工程师需要了解的 Babel 知识 - 政采云前端团队

31、vue组件通讯

1)props  $emit

2)$refs

3)Vuex

4)$parents   $children

5)provide  inject

6)$attrs 和$listeners A->B->C。Vue 2.4 开始提供了$attrs 和$listeners 来解决这个问题

7)eventBus 兄弟组件数据传递 这种情况下可以使用事件总线的方式

32、父子组件生命周期执行顺序

1)加载渲染过程

父 beforeCreate->父 created->父 beforeMount->子 beforeCreate->子 created->子 beforeMount->子 mounted->父 mounted

2)子组件更新过程

父 beforeUpdate->子 beforeUpdate->子 updated->父 updated

3)父组件更新过程

父 beforeUpdate->父 updated

4)销毁过程

父 beforeDestroy->子 beforeDestroy->子 destroyed->父 destroyed

33、v-if 和 v-show 的区别

v-if 在编译过程中会被转化成三元表达式,条件不满足时不渲染此节点。

v-show 会被编译成指令,条件不满足时控制样式将对应节点隐藏 (display:none)

使用场景

v-if 适用于在运行时很少改变条件,不需要频繁切换条件的场景

v-show 适用于需要非常频繁切换条件的场景

33-1、display:none、visibility:hidden 和 opacity:0 之间的区别?

34、Vue2.0 响应式数据的原理

整体思路是数据劫持+观察者模式

对象内部通过 defineReactive 方法,使用 Object.defineProperty 将属性进行劫持(只会劫持已经存在的属性),数组则是通过重写数组方法来实现。当页面使用对应属性时,每个属性都拥有自己的 dep 属性,存放他所依赖的 watcher(依赖收集),当属性变化后会通知自己对应的 watcher 去更新(派发更新)。

相关代码如下

  1. class Observer {
  2. // 观测值
  3. constructor(value) {
  4. this.walk(value);
  5. }
  6. walk(data) {
  7. // 对象上的所有属性依次进行观测
  8. let keys = Object.keys(data);
  9. for (let i = 0; i < keys.length; i++) {
  10. let key = keys[i];
  11. let value = data[key];
  12. defineReactive(data, key, value);
  13. }
  14. }
  15. }
  16. // Object.defineProperty数据劫持核心 兼容性在ie9以及以上
  17. function defineReactive(data, key, value) {
  18. observe(value); // 递归关键
  19. // --如果value还是一个对象会继续走一遍odefineReactive 层层遍历一直到value不是对象才停止
  20. // 思考?如果Vue数据嵌套层级过深 >>性能会受影响
  21. Object.defineProperty(data, key, {
  22. get() {
  23. console.log("获取值");
  24. //需要做依赖收集过程 这里代码没写出来
  25. return value;
  26. },
  27. set(newValue) {
  28. if (newValue === value) return;
  29. console.log("设置值");
  30. //需要做派发更新过程 这里代码没写出来
  31. value = newValue;
  32. },
  33. });
  34. }
  35. export function observe(value) {
  36. // 如果传过来的是对象或者数组 进行属性劫持
  37. if (
  38. Object.prototype.toString.call(value) === "[object Object]" ||
  39. Array.isArray(value)
  40. ) {
  41. return new Observer(value);
  42. }
  43. }

35、vue-router 路由钩子函数是什么 执行顺序是什么

路由钩子的执行流程, 钩子函数种类有:全局守卫、路由守卫、组件守卫

完整的导航解析流程:

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter。
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter。
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。

36、vue-router 动态路由是什么 有什么问题

动态路由就是有动态变量的,例:

  1. const User = {
  2. template: "<div>User</div>",
  3. };
  4. const router = new VueRouter({
  5. routes: [
  6. // 动态路径参数 以冒号开头
  7. { path: "/user/:id", component: User },
  8. ],
  9. });

36-1、vue-router 组件复用导致路由参数失效怎么办?

1.通过 watch 监听路由参数再发请求

  1. watch: { //通过watch来监听路由变化
  2. "$route": function(){
  3. this.getData(this.$route.params.xxx);
  4. }
  5. }

2.用 :key 来阻止“复用”

<router-view :key="$route.fullPath" />

37、谈一下对 vuex 的个人理解

主要包括以下几个模块:

  • State:定义了应用状态的数据结构,可以在这里设置默认的初始状态。
  • Getter:允许组件从 Store 中获取数据,mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性。
  • Mutation:是唯一更改 store 中状态的方法,且必须是同步函数。
  • Action:用于提交 mutation,而不是直接变更状态,可以包含任意异步操作。
  • Module:允许将单一的 Store 拆分为多个 store 且同时保存在单一的状态树中。

38、你都做过哪些 Vue 的性能优化

  • 图片懒加载
  • 路由懒加载
  • 第三方插件的按需引入
  • 防抖、节流运用
  • 对象层级不要过深,否则性能就会差
  • 不需要响应式的数据不要放到 data 中(可以用 Object.freeze() 冻结数据)
  • v-if 和 v-show 区分使用场景
  • computed 和 watch 区分使用场景
  • v-for 遍历必须加 key,key 最好是 id 值,且避免同时使用 v-if
  • 大数据列表和表格性能优化-虚拟列表/虚拟表格
  • 防止内部泄漏,组件销毁后把全局变量和事件销毁
  • 适当采用 keep-alive 缓存组件
  • 服务端渲染 SSR or 预渲染

39、keep-alive 使用场景和原理

keep-alive 是 Vue 内置的一个组件,可以实现组件缓存,当组件切换时不会对当前组件进行卸载。

  • 常用的两个属性 include/exclude,允许组件有条件的进行缓存。

  • 两个生命周期 activated/deactivated,用来得知当前组件是否处于活跃状态。

  • keep-alive 的中还运用了 LRU(最近最少使用) 算法,选择最近最久未使用的组件予以淘汰。

Vue.set 方法原理

了解 Vue 响应式原理的同学都知道在两种情况下修改数据 Vue 是不会触发视图更新的

1.在实例创建之后添加新的属性到实例上(给响应式对象新增属性)

2.直接更改数组下标来修改数组的值

Vue 修饰符有哪些

  • 表单修饰符

        lazy

        在我们填完信息,光标离开标签的时候,才会将值赋予给value,也就是在change事件之后再进行信息同步

        trim

        number

  • 事件修饰符

        stop        阻止了事件冒泡,相当于调用了event.stopPropagation方法

        prevent        阻止了事件的默认行为,相当于调用了event.preventDefault方法

        self        只当在 event.target 是当前元素自身时触发处理函数,阻止事件冒泡

        once        绑定了事件以后只能触发一次,第二次就不会触发

        capture        使事件触发从包含这个元素的顶层开始往下触发

        passive

        在移动端,当我们在监听元素滚动事件的时候,会一直触发onscroll事件会让我们的网页变卡,因此我们使用这个修饰符的时候,相当于给onscroll事件整了一个.lazy修饰符

        native        让组件变成像html内置标签那样监听根元素的原生事件,否则组件上使用 v-on 只会监听自定义事件

  • 鼠标按钮修饰符

        left 左键点击

        right 右键点击

        middle 中键点击

  • 键盘修饰符

键盘修饰符是用来修饰键盘事件(onkeyuponkeydown)的,有如下:

keyCode存在很多,但vue为我们提供了别名,分为以下两种:

  • 普通键(enter、tab、delete、space、esc、up...)

  • 系统修饰键(ctrl、alt、meta、shift...)

<input type="text" @keyup.keyCode="shout()">

  • v-bind修饰符

async        能对props进行一个双向绑定

prop        设置自定义标签属性,避免暴露数据,防止污染HTML结构

camel        将命名变为驼峰命名法,如将view-Box属性名转换为 viewBox

40、Vue 模板编译原理

Vue 的编译过程就是将 template 转化为 render 函数的过程 分为以下三步

第一步是将 模板字符串 转换成 element ASTs(解析器)
第二步是对 AST 进行静态节点标记,主要用来做虚拟DOM的渲染优化(优化器)
第三步是 使用 element ASTs 生成 render 函数代码字符串(代码生成器)

41、Vue双向绑定理解

1)联系MVVM框架,ViewModel的作用:

数据变化后更新视图,视图变化后更新数据。

2)ViewModel由两部分组成

监视器(observer):对所有数据属性进行监听;

解析器(compiler):对每个元素节点的指令进行扫描跟解析,根据指令模板替换数据,以及绑定相应的更新函数

3)Vue为例,Vue双向绑定流程

        1、new Vue()执行初始化,对data进行响应化处理,发生在observer中

        2、同时对模板进行编译(AST),找到其中动态绑定的数据,从data中获取并初始化视图,这个过程发生在compiler中。

        3、同时定义一个更新函数和watcher,将来对应数据变化时,触发watcher调用更新函数。

        4、由于data的某个key在⼀个视图中可能出现多次,所以每个key都需要⼀个管家Dep来管理多个Watcher。

   5、将来data中数据⼀旦发生变化,会首先找到对应的Dep,通知所有Watcher执行更新函数

42、首屏加载

首屏时间(First Contentful Paint),指的是浏览器从响应用户输入网址地址,到首屏内容渲染完成的时间,此时整个网页不一定要全部渲染完成,但需要展示当前视窗需要的内容

1)加载慢的原因

  • 网络延时问题

  • 资源文件体积是否过大

  • 资源是否重复发送请求去加载了

  • 加载脚本的时候,渲染内容堵塞了

2)解决方案

  • 减小入口文件体积

  • 静态资源本地缓存

  • UI框架按需加载

  • 图片资源的压缩

  • 组件重复打包

  • 开启GZip压缩

  • 使用SSR

43、为什么data属性是一个函数而不是一个对象

组件必须用data(),因为使用data:{},会导致重复使用组件是,内存地址重复,公用同一个内存地址。函数时不会出现该问题。

44、Vue实例挂载的过程

  • vue构造函数 -> 调用多个init方法(定义 _init,定义$set、$get、$delete、$watch等,定义事件 $on、$once、$off、$emit,定义_update,定义_render返回虚拟dom)
  • beforeCreate阶段,不能访问data,methods,props,computed,watch
  • create阶段,可以访问data,methods,props,computed,watch,访问不到dom
  • mounted阶段,挂载完毕,数据双向绑定,可以访问到dom
  • 调用$mount进行页面的挂载

  • 挂载的时候主要是通过mountComponent方法

  • 定义updateComponent更新函数

  • 执行render生成虚拟DOM

  • _update将虚拟DOM生成真实DOM结构,并且渲染到页面中

45、vue.nextTick()

用于获取数据变化后,最新的dom。

46、mixin  混入

47、Observable

在非父子组件通信时,可以使用通常的bus或者使用vuex,但是实现的功能不是太复杂,而使用上面两个又有点繁琐。这时,observable就是一个很好的选择

创建一个js文件

  1. // 引入vue
  2. import Vue from 'vue
  3. // 创建state对象,使用observable让state对象可响应
  4. export let state = Vue.observable({
  5. name: '张三',
  6. 'age': 38
  7. })
  8. // 创建对应的方法
  9. export let mutations = {
  10. changeName(name) {
  11. state.name = name
  12. },
  13. setAge(age) {
  14. state.age = age
  15. }
  16. }

 在.vue文件中直接使用即可

  1. <template>
  2. <div>
  3. 姓名:{{ name }}
  4. 年龄:{{ age }}
  5. <button @click="changeName('李四')">改变姓名</button>
  6. <button @click="setAge(18)">改变年龄</button>
  7. </div>
  8. </template>
  9. import { state, mutations } from '@/store
  10. export default {
  11. // 在计算属性中拿到值
  12. computed: {
  13. name() {
  14. return state.name
  15. },
  16. age() {
  17. return state.age
  18. }
  19. },
  20. // 调用mutations里面的方法,更新数据
  21. methods: {
  22. changeName: mutations.changeName,
  23. setAge: mutations.setAge
  24. }
  25. }

48、diff操作

diff 算法是一种通过同层的树节点进行比较的高效算法。

v-for加key,key 是为 Vue 中 vnode 的唯一标记,通过这个 key,我们的 diff 操作可以更准确、更快速。

49、TS

课程指南 | Vue3+TS 快速上手

1)interface 接口  属性?:表示可有可无   readonly  只读

2)implements  类实现接口。extends  接口继承接口  类继承类

3)派生类  super.父方法  public、private(私有)、protected(派生类中可以访问)

        存取器   get/set 属性

4)static修饰的为静态属性/方法。不能用this.xxx使用。类名.静态属性/方法调用和赋值。构造函数不能用static修饰。

5)abstract  抽象类/方法。

6)函数,函数类型固定,返回值固定。函数声明时,可选参数:参数?表示可传可不传;参数也可以给默认值。剩余参数:...参数名。

7)泛型,any 表示不预先指定具体类型。函数泛型:函数名<T, K>。泛型类,泛型接口,泛型约束。

Vue+Vue3.0

1)setup: 组合API的入口函数;ref: 定义一个数据的响应式,ref对象.value,对象是ref类型; reactive: 多个数据的响应式,对象是Proxy类型;  总结:想操作数据影响界面更新,需改动ref对象或reactive对象(代理对象),目标对象数据也会随之变化。

2)vue为解决1、对象新增或删除属性时,界面不更新2.通过数组下边替换元素或更新长度,界面不更新问题,用vue.set解决;vue3  响应式原理核心:proxy(代理)。proxy(target, handler)。target 目标对象。handler  处理器对象  监视数据变化,其中有 get() set()  delete()等13种方法。reflect(反射): 动态对被代理对象的相应属性进行特定的操作。

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <title>Proxy 与 Reflect</title>
  7. </head>
  8. <body>
  9. <script>
  10. const user = {
  11. name: "John",
  12. age: 12
  13. };
  14. /*
  15. proxyUser是代理对象, user是被代理对象
  16. 后面所有的操作都是通过代理对象来操作被代理对象内部属性
  17. */
  18. const proxyUser = new Proxy(user, {
  19. get(target, prop) {
  20. console.log('劫持get()', prop)
  21. return Reflect.get(target, prop)
  22. },
  23. set(target, prop, val) {
  24. console.log('劫持set()', prop, val)
  25. return Reflect.set(target, prop, val); // (2)
  26. },
  27. deleteProperty (target, prop) {
  28. console.log('劫持delete属性', prop)
  29. return Reflect.deleteProperty(target, prop)
  30. }
  31. });
  32. // 读取属性值
  33. console.log(proxyUser===user)
  34. console.log(proxyUser.name, proxyUser.age)
  35. // 设置属性值
  36. proxyUser.name = 'bob'
  37. proxyUser.age = 13
  38. console.log(user)
  39. // 添加属性
  40. proxyUser.sex = '男'
  41. console.log(user)
  42. // 删除属性
  43. delete proxyUser.sex
  44. console.log(user)
  45. </script>
  46. </body>
  47. </html>

3)setup细节:

        1、setup在beforeCreate之前执行,组件对象还没被创建,也就意味着组件实例对象this不能用。 

        2、setup(props, context)

                props参数,是一个对象,里面有父向子传的数据。

                context里有三个属性{attrs, emit, slots}

                attrs对象:获取当前子组件标签上的所有属性,但是该属性是没在props声明接受的对象,相当于this.$attrs。

                emit:用来分发自定义事件的函数,相当于this.$emit。

4)reactive和ref细节

        1、ref用来处理基本类型,如果ref一个对象或者数组,内部自动转换为reactive代理对象。

        2、reactive用来处理对象(递归深度响应式)。

        3、ref内部: 通过给value属性添加getter/setter来实现对数据的劫持

        4、reactive内部: 通过使用Proxy来实现对对象内部所有数据的劫持, 并通过Reflect操作对象内部数据

        5、ref的数据操作: 在js中要.value, 在模板中不需要(内部解析模板时会自动添加.value)

5)computed和watch   写法看代码

        1、computed里有get()和set()

        2、watch两个特性,immediate立即执行,deep深度监视。

        3、watch监视非响应式数据,要用回调写法。

        4、watchEffect  监听所有数据,所以不用指定监视对象。默认初始就会执行一次。

  1. <template>
  2. <h2>App</h2>
  3. fistName: <input v-model="user.firstName"/><br>
  4. lastName: <input v-model="user.lastName"/><br>
  5. fullName1: <input v-model="fullName1"/><br>
  6. fullName2: <input v-model="fullName2"><br>
  7. fullName3: <input v-model="fullName3"><br>
  8. </template>
  9. <script lang="ts">
  10. /*
  11. 计算属性与监视
  12. 1. computed函数:
  13. 与computed配置功能一致
  14. 只有getter
  15. 有getter和setter
  16. 2. watch函数
  17. 与watch配置功能一致
  18. 监视指定的一个或多个响应式数据, 一旦数据变化, 就自动执行监视回调
  19. 默认初始时不执行回调, 但可以通过配置immediate为true, 来指定初始时立即执行第一次
  20. 通过配置deep为true, 来指定深度监视
  21. 3. watchEffect函数
  22. 不用直接指定要监视的数据, 回调函数中使用的哪些响应式数据就监视哪些响应式数据
  23. 默认初始时就会执行第一次, 从而可以收集需要监视的数据
  24. 监视数据发生变化时回调
  25. */
  26. import {
  27. reactive,
  28. ref,
  29. computed,
  30. watch,
  31. watchEffect
  32. } from 'vue'
  33. export default {
  34. setup () {
  35. const user = reactive({
  36. firstName: 'A',
  37. lastName: 'B'
  38. })
  39. // 只有getter的计算属性
  40. const fullName1 = computed(() => {
  41. console.log('fullName1')
  42. return user.firstName + '-' + user.lastName
  43. })
  44. // 有getter与setter的计算属性
  45. const fullName2 = computed({
  46. get () {
  47. console.log('fullName2 get')
  48. return user.firstName + '-' + user.lastName
  49. },
  50. set (value: string) {
  51. console.log('fullName2 set')
  52. const names = value.split('-')
  53. user.firstName = names[0]
  54. user.lastName = names[1]
  55. }
  56. })
  57. const fullName3 = ref('')
  58. /*
  59. watchEffect: 监视所有回调中使用的数据
  60. */
  61. /*
  62. watchEffect(() => {
  63. console.log('watchEffect')
  64. fullName3.value = user.firstName + '-' + user.lastName
  65. })
  66. */
  67. /*
  68. 使用watch的2个特性:
  69. 深度监视
  70. 初始化立即执行
  71. */
  72. watch(user, () => {
  73. fullName3.value = user.firstName + '-' + user.lastName
  74. }, {
  75. immediate: true, // 是否初始化立即执行一次, 默认是false
  76. deep: true, // 是否是深度监视, 默认是false
  77. })
  78. /*
  79. watch一个数据
  80. 默认在数据发生改变时执行回调
  81. */
  82. watch(fullName3, (value) => {
  83. console.log('watch')
  84. const names = value.split('-')
  85. user.firstName = names[0]
  86. user.lastName = names[1]
  87. })
  88. /*
  89. watch多个数据:
  90. 使用数组来指定
  91. 如果是ref对象, 直接指定
  92. 如果是reactive对象中的属性, 必须通过函数来指定
  93. */
  94. watch([() => user.firstName, () => user.lastName, fullName3], (values) => {
  95. console.log('监视多个数据', values)
  96. })
  97. return {
  98. user,
  99. fullName1,
  100. fullName2,
  101. fullName3
  102. }
  103. }
  104. }
  105. </script>

6)与 2.x 版本生命周期相对应的组合式 API

        1、beforeCreate -> 使用 setup()

        2、created -> 使用 setup()

        3、beforeMount -> onBeforeMount(() => {})

        4、mounted -> onMounted(() => {})

        5、beforeUpdate -> onBeforeUpdate(() => {})

        6、updated -> onUpdated(() => {})

        7、beforeDestroy -> onBeforeUnmount(() => {})

        8、destroyed -> onUnmounted(() => {})

        9、errorCaptured -> onErrorCaptured(() => {})

        6-1)3.0对应生命周期钩子比2.x钩子快。

        6-2)新增两个钩子。

                onRenderTracked  状态跟踪:跟踪页面上所有响应式变量和方法的状态。        

  1. onRenderTracked((event) => {
  2. console.log("状态跟踪组件----------->");
  3. console.log(event);
  4. });

                onRenderTriggerd  状态触发。给你变化值的信息,并且新值和旧值都会展示。

  1. onRenderTriggered((event) => {
  2. console.log("状态触发组件--------------->");
  3. console.log(event);
  4. });
  5. 对 event 对象属性的详细介绍:
  6. - key 那边变量发生了变化
  7. - newValue 更新后变量的值
  8. - oldValue 更新前变量的值
  9. - target 目前页面中的响应变量和函数

 7)自定义hook函数,类似vue2.x的mixin用法:封装ajax请求。

hooks/useRequest.ts

  1. import { ref } from 'vue'
  2. import axios from 'axios'
  3. /*
  4. 使用axios发送异步ajax请求
  5. */
  6. export default function useUrlLoader<T>(url: string) {
  7. const result = ref<T | null>(null)
  8. const loading = ref(true)
  9. const errorMsg = ref(null)
  10. axios.get(url)
  11. .then(response => {
  12. loading.value = false
  13. result.value = response.data
  14. })
  15. .catch(e => {
  16. loading.value = false
  17. errorMsg.value = e.message || '未知错误'
  18. })
  19. return {
  20. loading,
  21. result,
  22. errorMsg,
  23. }
  24. }
  1. <template>
  2. <div class="about">
  3. <h2 v-if="loading">LOADING...</h2>
  4. <h2 v-else-if="errorMsg">{{errorMsg}}</h2>
  5. <!-- <ul v-else>
  6. <li>id: {{result.id}}</li>
  7. <li>name: {{result.name}}</li>
  8. <li>distance: {{result.distance}}</li>
  9. </ul> -->
  10. <ul v-for="p in result" :key="p.id">
  11. <li>id: {{p.id}}</li>
  12. <li>title: {{p.title}}</li>
  13. <li>price: {{p.price}}</li>
  14. </ul>
  15. <!-- <img v-if="result" :src="result[0].url" alt=""> -->
  16. </div>
  17. </template>
  18. <script lang="ts">
  19. import {
  20. watch
  21. } from "vue"
  22. import useRequest from './hooks/useRequest'
  23. // 地址数据接口
  24. interface AddressResult {
  25. id: number;
  26. name: string;
  27. distance: string;
  28. }
  29. // 产品数据接口
  30. interface ProductResult {
  31. id: string;
  32. title: string;
  33. price: number;
  34. }
  35. export default {
  36. setup() {
  37. // const {loading, result, errorMsg} = useRequest<AddressResult>('/data/address.json')
  38. const {loading, result, errorMsg} = useRequest<ProductResult[]>('/data/products.json')
  39. watch(result, () => {
  40. if (result.value) {
  41. console.log(result.value.length) // 有提示
  42. }
  43. })
  44. return {
  45. loading,
  46. result,
  47. errorMsg
  48. }
  49. }
  50. }
  51. </script>

8)toRefs可以把reactive包裹的数据变成普通的对象的ref对象。(注意:ref对象js里调用要加.value

9)其他API  

        1、shallowReactive  shallowRef  浅响应式(区别于reactive  ref  深度响应式)。

        shallowReactive : 只处理了对象内最外层属性的响应式(也就是浅响应式)

        shallowRef: 只处理了value的响应式, 不进行对象的reactive处理

        2、readOnly(深只读)  shallowReadOnly (浅只读,深层对象可以修改)

        3、toRaw  markRaw

                toRaw

                        由响应式代理对象变为非响应式的普通对象,并返回

                markRaw

                        标记一个对象,使其永远不会转换为代理。返回非响应式的普通对象本身

        4、toRef(据说很有用)

                1)为源响应式对象上的某个属性创建一个 ref对象,二者内部操作的是同一个数据值, 更新时二者是同步的

                2)区别ref: 拷贝了一份新的数据值单独操作, 更新时相互不影响

        5、customRef 自定义ref

        有track跟trigger回调  对应 get()根set()   下面例子里有

  1. <template>
  2. <h2>App</h2>
  3. <input v-model="keyword" placeholder="搜索关键字"/>
  4. <p>{{keyword}}</p>
  5. </template>
  6. <script lang="ts">
  7. /*
  8. customRef:
  9. 创建一个自定义的 ref,并对其依赖项跟踪和更新触发进行显式控制
  10. 需求:
  11. 使用 customRef 实现 debounce 的示例
  12. */
  13. import {
  14. ref,
  15. customRef
  16. } from 'vue'
  17. export default {
  18. setup () {
  19. const keyword = useDebouncedRef('', 500)
  20. console.log(keyword)
  21. return {
  22. keyword
  23. }
  24. },
  25. }
  26. /*
  27. 实现函数防抖的自定义ref
  28. */
  29. function useDebouncedRef<T>(value: T, delay = 200) {
  30. let timeout: number
  31. return customRef((track, trigger) => {
  32. return {
  33. get() {
  34. // 告诉Vue追踪数据
  35. track()
  36. return value
  37. },
  38. set(newValue: T) {
  39. clearTimeout(timeout)
  40. timeout = setTimeout(() => {
  41. value = newValue
  42. // 告诉Vue去触发界面更新
  43. trigger()
  44. }, delay)
  45. }
  46. }
  47. })
  48. }
  49. </script>

50、async  defer

async:加载和渲染后续文档元素的过程将和 script.js 的加载与执行并行进行(异步),乱序;

defer:js文件异步读取加载,要在所有元素解析完成之后,DOMContentLoaded 事件触发之前完成;

51、Promise.all

  1. Promise.all = function (promises) {
  2. return new Promise((resolve, reject) => {
  3. // 参数可以不是数组,但必须具有 Iterator 接口
  4. if (typeof promises[Symbol.iterator] !== "function") {
  5. reject("Type error");
  6. }
  7. if (promises.length === 0) {
  8. resolve([]);
  9. } else {
  10. const res = [];
  11. let count = 0;
  12. const len = promises.length;
  13. for (let i = 0; i < len; i++) {
  14. //考虑到 promises[i] 可能是 thenable 对象也可能是普通值
  15. Promise.resolve(promises[i])
  16. .then((data) => {
  17. res[i] = data;
  18. if (++count === len) {
  19. resolve(res);
  20. }
  21. })
  22. .catch((err) => {
  23. reject(err);
  24. });
  25. }
  26. }
  27. });
  28. };

52、类数组转数组

1、Array.from();

2、Array.prototype.slice.call():

3、扩展运算符

4、Array.prototype.concat.apply();

53、动画属性

  • animation-name   名字
  • animation-duration  时间
  • animation-timing-function  速度曲线
  • animation-delay  动画开始之前的延迟
  • animation-iteration-count  动画执行次数
  • animation-direction   是否轮流反向播放动画

54、DOCTYPE有什么作用?标准模式与混杂模式如何区分?它们有何意义?

告诉浏览器使用哪个版本的HTML规范来渲染文档。DOCTYPE不存在或形式不正确会导致HTML文档以混杂模式呈现。
标准模式(Standards mode)以浏览器支持的最高标准运行;混杂模式(Quirks mode)中页面是一种比较宽松的向后兼容的方式显示。

55、常见的浏览器内核有哪些?

  1. Trident( MSHTML ):IE MaxThon TT The World 360 搜狗浏览器  -ms-

  2. Geckos:Netscape6及以上版本 FireFox Mozilla Suite/SeaMonkey  -moz-

  3. Presto:Opera7及以上(Opera内核原为:Presto,现为:Blink)  -o-

  4. Webkit:Safari Chrome  -webkit-

56、HTML5的文件离线储存怎么使用,工作原理是什么

在线情况下,浏览器发现HTML头部有manifest属性,它会请求manifest文件,如果是第一次访问,那么浏览器就会根据manifest文件的内容下载相应的资源,并进行离线存储。如果已经访问过并且资源已经离线存储了,那么浏览器就会使用离线的资源加载页面。然后浏览器会对比新的manifest文件与旧的manifest文件,如果文件没有发生改变,就不会做任何操作,如果文件改变了,那么就会重新下载文件中的资源,并且进行离线存储。例如,

在页面头部加入manifest属性

<html manifest='cache.manifest'>

57、websocket

58、JS继承(6种)

59、watch跟computed区别

1、computed支持缓存;watch不支持缓存

2、computed不支持异步;watch支持异步

3、computed是多对一或一对一关系;watch是一对多关系

4、computed里每个属性都可以设置set跟get;watch监听的数据必须是data或props里声明过的

60、手写axios

61、小程序

微信小程序 面试题整理(自用)_热爱°可抵岁月漫长的博客-CSDN博客_小程序面试题

62、IE浏览器兼容问题处理

IE浏览器兼容性问题解决方案 - 码上快乐

63、gitlab-ci

GitLab CI介绍——入门篇_BuildRun技术团队的博客-CSDN博客_gitlab-ci

64、vue原理题

12道vue高频原理面试题,你能答出几道? - 知乎

65、回调地狱怎么处理

66、H5新增

H5新增_·Q·的博客-CSDN博客_h5新增

67、块状/内联元素

块状:<div>、<p>、<h1>-<h6>、 <ol>、<ul>、<dl>、<table>、 <address>、<blockquote> 、<form>

内联:<a>、<span>、<br>、<i>、<em>、<strong> <label>、<q>、<var>、<cite>、<code>

68、css能继承的属性

visibility、cursor、line-height、font-size

69、值类型和引用类型区别

引用类型有:Object、Array、Function

两者直接的区别在于值类型保存具体的值,引用类型保存值的地址

70、class的类型实际是函数、本质是null

71、promise

1)三种状态:pending(待定状态)、resolve、reject

2)变化过程:pending->resolve/reject

3)resolve不能到reject状态

4).catch里再接promise会到.then

算法

正则了解

shell了解

最全的 Vue 面试题+详解答案 - 掘金

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/821689
推荐阅读
相关标签
  

闽ICP备14008679号