前端面试(代码)

本文涵盖了前端面试中常见的代码题目,包括JS数组去重、异步处理、闭包、DOM操作、数组操作和算法等。通过分析和解答,帮助读者深入理解前端开发中的关键技术点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


JS数组去重

Array.prototype.unique1 = function () {

  var n = []; //一个新的临时数组

  for (var i = 0; i < this.length; i++) //遍历当前数组
  {

      //如果当前数组的第i已经保存进了临时数组,那么跳过,

      //否则把当前项push到临时数组里面

     if (n.indexOf(this[i]) == -1) 
       n.push(this[i]);

  }
  return n;
}
Array.prototype.unique2 = function()
{

   var n = {},r=[]; //n为hash表,r为临时数组

   for(var i = 0; i < this.length; i++) //遍历当前数组
    {

        if (!n[this[i]]) //如果hash表中没有当前项
        {

            n[this[i]] = true; //存入hash表

            r.push(this[i]); //把当前数组的当前项push到临时数组里面

        }

    }
    return r;
}
Array.prototype.unique3 = function()
{

    var n = [this[0]]; //结果数组

    for(var i = 1; i < this.length; i++) //从第二项开始遍历
    {

        //如果当前数组的第i项在当前数组中第一次出现的位置不是i,

        //那么表示第i项是重复的,忽略掉。否则存入结果数组

        if (this.indexOf(this[i]) == i) n.push(this[i]);

    }

    return n;

}
arr = [...new Set(arr)]; //ES6新方法


js中for循环中的setTimeout()正常工作
我们希望每隔2秒依次输出1,2,3

for (var i = 1; i <= 3; i++) {
    setTimeout(function () {
                console.log(i);
            },2000);
}

实际上却是,在间隔2秒后直接输出3个3。
原因在于计时器是共享一个i,当for循环结束时,i已经变成3,所以这时就会多次弹出3.所以通过定义一个函数来实现中介的作用,从而创建了变量的值的副本。

function doSetTimeout(i) {
  setTimeout(function() { console.log(i); }, 2000);
}

for (var i = 1; i <= 3; ++i)
  doSetTimeout(i);

这时虽然输出1,2,3,但却是间隔2秒后一次性输出,并未达到我们要求的每隔2秒输出一个要求。所以这时我们要调整setTimeout的时间间隔

function doSetTimeout(i) {
  setTimeout(function() { console.log(i); }, 2000*i);
}

for (var i = 1; i <= 3; ++i)
  doSetTimeout(i);

<SCRIPT LANGUAGE="JavaScript">
var bb = 1;
function aa(bb) {
    bb = 2;
    alert(bb);
};
aa(bb);
alert(bb);
</SCRIPT>

结果:依次弹出 2和1
分析:函数体内,bb并没有使用var来定义,按理说这个bb在预处理的时候应该是window的属性。但在这里,函数声明的时候,带了一个参数bb,也就是相当于在函数体内声明了var bb。所以,函数里的bb就是函数活动对象的属性。所以函数执行时会输出2。函数执行完后,函数的活动对象被销毁,也就是局部的这个bb被删除了,执行流进入到window,再输出bb,值就是1了。如果声明函数时,把参数那里的bb去掉,这段代码执行起来,结果就是弹出 2 2


有一个长度未知的数组a,如果它的长度为0就把数字1添加到数组里面,否则按照先进先出的队列规则让第一个元素出队。

分析:这道题主要是考核了数组的队列方法和栈方法。

a.length === 0 ? a.push(1) : a.shift();

var test = (
   function(a) {
     this.a = a;
     return function(b) {         return this.a + b;     }
   }
   (function(a, b) {
        return a;  }(1, 2)
   )
); 
console.log(test(4)); 

输出5,考查自执行函数和闭包


请把<ul><li>第1行</li><li>第2行</li>...</ul>(ul之间有10个li元素)插入body里面,注意:需要考虑到性能问题。
分析:这题主要考察了dom操作。插入节点操作的可以使用insertBefore和appendChild方法,随便用一个都行。但是,题目要求要考虑性能问题,这才是关键,因为,JavaScript操作dom的开销是很大的!提高性能就要减少dom操作。因此,我当时使用了下面的方法,只操作一次dom就够的了:

var lis = ""; 
var ul = document.createElement("ul");   //把li以字符串形式生成
for(var i = 1; i <= 10; i++) {     
   lis += "<li>第" + i + "行</li>"; 
}   // 最后通过innerHTML插入ul里面
ul.innerHTML = lis;   //这里才操作dom,把ul插入到body
document.body.appendChild(ul);


不使用loop循环,创建一个长度为100的数组,并且每个元素的值等于它的下标。
(1)使用setInterval

var a = [],     i = 0;
var interval = setInterval(function() {
                  i < 100 ? a.push(i++) : clearInterval(interval);
                }, 0);

(2)使用数组

var a = Array(100).join(",").split(",").map(
  function(item, index) {
   return index;
  }
);
先是创建一个数组,然后,通过join方法把它转成字符串,然后,再通过split方法把字符串转成数组,这时候,它就拥有100个值为空的元素了,然后,再通过map函数,改变这些元素的值即可。

(3)es6方法

var arrNew = Array.from({length: 100},(v,k)=>k);
console.log(arrNew );
var arr = new Array(100).keys();
console.log(Array.from(arr));

错误方法:

var a = new Array(100);
a = a.map(function(item, index) {     return index; });

因为JavaScript数组是稀疏数组,比如,通过new Array(100)创建一个新的数组的,虽然他的长度是100,但是实际上他是一个空数组,也就是说没有真实存在的元素。所以使用map方法,根本不会去遍历这个数组100次的。


实现数组乱序

var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],     sign = 1;  a.sort(function(a, b) {
     //因为Math.random产生的数在0-1之间
    //所以0.5两边的概率是相等的
    //大于0.5时为升序,小于0.5时为降序
    sign = (Math.random() > 0.5) ? 1 : -1;
    return (a - b) * sign;   });


有一个长度为100的数组,请以优雅的方式求出该数组的前10个元素之和
分析:其实,对于数组求和有很多种方法,也很简单。但是,这题有两个限制条件:优雅的方式、前10个元素。对于“前10个元素”这个限制条件可以使用Array.prototype.slice()方法来截取,对于”优雅的方式”,我的理解是应该尽可能使用数组自带的方法,最好可以使用高阶函数!所以我觉得应该是Array.prototype.reduce()方法。

var a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15], sum = 0;
sum = a.slice(0, 10).reduce(function(pre, current)  {
                                 return pre + current; });   console.log(sum); //55

注意, Array的reduce()把一个函数作用在这个Array的[x1, x2, x3…]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算

var User = {     count: 1,
                 getCount: function() {     return this.count;   }
            }; 
console.log(User.getCount());  //输出1
var func = User.getCount;   
console.log(func());   //输出Undefined

这里func的上下文是window,因此已经失去了count属性。改进如下,使用Function.prototype.bind

var func = User.getCount.bind(User);
console.log(func());   

十一
解析URL地址
这里的方法就在JS代码里先创建一个a标签然后将需要解析的URL赋值给a的href属性

function parseURL(url) {
   var a =  document.createElement('a');
   a.href = url;
   return {
       source: url,
       protocol: a.protocol.replace(':',''),
       host: a.hostname,
       port: a.port,
       query: a.search,
       params: (function(){
           var ret = {},
               seg = a.search.replace(/^\?/,'').split('&'),
               len = seg.length, i = 0, s;
           for (;i<len;i++) {
               if (!seg[i])
                { continue; }
               s = seg[i].split('=');
               ret[s[0]] = s[1];
           }
           return ret;
       })(),
       file: (a.pathname.match(/\/([^\/?#]+)$/i) || [,''])[1],
       hash: a.hash.replace('#',''),
       path: a.pathname.replace(/^([^\/])/,'/$1'),
       relative: (a.href.match(/tps?:\/\/[^\/]+(.+)/) || [,''])[1],
       segments: a.pathname.replace(/^\//,'').split('/')
   };
}

用法


var myURL = parseURL('http://abc.com:8080/dir/index.html?id=255&m=hello#top');

myURL.file;     // = 'index.html'
myURL.hash;     // = 'top'
myURL.host;     // = 'abc.com'
myURL.query;    // = '?id=255&m=hello'
myURL.params;   // = Object = { id: 255, m: hello }
myURL.path;     // = '/dir/index.html'
myURL.segments; // = Array = ['dir', 'index.html']
myURL.port;     // = '8080'
myURL.protocol; // = 'http'
myURL.source;   // = 'http://abc.com:8080/dir/index.html?id=255&m=hello#top'

十二
重构如下两栏布局
这里写图片描述

<div class="content"><div class="aside"></div><div class="main"></div></div>
/*Qzone版*/
.aside{float:left;width:170px;}
.main{float:left;width:790px;}
/*朋友网版*/
.aside{float:left;width:170px;}
.main{overflow:hidden;#zoom:1;}
/*Facebook版*/
.aside{float:left;width:170px;}
.main{margin-left:170px;zoom:1;}
/*Yahoo版*/
.content{position:relative;zoom:1;}
.aside{position:absolute;left:0;top:0;width:170px;}
.main{margin-left:170px;zoom:1;}
/*Google版*/
.aside{display:inline-block;width:170px;}
.main{display:inline-block;width:790px;}

Qzone、朋友网、Facebook都给左栏浮动,唯一不同的是右栏的写法,Qzone给右栏定宽并且浮动,而朋友网和Facebook则并没有给右栏定宽也未浮动,而是利用了创建BFC并且为低版本IE触发hasLayout的原理让右栏自适应宽度。
Yahoo和Google两栏都未用浮动,唯一不同的是Yahoo用了绝对定位的方法,而谷歌用了inline-block,Google已经宣布旗下一些产品放弃对IE8 的支持,所以Google可以大胆的使用inline-block去实现布局,不用去为其他低版本浏览器写一大堆的hack。

十三
常见邮箱验证
输入的数据必须包含 @ 符号和点号(.)。同时,@ 不可以是邮件地址的首字符,并且 @ 之后需有至少一个点号

function validateForm(){
  var x=document.forms["myForm"]["email"].value;
  var atpos=x.indexOf("@");
  var dotpos=x.lastIndexOf(".");
  if (atpos<1 || dotpos<atpos+2 || dotpos+2>=x.length){
    alert("不是一个有效的 e-mail 地址");
    return false;
  }
}







?????????讲一下css的动画(我不太了解, 就直说不太了解,然后她让我试着写了下,就写了些印象里的,她说差不多)
猜一下,如果要绑定动画的话,在哪里绑定?怎么绑定?
如果是行内元素呢?如果字体font-size是10px,行高line-height是2px,显示多高?(依然不知道,猜测是2px,剩余的部分会被隐藏掉)。刚才试了下,发现打错了:

十四
找出整型数组中乘积最大的三个数

var unsorted_array = [-10, 7, 29, 30, 5, -10, -70];

computeProduct(unsorted_array); // 21000

function sortIntegers(a, b) {
  return a - b;
}

// greatest product is either (min1 * min2 * max1 || max1 * max2 * max3)
function computeProduct(unsorted) {
  var sorted_array = unsorted.sort(sortIntegers),
    product1 = 1,
    product2 = 1,
    array_n_element = sorted_array.length - 1;

  // Get the product of three largest integers in sorted array
  for (var x = array_n_element; x > array_n_element - 3; x--) {
      product1 = product1 * sorted_array[x];
  }
  product2 = sorted_array[0] * sorted_array[1] * sorted_array[array_n_element];

  if (product1 > product2) return product1;

  return product2
};

十五
给定两个数组,要求求出两个数组的交集,注意,交集中的元素应该是唯一的。

var firstArray = [2, 2, 4, 1];
var secondArray = [1, 2, 0, 2];

intersection(firstArray, secondArray); // [2, 1]

function intersection(firstArray, secondArray) {
  var hashmap = {};
  var intersectionArray = [];

  firstArray.forEach(function(element) {
    hashmap[element] = 1;
  });

  secondArray.forEach(function(element) {
    if (hashmap[element] === 1) {
      intersectionArray.push(element);
      hashmap[element]++;
    }
  });

  return intersectionArray;
}

十六
给定两个字符串,判断是否颠倒字母而成的字符串,譬如Mary与Army就是同字母而顺序颠倒:

var firstWord = "Mary";
var secondWord = "Army";

isAnagram(firstWord, secondWord); // true

function isAnagram(first, second) {
  // For case insensitivity, change both words to lowercase.
  var a = first.toLowerCase();
  var b = second.toLowerCase();

  // Sort the strings, and join the resulting array to a string. Compare the results
  a = a.split("").sort().join("");
  b = b.split("").sort().join("");

  return a === b;
}

十七
判断某个字符串是否为回文字符串,譬如racecar与race car都是回文字符串:

function isPalindrome(word) {
  // Replace all non-letter chars with "" and change to lowercase
  var lettersOnly = word.toLowerCase().replace(/\s/g, "");

  // Compare the string with the reversed version of the string
  return lettersOnly === lettersOnly.split("").reverse().join("");
}

十八
判断是否为 2 的指数值

// For the non-zero case:
function isPowerOfTwo(number) {
  return number & (number - 1) === 0;
}

// For zero-case:
function isPowerOfTwoZeroCase(number) {
  return (number !== 0) && ((number & (number - 1)) === 0);
}

十九
二进制转换

function decimalToBinary(digit) {
  if(digit >= 1) {
    if (digit % 2) {
      return decimalToBinary((digit - 1) / 2) + 1;
    } else {
      // Recursively return proceeding binary digits
      return decimalToBinary(digit / 2) + 0;
    }
  } else {
    // Exit condition
    return '';
  }
}

二十
创建一个函数来判断给定的表达式中的大括号是否闭合:

var expression = "{{}}{}{}"
var expressionFalse = "{}{{}";

isBalanced(expression); // true
isBalanced(expressionFalse); // false
isBalanced(""); // true

function isBalanced(expression) {
  var checkString = expression;
  var stack = [];

  // If empty, parentheses are technically balanced
  if (checkString.length <= 0) return true;

  for (var i = 0; i < checkString.length; i++) {
    if(checkString[i] === '{') {
      stack.push(checkString[i]);
    } else if (checkString[i] === '}') {
      // Pop on an empty array is undefined
      if (stack.length > 0) {
        stack.pop();
      } else {
        return false;
      }
    }
  }

  // If the array is not empty, it is not balanced
  if (stack.pop()) return false;
  return true;
}

二十一
二分搜索
(1)首先,从有序数组的中间的元素开始搜索,如果该元素正好是目标元素(即要查找的元素),则搜索过程结束,否则进行下一步。
(2)如果目标元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半区域查找,然后重复第一步的操作。
(3)如果某一步数组为空,则表示找不到目标元素。

     // 非递归算法
        function binary_search(arr, key) {
            var low = 0,
                high = arr.length - 1;
            while(low <= high){
                var mid = parseInt((high + low) / 2);
                if(key == arr[mid]){
                    return  mid;
                }else if(key > arr[mid]){
                    low = mid + 1;
                }else{
                    high = mid -1;
                }
            }
            return -1;
        };
        var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
        var result = binary_search(arr,10);
        alert(result); // 9 返回目标元素的索引值       
    // 递归算法
        function binary_search(arr,low, high, key) {
            if (low > high){
                return -1;
            }
            var mid = parseInt((high + low) / 2);
            if(arr[mid] == key){
                return mid;
            }else if (arr[mid] > key){
                high = mid - 1;
                return binary_search(arr, low, high, key);
            }else if (arr[mid] < key){
                low = mid + 1;
                return binary_search(arr, low, high, key);
            }
        };
        var arr = [1,2,3,4,5,6,7,8,9,10,11,23,44,86];
        var result = binary_search(arr, 0, 13, 10);
        alert(result); // 9 返回目标元素的索引值  

二十二
手写数组快速排序
“快速排序”的思想很简单,整个排序过程只需要三步:
(1)在数据集之中,选择一个元素作为”基准”(pivot)。
(2)所有小于”基准”的元素,都移到”基准”的左边;所有大于”基准”的元素,都移到”基准”的右边。
(3)对”基准”左边和右边的两个子集,不断重复第一步和第二步,直到所有子集只剩下一个元素为止。

 var quickSort = function(arr) {
  if (arr.length <= 1) { return arr; }
  var pivotIndex = Math.floor(arr.length / 2);
  var pivot = arr.splice(pivotIndex, 1)[0];
  //这里注意splice返回,是一个包含被删除项目的新数组,所以执行后arr已经删除元素,而【0】则代表被删除的pivot
  var left = [];
  var right = [];
  for (var i = 0; i < arr.length; i++){
    if (arr[i] < pivot) {
      left.push(arr[i]);
    } else {
      right.push(arr[i]);
    }
  }
  return quickSort(left).concat([pivot], quickSort(right));
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值