面试问题总结(一)

357 阅读6分钟

最近面试了 2 家公司( 5月29日 - 6月2日 ),整理一下面试时面试官提出的问题,以做记录~

面试感想🔗

1. 自我介绍 + 项目介绍

大概介绍了下毕业时间,实习经历,最近一份工作的工作内容。

项目相关

2. 说一下你第一个项目中( vsxxx )app 和 H5 是如何进行交互的,举个简单的例子

App 在打开 H5 页面时,通过向页面注册需要交互的方法,前端通过调用这个 app 提供的方法来向客户端获取数据或发送数据( window.WebViewJavascriptBridge )

首先,由于安卓和 ios 注入方法的不用,所以安卓在调用方法前,前端需要判断一下当前 window 下是否存在指定的方法。

// 检测安卓的方法是否存在
function connectWebViewJavascriptBridge(callback) {
  if (window.WebViewJavascriptBridge) {
    callback(WebViewJavascriptBridge);
  } else {
    document.addEventListener(
      'WebViewJavascriptBridgeReady',
      function() {
        callback(WebViewJavascriptBridge);
      },
      false
    );
  }
}

然后接下来是具体方法的调用,以 app 打开 H5,需要给 H5 发送当前登录 app 的用户的登录信息为例

// 调用获取客户端信息的方法
let userInfos = {};
let firstEnter = true;
getUserInfos(reqDate, (data) => {
    userInfos = JSON.parse(data); // 这里获得app的用户的登录信息
});
function getUserInfos(reqDate, successCall) {
  if (isIos) {
    window['H5GetUserInfos'] = function(data) {
        if (successCall) {
            // 调用成功的回调函数,data为客户端返回给我们的数据
            successCall(data);
        }
      };
      // 将调用方法时请求的参数发送给客户端,若无填null
      window.webkit.messageHandlers.H5GetUserInfos.postMessage(reqDate);
  } else if (isAndroid) {
    androidGetUserInfos(reqDate, successCall);
  }
}
function androidGetUserInfos(reqDate, successCall) {
  connectWebViewJavascriptBridge(function(bridge) {
    if (firstEnter) {
        // 安卓的方法在调用前需要初始化一次,所以用个索引值标识,初始化了就不用在调用了
        firstEnter = false;
        bridge.init(function(message, responseCallback) {
            var data = {
                'Javascript Responds': 'Wee!'
            };
            responseCallback(data);
        });
    }
    bridge.callHandler('H5GetUserInfos', reqDate, function(
      responseData
    ) {
      successCall(responseData);
    });
  });
}

3. 页面如果一次要渲染成千上万个 dom,是否会造成卡顿,如何处理?

会造成卡顿,可以使用懒加载的方式,监听页面的滚动,靠近底部时加载剩余部分的 dom。

4. 做 H5 开发时,会碰到输入框聚焦后,被软键盘遮挡的情况,如何解决?

解决方案🔗

5. 绘制一个地图的边界,可以如何实现,数据应该是怎么的?

可以使用 canvas + svg 来绘制,数据使用 N 多个经纬度的坐标点连接起来,就可以绘制成一个地图的边界。

6. 一道 js 基础题,考察 null 和 undefined 的区别

    let b,a = null;
    console.log(a==b);  // 输出true
    console.log(a===b); // 输出false

因为 let b,a = null 这句代码的结果是 b: undefineda: null

在比较相等性之前有个前提条件,不能将 nullundefined 他任何值,并且规定 nullundefined 是相等的。

全等于状态下,是 false,这个很好理解,它们不属于同一数据类型(如下图所示)。

7. 用 js 来去除数组中重复的值

思路一:使用 ES6 的 set

let arr = [1,1,5,3,2,5,0];
return Array.from(new Set(arr));

思路二:使用 Map - 用数组的值做 key,个数做 value,循环数组,如果遇到已有的 key 值就不做任何操作,如果遇到没有的就存下来做 key 。直到循环完,最后只取 map 的 key ,就可以得到去重后的数组。

实现如下:(利用Object的属性值唯一)

let arr = [1,1,5,3,2,5,0];
let result = []; // 去重数组
let obj = {}; // 去重对象
for(let i = 0; i < arr.length; i++) {
    if(!obj[arr[i].item]) {
        result.push(arr[i].item);
        obj[arr[i].item] = i + 1;
    }
}

8. 算法题 - 两数只和

给定一个整数数组 nums 和一个目标值 target,请你在该数组中找出和为目标值的那 两个 整数,并返回他们的数组下标。假设每种输入只会对应一个答案。但是,数组中同一个元素不能使用两遍。 解法一: 时间复杂度:O(n) 的平方

let nums = [2, 7, 11, 15], target = 9
function twoSum(nums, target) {
    for (int i = 0; i < nums.length; i++) {
        for (int j = i + 1; j < nums.length; j++) {
            if (nums[j] == target - nums[i]) {
                return new int[] { i, j };
            }
        }
    }
}

解法二: 时间复杂度:O(n)

const twoSum = (nums, target) => {
    let map = new Map();
    let res = [];
    nums.forEach((e, i) => map.set(e, i));
    for(let i=0;i<nums.length;i++) {
        let j = map.get[targer - nums[i]];
        if(j && j !== i) {
            res = [i, j];
            break;
        }
    }
    return res;
};

解法三:双指针

const twoSum = (numbers, target) => {
    var i = 0, j = numbers.length - 1;    
    while (i < j){
        if(numbers[i] + numbers[j] == target) {    
            break; // 等于,则得到结果
        }        
        else if(numbers[i] + numbers[j] < target) {
            i++; // 小于则:指向低处的指针向高处移动,两数和增加
        }        
        else {            
            j--; // 大于则:指向高处的指针向低处移动,两数和减小
        }    
    }    
    return [i + 1, j + 1];
};

9. 使用 Eslint 来做了哪些代码审查?

看这里🔗

10. 简述一下 Vue 双向绑定的原理

看这里🔗

11. Vue 的生命周期

自己的:🔗

别人的:🔗

12. 开发 H5 使用的计量单位是?如何进行换算的?

使用的是 rem,以 375 为基准来计算,计算过程如下:

@fontSizeStandard: 37.5; // 设置字号基准值为37.5

使用具体dom的像素值 / @fontSizeStandard = rem的值。

.pxtorem(@property; @sizeValue) {
  @remValue: (@sizeValue / @fontSizeStandard);
  @{property}: ~'@{remValue}rem';
}

使用如下: 
.pxtorem(font-size, 14);

13. Webpack 如何进行节流(性能优化)/ 浏览器防抖如何实现

  • 资源与依赖包的控制
  • 减少文件搜索范围(设置 resolve.alias 字段 / 合理配置 extensions 扩展名)
  • loader 预处理文件增加 include 匹配特定条件
  • happypack 多线程执行
  • babel-plugin-dynamic-import-node 异步加载
  • DllPlugin 分包

详细点击这里🔗

防抖的实现:以表单提交为例,给提交按钮设置一个 disabled 属性,数据提交发起前将 disabled 设置为 true ,禁止用户点击,等到服务端返回了具体数据后再将 disabled 复原。

14. Get 和 Post 的区别

  • get 产生一个 TCP 数据包;post 产生两个 TCP 数据包。
  • 对于 get 请求,浏览器会把 http header 和 data 一并发送出去,服务器响应 200; 而对于 post ,浏览器先发送 header,服务器响应 100 continue,浏览器再发送 data ,服务器响应 200 ok。
  • get 请求的参数是明文显示在 url 后的,并且有长度限制,而 post 没有
  • get 请求参数会被完整保留在浏览器历史记录里,而 post 中的参数不会被保留。

15. 图片懒加载如何实现

首先一张图片就是一个 标签,浏览器是否发起请求图片是根据 的 src 属性。

所以实现懒加载的关键就是,在图片没有进入可视区域时,先不给 的 src 赋值,这样浏览器就不会发送请求了,等到图片进入可视区域再给 src 赋值。

实现步骤:

  • 加载 loading 图片 (首先给所有的 img 标签一个默认的 loading 图)
  • 判断哪些图片要加载(图片距离顶部的距离大于可视区域和滚动区域之和时懒加载)
  • 隐形加载图片后替换真图片
    //创建一个临时图片,这个图片在内存中不会到页面上去。实现隐形加载
    var temp = new Image();
    temp.src = imgs[i].getAttribute('data-src'); // 只会请求一次
    // onload 判断图片加载完毕,真是图片加载完毕,再赋值给 dom 节点
    temp.onload = function(){
    	// 获取自定义属性 data-src ,用真图片替换假图片
    	imgs[i].src = imgs[i].getAttribute('data-src')
    }
    

面试题总结完毕~