前端面试题整理(2022-07-10)

98 阅读6分钟

1、Vue 双向数据绑定原理

vue双向数据绑定原理,又称vue响应式原理,是vue的核心,双向数据绑定是通过数据劫持结合发布者订阅者模式的方式来实现的,通过Object.defineProperty()来劫持各个属性的 setter,getter,在数据变动时发布消息给订阅者,触发相应的监听回调来渲染视图。也就是说数据和视图同步,数据发生变化,视图跟着变化,视图变化,数据也随之发生改变

vue实现双向数据绑定的核心是Object.defineProperty()方法

Object.defineProperty(obj, prop, descriptor)方法,接收三个参数,分别为obj(定义其上属性的对象)prop(定义或修改的属性)descriptor(具体的改变方法),就是用这个方法来定义一个值,当调用时我们使用了它里面的get方法,当我们给这个属性赋值时,又用到了它里面的set方法

具体步骤:

第一步: 需要observer的数据对象进行递归遍历,包括子属性对象的属性,都加上 setter和getter 这样的话,给这个对象的某个值赋值,就会触发setter,那么就能监听到了数据变化

第二步: compile解析模板指令,将模板中的变量替换成数据,然后初始化渲染页面视图,并将每个指令对应的节点绑定更新函数,添加监听数据的订阅者,一旦数据有变动,收到通知,更新视图

第三步: Watcher订阅者是Observer和Compile之间通信的桥梁,主要做的事情是: 1、在自身实例化时往属性订阅器(dep)里面添加自己 2、自身必须有一个update()方法 3、待属性变动dep.notice()通知时,能调用自身的update()方法,并触发Compile中绑定的回调,则功成身退。

第四步: MVVM作为数据绑定的入口,整合Observer、Compile和Watcher三者,通过Observer来监听自己的model数据变化,通过Compile来解析编译模板指令,最终利用Watcher搭起Observer和Compile之间的通信桥梁,达到数据变化 -> 视图更新;视图交互变化(input) -> 数据model变更的双向绑定效果。

2、v-model语法糖是怎么实现的

v-model其实是@input结合:value的语法糖。

如果我们自定义一个组件,定义好@input的监听方法和:value的属性定义就可以使用v-model这个语法糖了。

3、Hash和history有什么区别

hash 模式是一种把前端路由的路径用井号 # 拼接在真实 url 后面的模式。当井号 # 后面的路径发生变化时,浏览器并不会重新发起请求,而是会触发 onhashchange 事件。

history API 是 H5 提供的新特性,允许开发者直接更改前端路由,即更新浏览器 URL 地址而不重新发起请求

对于 history 来说,确实解决了不少 hash 存在的问题,但是也带来了新的问题。具体如下:

  • 使用 history 模式时,在对当前的页面进行刷新时,此时浏览器会重新发起请求。如果 nginx 没有匹配得到当前的 url ,就会出现 404 的页面。
  • 而对于 hash 模式来说, 它虽然看着是改变了 url ,但不会被包括在 http 请求中。所以,它算是被用来指导浏览器的动作,并不影响服务器端。因此,改变 hash 并没有真正地改变 url ,所以页面路径还是之前的路径, nginx 也就不会拦截。
  • 因此,在使用 history 模式时,需要通过服务端来允许地址可访问,如果没有设置,就很容易导致出现 404 的局面。

4、什么是深拷贝和浅拷贝?以及怎么实现深拷贝和浅拷贝?

深拷贝:完整拷贝原对象 浅拷贝:只拷贝原对象第一层的属性

深拷贝的实现:遍历并递归原对象的属性赋值给新对象 浅拷贝的实现:遍历原对象的属性赋值给新对象

5、什么是原型什么是原型链?

对象的内置属性_proto_指向它的构造函数的 prototype 指向的对象,Javascript的执行器,在查找对象的属性时,在对象作用域如果找不到,就会去__proto__里面查找。

6、箭头函数和普通函数有什么区别?

(1)箭头函数比普通函数更加简洁 如果没有参数,就直接写一个空括号即可 如果只有一个参数,可以省去参数括号 如果有多个参数,用逗号分割 如果函数体的返回值只有一句,可以省略大括号 如果函数体不需要返回值,且只有一句话,可以给这个语句前面加一个void关键字。最常用的就是调用一个函数: let fn = () => void doesNotReturn()

(2) 箭头函数没有自己的this 箭头函数不会创建自己的this,所以它没有自己的this,它只会在自己作用域的上一层继承this。所以箭头函数中的this的指向在它在定义时一家确定了,之后不会改变。

(3)箭头函数继承来的this指向永远不会改变

(4) call()、apply()、bind()等方法不能改变箭头函数中的this指向

(5) 箭头函数不能作为构造函数使用

(6) 箭头函数没有自己的arguments

(7) 箭头函数没有prototype

(8) 箭头函数不能用作Generator函数,不能使用yeild关键字

7、New操作符做了什么事情?

1、首先创建了一个新对象

2、设置原型,将对象的原型设置为函数的prototype对象

3、让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)

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

8、说一下eventloop

Javascript的任务运行机制为eventloop。

image.png

如图:

任务队列分为宏任务队列和微任务队列。

setInterval, setTimeout, http请求放在宏队列里。

Promise和普通的任务放在微队列里。

先执行微任务,在执行宏任务。

9、什么是闭包,闭包的作用是什么

当一个内部函数被调用,就会形成闭包,闭包就是能够读取其他函数内部变量的函数。 闭包作用:

局部变量无法共享和长久的保存,而全局变量可能造成变量污染,所以我们希望有一种机制既可以长久的保存变量又不会造成全局污染。

10、Promise是什么?

Promise 是异步编程的一种解决方案:从语法上讲,promise是一个对象,从它可以获取异步操作的消息;从本意上讲,它是承诺,承诺它过一段时间会给你一个结果。promise有三种状态: pending(等待态),fulfiled(成功态),rejected(失败态) ;状态一旦改变,就不会再变。创造promise实例后,它会立即执行。