前端面试题 X 10

142 阅读9分钟

1. v-if和v-show的区别

  • 实现原理:‌

    • v-show是通过动态地切换元素的display属性来实现显示与隐藏。‌当条件为false时,‌元素不会从DOM中移除,‌只是简单地通过修改样式来控制显示与隐藏。‌这种方式的优点是初始渲染性能较高,‌因为它避免了DOM元素的创建和销毁,‌但频繁切换时可能会导致性能问题,‌因为每次切换都需要重新计算样式。‌
    • v-if则是真正地根据条件来销毁和创建DOM元素。‌当条件为true时,‌元素会被创建并添加到DOM中;‌当条件为false时,‌元素会被从DOM中移除。‌这种方式适用于需要根据条件渲染大量数据的情况,‌但频繁使用可能会导致性能下降,‌因为每次条件变化都需要进行DOM的创建和销毁操作。‌
  • 性能差异:‌

    • v-show的性能通常优于v-if,‌尤其是在需要频繁切换显示与隐藏的情况下。‌这是因为v-show只是通过修改CSS样式来切换元素的可见性,‌而不需要进行DOM元素的增删操作,‌从而减少了浏览器的重绘和重排开销。‌
    • v-if在条件切换时会有更高的切换开销,‌因为它涉及到DOM元素的创建和销毁。‌然而,‌在某些情况下,‌如条件很少改变或需要处理多种条件场景时,‌v-if可能更为合适,‌因为它提供了更灵活的条件判断能力。‌
  • 使用场景:‌

    • 当需要频繁切换元素的显示与隐藏时,‌应优先考虑使用v-show,‌因为它能提供更好的初始渲染性能和较少的性能开销。‌
    • 如果条件变化不频繁,‌或者需要根据条件渲染大量数据到页面上(‌符合条件的数据将被渲染)‌,‌则应使用v-if。‌此外,‌v-if可以与v-else、‌v-else-if等指令结合使用,‌以处理多种条件场景。‌

2. v-model实现的原理

v-model只不过是一个语法糖而已,真正的实现靠的还是

原理:
1、通过v-bind,动态绑定value属性
2、监听input事件,把变化后的值赋值给变量

2. 计算属性和侦听器的区别

computed:是计算属性,依赖其它属性值

  1. 支持缓存,只有依赖数据发生改变,才会重新进行计算
  2. 不支持异步,当computed内有异步操作时无效,无法监听数据的变化

watch:没有缓存性,更多的是观察的作用,类似于某些数据的监听回调,每当监听的数据变化时都会执行回调进行后续操作;

  1. 不支持缓存,数据变,直接会触发相应的操作;
  2. watch支持异步
  3. 监听的函数接收两个参数,第一个参数是最新的值;第二个参数是输入之前的值

3. 数组常见方法

方法详解
pop()删除数组的最后一个元素,成功返回删除元素的值
shift()删除数组的第一个元素,成功返回删除元素的值
unshift()往数组最前面添加一个元素,成功返回当前数组的长度
splice()有三个参数,第一个是想要删除的元素的下标(必选),第二个是想要删除的个数(必选),第三个是删除 后想要在原位置替换的值
sort()sort() 使数组按照字符编码默认从小到大排序,成功返回排序后的数组
reverse()reverse() 将数组倒序,成功返回倒序后的数组
push()往数组最后面添加一个元素,成功返回当前数组的长度
filterfilter() 方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
concatconcat() 方法用于连接两个或多个数组。该方法不会改变现有的数组
sliceslice() 方法可从已有的数组中返回选定的元素。该方法并不会修改数组,而是返回一个子数组

4.请简述原型/原型链/(原型)继承

什么是原型:

任何对象实例都有一个原型,也叫原型对象,这个原型对象由对象的内置属性_proto_指向它的构造函数的 prototype 指向的对象,即任何对象都是由一个构造函数创建的,但是不是每一个对象都有 prototype,只有方法才有 prototype。

什么是原型链?

原型链基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。我们知道,每个构造函数都有一个原型对象,每个原型对象都 有一个指向构造函数的指针,而实例又包涵一个指向原型对象的内部指针。

原型链的核心就是依赖对象的_proto_的指向,当自身不存在的属性时,就一层层的扒出创建对象的构造函数,直至到 Object 时,就没有 _proto_指向了。因为_proto_实质找的是 prototype,所以我们只要找这个链条上的构造函数的 prototype。其中 Object.prototype 是没有_proto_属性的,它 ==null。

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的 指针,而实例都包含指向原型对象内部的指针。我们让原型对象等于另一个原型对象的实例此时原型对象将包含一个指向原型对象的指针,再让原型对象的实例等于原型对象,如此层层递进就构成了实例和原型的链条,这就是原型链的概念。

每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数想 指针(constructor),而实例对象都包含一个指向原型对象的内部指针 (proto)。如果让原型对象等于另一个原型对象的实例,此时的原型 对象将包含一个指向另一个原型的指针(proto),另一个原型也包含 着一个指向另一个构造函数的指针(constructor)。假如另一个原型又是 另一个类型的实例……这就构成了实例与原型的链条。也叫原型链 。

原型继承是 js 的一种继承方式,原型链作为实现继承的主要方法,其基本思路是利用原型让一个引用类型继承另一个引用类型的属性和方法, 原型继承:利用原型中的成员可以被和其相关的对象共享这一特性,可以实现继承,这种实现继承的方式,就叫做原型继承。

5.Promise 的理解

1)、什么是 Promise?

我们都知道,Promise 是承诺的意思,承诺它过一段时间会给你一个结果。Promise是一种解决异步编程的方案,相比回调函数和事件更合理和更强大。

从语法上讲,promise 是一个对象,从它可以获取异步操作的消息;

2)、promise 有三种状态:

pending 初始状态也叫等待状态,

fulfiled 成功状态,

rejected 失败状态,

状态一旦改变,就不会再变。创造 promise 实例后,它会立即执行。

3)、Promise 的两个特点

1、Promise 对象的状态不受外界影响。

2、Promise 的状态一旦改变,就不会再变,任何时候都可以得到这个结果,状态不可以逆。

4)、Promise 的三个缺点

1)无法取消 Promise,一旦新建它就会立即执行,无法中途取消。

2)如果不设置回调函数,Promise 内部抛出的错误,不会反映到外部。

3)当处于pending(等待)状态时,无法得知目前进展到哪一个阶段,是刚刚开始还是即将完成。

6.我们用 Promise 来解决什么问题?

promise 是用来解决两个问题的:

1.回调地狱,代码难以维护,常常第一个的函数的输出是第二个函数的输入这种现象。

2.promise 可以支持多并发的请求,获取并发请求中的数据,这个 promise 可以解决异步的问题,本身不能说 promise 是异步的。

7.请简述 async 的用法

Async 就是 generation 和 promise 的语法糖,async 就是将 generator 的*换成 async,将 yiled 换成 await 函数前必须加一个 async,异步操作方法前加一个 await 关键字,意思就 是等一下,执行完了再继续走,注意:await 只能在 async 函数中运行, 否则会报错 Promise 如果返回的是一个错误的结果,如果没有做异常处理,就会报 错,所以用 try..catch

8.改变函数内部 this 指针的指向函数(bind,apply,call 的区 别)

通过 apply 和 call 改变函数的 this 指向,他们两个函数的第一个参数都是一样的表示要改变指向的那个对象,第二个参数,apply 是数组,而 call 则是 arg1,arg2...这种形式。通过 bind 改变 this 作用域会返回一个新的函数,这个函数不会马上执行。

9.深浅拷贝是什么如何实现?

深拷贝:指针赋值,并且内容拷贝。

浅拷贝:只是简单的指针赋值数组

浅拷贝: 如果是数组,可以使用数组的一些方法实现:slice(),concat() 返回一个新数组的特性实现拷贝。

用扩展运算符 spread 实现数组深拷贝: JSON.parse(JSON.stringify())不仅适用于数组还适用于对象。不能拷贝函数,undefined,symbol。

10.For 循环与 map 循环有什么区别

For 遍历对象自身的和继承可枚举的属性,也就是说会包括那些原型链上的属性。

Map 方法不会对空数组进行检测,map 会返回一个新数组,不会对原数组产生影响。