一次前端面试的提问总结

2,023 阅读4分钟

记一次比较遥远的面试提问,记得多少写多少,附较详细的解答,欢迎指出错误。

1. 说说CSS中的相对定位与绝对定位:

  • position: relative;为相对定位,根据自身位置来进行定位。
  • position: absolute;为绝对定位,若父级节点的position属性不为static,则根据父级节点位置进行定位;否则则继续寻找上一级position属性不为static的节点进行定位,若都没有找到,则以视窗进行定位。

2. this的指向

  1. 一般情况下,this指向调用该函数的对象
  2. 箭头函数里的this指向定义时所在的对象
  3. this的指向可以通过bind函数改变

3. 类里静态方法的this指向

this指向调用该函数的对象,而静态方法不用创建实例来调用,而是通过类本身来直接调用,故this指向这个类本身而不是实例。

4. letconst

  • let:
  1. 定义的变量只在当前代码块有效,存在局部作用域。
  2. 不存在变量提升,即未定义前访问变量会报错,而不是返回undefined
  3. 在同一个代码块内不允许重复定义同一个变量。
  • const
  1. 拥有let的所有特性
  2. const定义的常量指向的地址不能改变。
  3. 如果定义的是个对象或者数组这种引用类型,只是不能改变它指向的内存地址,但它的属性可以改变。

5. 在React组件的render函数里调用setState会发生什么问题?哪个生命周期函数可以阻止这个问题发生?PureCompoent。

会发生死循环问题,因为setState又会触发render函数。shouldComponentUpdate生命周期函数返回false的时候不会触发render,可以阻止这个问题发生。

PureCompoent在shouldComponentUpdate实现一个浅比较,需要注意的是以下代码不会触发render

const newState = this.state.someState;

newState.attr = 'newValue';
this.setState({
    someState: newState,
});

这是因为浅比较是比较这个变量的地址,地址不变则返回false。 下面代码会触发render

const newState = this.state.someState;

newState.attr = 'newValue';
this.setState({
    someState: {...newState},
});

还可以使用immutable来写,这里使用的是immutable的一个辅助库immutability-helper-x:

import update from 'immutability-helper-x';
...

this.setState({
    someState: update.$set(this.state.someState, 'attr', 'newValue'),
});

6. 浅拷贝和深拷贝。

浅拷贝

浅拷贝就是把对象的属性的值都复制一份到新的内存地址,但只复制一层,若属性的值为对象,则还是原来的引用。如:

const obj = {
    child: {
        key: 'value',
    },
};
const newObj = shallowCopy(obj);

console.log(newObj.child === obj.child);  // true

实现方法:

function shallowCopy(obj) {
    // ES6
    // return {...obj};
    
    return Object.assign({}, obj);
}

深拷贝

而深拷贝则遍历整个对象,把这个对象所有的值都移到新的内存空间,不存在原来的引用,如:

const obj = {
    child: {
        key: 'value',
    },
};
const newObj = deepCopy(obj);

console.log(newObj.child === obj.child);  // false

深拷贝可以通过遍历整个对象来拷贝,也有一种比较简单的实现方法,但效率都比较差。

function deepCopy(obj) { 
  return JSON.parse(JSON.stringify(obj)); 
}

7. Node中的事件循环

因为JS是单线程的,执行I/O操作时会阻塞线程,如果一直等待I/O操作完成再执行下面的代码是不现实的,因此就需要事件循环。

事件循环就是当遇到像I/O这种阻塞线程的操作时,把他们交给系统内核去进行处理,Node继续往下执行代码,等到I/O操作执行完后告知Node,然后Node会把响应的回调函数加进事件队列等待执行。

8. 浏览器缓存

强缓存

HTTP状态码为200(from cache),它的优点是没有访问服务器,直接在本地读取缓存,减少HTTP请求,但也因为如此,这也是它的缺点,因为它不知道服务器资源是否有更新,从而无法获取到最新的资源,这个问题通常用给静态资源添加Hash值来判断资源有无更新,若Hash值不同,则会请求获取最新资源。

相关Header有(按优先级排序):

  1. Cache-Control。设定一个最大有效期,如Cache-Control: max-age=36000000
  2. Expires。它描述一个最后的过期时间,如Expires: Tue, 17 Jul 2018 15:42:01 GMT

协商缓存

HTTP状态码为304,当没有强缓存或者强缓存过期时,会发送请求到服务器,若服务器发现资源没有更新,则返回304告诉客户端不必更新。因为它还是要发送请求,所以比强缓存慢。

相关Header有:

  1. Last-ModifiedIf-Modified-Since
  2. ETagIf-None-Match

9. 内存泄漏

JS提供自动管理内存,称为“垃圾回收机制”,通常用的是“引用计数”,即当一个对象的引用数为0时就把它释放回收。而当一个不在使用的对象的引用数又不为0的时候,无法把他进行回收,即造成内存泄漏问题。