AntChen Front-end Dev Engineer

前端面试题集锦

2016-11-25

提供一些小的知识点,不全,也不是所有的方式,但是其中的一部分。
  • 1.如何编写js能提升网页的性能

  • js文件的加载位置:因为JavaScript执行和UI渲染是单线程的,js文件载入会阻塞后面对于页面的解析过程,页面会等到js文件完全加载并运行后才继续执行该做的操作。这样可能会出现页面空白or卡顿现象。所以一般无特殊要求会把js标签放入</body>之前(当然了,我们只谈小白编程,不谈什么requirejs之类的东东)。
  • 针对js文件的合并:开发时,我们由于团队合作,js文件可能会很多,所以发布时就没必要了,尽量整合到一起,也方便压缩和载入。
  • 不要让浏览器做深层次的访问:因为对于浏览器来说,一个标识符所处的位置越深,去读写他的速度也就越慢(对于这点,原型链是如这样,冒泡机制也是这样)。所以我们应该更少的访问深层次的东西。比如:
//修改前
function getLi(){
    var i = 0;
    for(;i<document.getElementsByTagName("li").length;i++){ //访问document
        console.log(i,document.getElementsByTagName("li")[i]); //访问document
    };
};
//修改后
function getLi(){
    var li_s = document.getElementsByTagName("li"); //访问document
    var i = 0;
    for(;i<li_s.length;i++){
        console.log(i,li_s[i]); //访问局部变量li_s
    };
};
  • 减少DOM操作:DOM操作远比javascript的执行耗性能,虽然我们避免不了对DOM进行操作,但我们可以尽量去减少该操作对性能的消耗。
  • 减少Dom的重绘重排版;
  • 循环的优化:一个小细节
//修改前
var i = 0;
for(;i<arr.lengthli++){ //每次循环都需要获取数组arr的length
    console.log(arr[i]);
}
//修改后
var i = 0;
var len = arr.length; //获取一次数组arr的length
for(;i<len;i++){
    console.log(arr[i]);
}
  • 2.语义化的html:根据内容的结构化(内容语义化),选择合适的标签(代码语义化)便于开发者阅读和写出更优雅的代码的同时让浏览器的爬虫和机器很好地解析。这个我个人觉得在以前的写法时倒没太注意这些,大多数网站都是一堆div进行到底,偶尔有些别的标签。但是,在HTML5感觉就比较适应了,像如下这种就很明显的语义。
  • 3.一个完整的网页呈现全过程:用户在浏览器中输入一个链接地址;浏览器通过DNS服务,找到url指向的服务器;浏览器通过TCP协议,向Apache Httpd服务器请求资源;Apache Httpd服务器根据配置,决定如何处理资源;并且处理请求及响应的header和body;直接返回静态资源,如果是配置了其他应用服务器或者网关,那么apache将请求转发给网关或应用容器,例如Tomcat或者调用php解释器,在应用容器返回处理的结果之后,返回给客户端;php运行时或者Tomcat分析路由和请求头部,执行相应的服务端代码,调用服务器配置的资源,根据请求,进行计算;php程序调用MySQL数据库,通过mysql协议获取程序对应的数据。
  • 4.浏览器状态码:

整理了一些常见的浏览器状态码代表的意思。

200:确定,客户端请求已成功;

201:已创建;

202:已接受;

203:非权威性信息;

204:无内容;

205:重置内容;

206:部分内容。

301:已永久移动;

302:对象已移动;

304:未修改;

307:临时重定向。

400:错误的请求;

401:访问被拒绝;

403:禁止访问;

404:未找到;

405:用来访问本页面的 HTTP 谓词不被允许(方法不被允许)。

500:内部服务器错误。

js 常用算法

8种排序算法:插入排序、快速排序、冒泡排序、希尔排序、简单选择排序、堆排序、归并排序、折半插入排序。

结果很明显,快速排序、堆排序、归并排序这三种执行效率最快,不过话说回来,冒泡排序的代码真的是最好写的!看来算法高效代码复杂与算法低下代码简单是个很辩证的关系啊!


1.对数组(数字)进行大小排序

无法去重 (易错点:value1跟value2对比,不是value2跟value1对比)

var array = [4,8,128,1,64,2,16,32];
array = array.sort(compare);
function compare(value1, value2){
    if(value1 < value2){
           return -1;
      }else if(value1 > value2){
           return 1;
      }else{
           return 0;
      }
 }

结果:

[1, 2, 4, 8, 16, 32, 64, 128]

通常这种返回值是为了简洁表达value1,value2

返回-1:说明 value1小于value2

返回 0:说明 value1等于value2

返回 1:说明 value1大于value2


2.数组去重

原理:定义一个对象obj,然后把数组元素作为obj的属性名,利用属性名是否重复进行判重

方法一

var arr = ['1', '2', '2', '3', '3', '4', '5', '6'];
var unique = function(arr){
  let obj = {};
  let newArr = [];
  arr.forEach(function(x){
    if(!obj[x]){ //如果对象中没有该元素对应的属性
      obj[x] = true;
      newArr.push(x);
    }
  });
  return newArr;
}
unique(arr)

方法二

//利用数组的indexOf方法(indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。!!!如果要检索的字符串值没有出现,则该方法返回 -1。)
function unique (arr) {
 var result = [];
 for (var i = 0; i < arr.length; i++)
 {
  if (result.indexOf(arr[i]) == -1) result.push(arr[i]);
 }
 return result;
}

结合起来,

var array2 = [1, 2, 1, 1, 2, 2, 3, 5, 8];
var arrayNew = [4, 1, 2, 6, 7, 7, 8, 8, 3];
function arrayUnique(arr) {
  var a = arr.concat(array2);
  var result = [];
  var obj = {};
  a.forEach(x => {
    if (!obj[x]) {
      obj[x] = true;
      result.push(x)
    }
  })
  result.sort(function(v1, v2){
    if (v1 > v2) {
      return 1;
    } else {
      return -1;
    }
  })
  return result;
};
arrayUnique(arrayNew)

结果:

["1", "2", "3", "4", "5", "6"]

3.1使用快速排序算法对数组进行排序

这里面包括两种效果,一种是利用快排的特性实现了去重快排,另一种是不去重的快排。

原理:获得目标数组,选定一个元素最为标志位,遍历剩余的元素,比标志位大放右边,比标志位小放左边。

特别注意:还有与标志位相等的元素,如果你存储相等的元素,就实现了去重,如果存储了,就不去重。

var arr = [11, 2, 2, 36, 35, 4, 5, 6];
var quickSort = function(arr){
  if(arr.length <= 1){
    return arr;
  }
  //定义一个左数组,定义一个右数组
  let leftArr = [];
  let rightArr = [];
  //选定一个参照值
  let tag = arr[Math.floor(arr.length/2)];
  /*
   * 使用如下方式判断,会把重复元素去掉,就实现了快排的同时去重
   */
  for(let i = 0; i < arr.length; i++){
    if(arr[i] < tag){ //将比tag小的元素放在左数组中
      leftArr.push(arr[i]);
    }
    if(arr[i] > tag){ //将比tag大的元素放在右数组中
      rightArr.push(arr[i]);
    }
  }
  /*
   * 使用如下方式就是使用快排进行排序,不去重
   */
  for(let i = 1; i < arr.length; i++){
    if(arr[i] < tag){ //将比tag小的元素放在左数组中
      leftArr.push(arr[i]);
    }else{ //将比tag大的元素放在右数组中
      rightArr.push(arr[i]);
    }
  }
  //递归调用
  return [].concat(quickSort(leftArr),[tag],quickSort(rightArr));
}
quickSort(arr)

结果: 第一种去重:

[2, 4, 5, 6, 11, 35, 36]

第二种不去重:

[2, 2, 4, 5, 6, 11, 35, 36]

3.2使用冒泡排序算法对数组进行排序

在冒泡排序中的核心部分是

var arr = [12, 23, 2, 32, 3, 45, 23, 12, 4, 5, 6];
var n = arr.length;
var flag = true;
for(i = 0;i < n - 1;i++){
    flag = true;
    for(j = 0;j < n - 1 - i;j++) {
        if(arr[j+1] < arr[j]) {
            var temp = arr[j+1];
            arr[j+1] = arr[j];
            arr[j] = temp;
            flag = false;
        }
    }
    if (flag) {
        break;
    }
}
console.log(arr)

3.3 使用选择排序对数组进行排序

原理:先从原始数组中选择一个最小的数据,和第一个位置1的数据交换。再从剩下的n-1个数据中选择次小的数据,将其和第二个位置的数据交换。不断重复,直到最后两个数据完成交换。可以很清楚的发现,选择排序是固定位置,找元素.

var arr = [12, 23, 2, 32, 3, 45, 23, 12, 4, 5, 6];
function selectSort(arr) {
    var min = 9999,
        minindex = 0;
    var left = [],
        right = arr.slice();
    if (arr.length <= 1) return arr;
    for (var i = 0; i < arr.length; i++) {
        if (arr[i] <= min) {
            min = arr[i];
            minindex = i;
        }
    }
    left.push(min);
    right.splice(minindex, 1);
    return [].concat(left, selectSort(right))
}

var results = selectSort(arr)
console.log(results)

4.统计字符串中出现次数最多的字符

原理:这个和数组去重类似,也是利用一个对象obj,将数组元素作为对象的属性名,如果不存在该属性名,则值赋为1,如果存在,则值加1。

var str = 'apapeeecccnnnss,,,asdwqsssqiirue';
var maxShowTimes = function(str) {
  // 创建一个用于判重的对象
  let obj = {};
  // 判断字符串是否为空或只有一个元素
  if (str.length <= 1){
    return str.length === 0 ? '字符串不能为空' : str;
  }
  // 利用String的charAt()方法获取各个字符
  for (let i = 0; i <= str.length; i++){
    if (!obj[str.charAt(i)]){ //如果不存在
      obj[str.charAt(i)] = 1;
    } else{ //如果存在
      obj[str.charAt(i)] += 1;
    }
  }
  // 在obj对象中寻找值最大的那个属性
  let maxChar = ''; //出现次数最多的那个字符
  let maxTimes = 0; //出现的次数
  for (var k in obj){
    if (obj[k] > maxTimes){
      maxChar = k;
      maxTimes = obj[k];
    }
  }
  return maxChar;
}
maxShowTimes(str)

结果:

s

5.不借助第三个变量实现两个变量交换值

原理:就是一个变量替换,思路很巧妙,只能用于数字的交换。

var swap = function(a,b) {
  if(a === b) {
    return [a, b];
  }
  b = b - a; // 此处的 b - a中的b和a的值是最初的值
  a = a + b; // a = a + b -a; 实现了将b的值赋给a
  b = a - b; // b = a - (b - a) = 2a - b 相当于 2b = 2a;实现了将a的值赋给b
  return [a,b];
}

5.2.借助第三个变量实现两个变量交换值

var a = 1,
    b = 2;
var swap = function(a,b) {
  var a = Number(a),
      b = Number(b);
  if ( isNaN(a) && isNaN(b) ) {
    return '必须是数字类型'
  }
  if(a === b) {
    return [a, b];
  }
  var c;
  c = a;
  a = b;
  b = c;
  return [a,b];
}
swap(a, b)

结果:

[2, 1]

6.求一个数组的最大差值

原理:遍历一次数组,找到最大值和最小值,返回差值

var arr = [222, 123, 455, 77777, 1];
var getMaxProfit = function(arr){
  // 定义两个变量,分别存贮最大值和最小值
  let maxNum = arr[0];
  let minNum = arr[0];
  for(let i = 0; i < arr.length; i++){
    if(arr[i] > maxNum){
      maxNum = arr[i];
    }
    if(arr[i] < minNum){
      minNum = arr[i];
    }
  }
  return maxNum - minNum;
}
getMaxProfit(arr)

结果:

77776

7.获取任意长度的随机字符串

原理:可以手动指定字符库及随机字符长度n,利用Math.floor()和Math.random()两个方法实现获取随机字符。

var getRandomString = function(n){
  // 定义随机字符串的字符库
  let str = 'qwertyuiopasdfghjklzxcvbnm1234567890';
  // 定义一个临时变量tmp存储生成的随机字符串
  let tmp = '';
  //获取str的长度
  let len = str.length;
  // 生成一个长度为n的随机字符串
  for(let i = 0; i < n; i++){
    tmp += str.charAt(Math.floor(Math.random() * len));
  }
  return tmp;
}
getRandomString(4)

结果:

随机的四位 数字或者字符

8.数组顺序扰乱

var arr = ['1', '2', '2', '3', '3', '4', '5', '6'];
function shuffle(array) {
  var copy = [],
    n = array.length,
    i;
  // 如果还剩有元素则继续。。。
  while (n) {
    // 随机抽取一个元素
    i = Math.floor(Math.random() * array.length);
    // 如果这个元素之前没有被选中过。。
    if (i in array) {
      copy.push(array[i]);
      delete array[i];
      n--;
    }
  }
  return copy;
};
shuffle(arr)

js算法

m个人随机分成n份,每份里的人随机并且每份人数接近。

方法一:

var randomArr = function(total, length) {
    var arr = [],
      temp=0,
      i = 0,
      index,
      n = total / length;
    for (; i < total; i++) {
      arr.push(i);
    }
    for (var i = 0; i < total; i++) {
      index = parseInt( Math.random() * total );
      temp=arr[i];
      arr[i] = arr[index];
      arr[index]=temp;

    }
    for (var i = 0; i < length; i++) {
      console.log(arr.slice((i*n), (i+1)*n));
    }

  };
  randomArr(10, 4);

方法二:

var randomArr = function(total, length) {
    var arr = [],
      i = 0,
      n = total / length;
    for (; i < total; i++) {
      arr.push(i);
    }
    // 使用sort将原数组的顺序打乱,让有序变成无序
    arr.sort(function() {
      return Math.random() - 0.5;
    });
    for (var i = 0; i < length; i++) {
      console.log(arr.slice((i*n), (i+1)*n));
    }

  };
  randomArr(10, 4);

方法三:

var randomArr = function(total, length) {
    var arr = [],
      newArr = [],
      i = 0,
      index,
      n = total / length;
    for (; i < total; i++) {
      arr.push(i);
    }
    for (var i = 0; i < total; i++) {
      index = parseInt( Math.random() * arr.length );
      newArr.push( arr[index] );
      arr.splice(index, 1);
    }
    for (var i = 0; i < length; i++) {
      console.log(newArr.slice((i*n), (i+1)*n));
    }

  };
  randomArr(10, 4);

小结

  • 判断重复,需要定义一个对象obj;如果需要排序输出的需要定义一个数组

Similar Posts

上一篇 git 提交规范

下一篇 ES6学习小结

Comments