前端笔试题收集(带答案)

762 阅读7分钟
根据下面给定的html结构,在style标签里填充代码实现图中的样式

/* html 结构 */
<div class="box-wrap">
    <ul class="box ">
        <li>1</li>
        <li>2</li>
        <li>3</li>
        <li>4</li>                                    
        <li>5</li>
    </ul>
</div>
/* 填充任意代码 */
.box-wrap{ background-color: #DDD; width: 400px; height: 400px; border:1px solid #000;}

解题思路:

  1. 整体用flex布局,利用flex-direction将子项反转;
  2. 整体水平居中;
  3. 利用伪类nth-child实现个性化样式;
.box {
            display: flex;
            flex-direction: row-reverse;
            list-style-type: none;
            text-align: center;
            align-items: center;
            padding-inline-start: 0px;
            margin-block-end: 0;
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translate(-50%);
        }
        
        ul li {
            width: 38px;
            height: 90px;
            background-color: rgb(56, 140, 255);
            margin-right: 18px;
            vertical-align: middle;
            line-height: 90px;
        }
        
        li:nth-child(3) {
            width: 38px;
            height: 180px;
            line-height: 180px;
        }
        
        li:first-child {
            margin-right: 0;
        }

在数组中找到第K大的元素
示例:
输入: [3,5,6,7,2,4,7,3]k=3
输出: 5

解决思路:

  1. 利用快速排序将数组进行升序排序;
  2. 创建一个对象obj,对象的key放数组的每一项value,值也是value,这样可以过滤掉相同的元素;
  3. 从obj中取值就好;
let arr = [3, 5, 6, 7, 2, 4, 7, 3];

function partion(arr, low, high) {
    let privot = arr[low];
    while (low < high) {
        while (low < high && arr[high] > privot) {
            high--;
        }
        arr[low] = arr[high];
        while (low < high && arr[low] <= privot) {
            low++;
        }
        arr[high] = arr[low];
    }
    arr[low] = privot;
    return low;
}

function quickSort(arr, low, high) {
    if (low < high) {
        let index = partion(arr, low, high);
        quickSort(arr, 0, index - 1);
        quickSort(arr, index + 1, high);
    }
}
quickSort(arr, 0, arr.length - 1);

//找到第k大的数
function findKNum(array, k) {
    var obj = {},
        index = 0,
        result;
    array.forEach(element => {
        obj[element] = element;
    });
    for (var key in obj) {
        index++;
        if (k === index) {
            result = key;
        }
    }
    return result;
}
let result = findKNum(arr, 3);
console.log('结果是:' + result);//结果应该是4
找到html中最深的那个Element节点
  1. 将html节点作为根节点进行递归遍历;
  2. 递归的出口就是没有子节点;
//找到html中最深的那个Element节点
function findDeepestElement() {
    var html = document.querySelector('html');
    var deepestElement = {};
    findChild(html, deepestElement);
    var max = deepestElement['max'];
    return deepestElement[max];
}

function findChild(parent, deepestElement, max) {
    if (parent.hasChildNodes() && parent.children.length > 0) {
        var childrenArr = Array.prototype.slice.apply(parent.children);
        childrenArr.forEach((child) => {
            child['index'] = (parent.index || 0) + 1;
            findChild(child, deepestElement, max);
        })
    } else {
        var index = parent['index'] || 0;
        var max = deepestElement['max'] || 0;
        if (deepestElement[index]) {
            deepestElement[index].push(parent);
        } else {
            deepestElement[index] = [parent];
        }
        if (index > max) {
            max = index;
        }
        deepestElement['max'] = max;
    }
}

var deepestElement = findDeepestElement();
console.log(deepestElement);
实现sum方法,使sum(x)(y) sum(x,y) 返回的结果相同
function sum(num1) {
    if (arguments.length > 0 && arguments[1]) {
        var arr = Array.prototype.slice.apply(arguments);
        num1 = arr.reduce((total, value) => {
            return total + value;
        })
        return num1;
    } else {
        function add(num) {
            num1 = num1 + num;
            return add;
        }
        add.toString = function() {
            return num1;
        }
        return add;
    }
}
var result1 = sum(1)(2)(3);
var result2 = sum(1, 2, 3);
console.log('result1:' + result1 + '-----result2:' + result2);
填充代码实现template方法
var str = '您好,<%=name%>。欢迎来到<%=location%>';
var compiled = template(str);
// complied的输出值为:'您好,张三。欢迎来到**游戏'
compiled({name: '张三', location: '**游戏'})

解决思路:

  1. tempalte方法的返回值是一个方法,并且该返回的方法接受一个json对象作为参数;
  2. 用json对象的key去匹配str中的该key对应的表达式,用值去替换该表单式;
function template(str) {
    return function(options) {
        Object.keys(options).forEach(key => {
            str = str.replace(new RegExp(`<%=${key}%>`, 'g'), options[key]);
        });
        return str;
    }
}

无缝滚动的实现

效果图:

实现思路:

  1. 用setInterval来模拟动画;
  2. 用一个空div来复制一份图片,如果滚动的高度等于空div的offsetTop,则重置滚动条的高度
<template>
    <div class="container" ref="container">
        <div class="images" ref="images">
            <img src="../assets/img/carousel_1.jpg"/>
            <img src="../assets/img/carousel_2.jpg"/>
            <img src="../assets/img/carousel_3.jpg"/>
            <img src="../assets/img/carousel_4.jpg"/>
            <img src="../assets/img/carousel_5.jpg"/>
        </div>
        <div class="empty" ref="empty"></div>
    </div>
</template>
<script>
    export default{
        name:'noGrapScroll',
        mounted(){
            let vm = this;
                vm.$refs.empty.innerHTML = vm.$refs.images.innerHTML;
            setInterval(()=>{
                let scrollTop = vm.$refs.container.scrollTop;            
                if(vm.$refs.empty.offsetTop==vm.$refs.container.scrollTop){
                    vm.$refs.container.scrollTop = 0;
                }else{
                    scrollTop = scrollTop + 5;
                    vm.$refs.container.scrollTop = scrollTop;
                }
            },10);
        }
    }
</script>
<style scoped>
    .container{
        width: 1080px;
        height:840px;
        margin:0 auto;
        overflow:hidden;
    }
    img{
        width: 1080px;
        height: 420px;
    }   
</style>	
promise调用实现
new People('whr').sleep(3000).eat('apple').sleep(5000).eat('durian')
new People('whr').sleep(3000).eat('apple').sleep(5000).eat('durian');

// 打印结果
// (等待3s)--> 'whr eat apple' -(等待5s)--> 'whr eat durian'

实现思路:

  1. 不用promise的话,可以借助函数的链式调用和队列的思路去完成;
  2. 如果用promise,借用resolve和then的关系去模拟;
class People {
    constructor(name) {
        this.name = name;
        this.queue = Promise.resolve();
    }
    sleep(timer) {
        this.queue = this.queue.then(() => {
            return new Promise(resolve => {
                setTimeout(function() {
                    resolve();
                }, timer);
            });
        });
        return this;
    }
    eat(fruit) {
        this.queue = this.queue.then(() => {
            console.log(`${this.name} eat ${fruit}`);
        })
        return this;
    }
}
taskSum(1000,()=>{console.log(1)}).task(1200,()=>{console.log(2)}).task(1300,()=>{console.log(3)})
实现taskSum(1000,()=>{console.log(1)}).task(1200,()=>{console.log(2)}).task(1300,()=>{console.log(3)}),
这里等待1s,打印1,之后等待1.2s,打印2,之后等待5.3s,打印3

function taskSum(timer,callback){   
    return new Task(timer,callback);
}

class Task {
    constructor(timer,callback){
        this.timer = timer;
        this.callback = callback;
        setTimeout(()=>{
            callback();
        },timer);
        this.queue = Promise.resolve();
    }
    sleep(timer) {
        this.queue = this.queue.then(() => {
            return new Promise(resolve => {
                setTimeout(function() {
                    resolve();
                }, timer);
            });
        });
        return this;
    }
    task(timer,callback){   
        this.queue.then(()=>{
            setTimeout(()=>{
                callback();
            },timer);
        })
        return this;
    }
}
taskSum(1000,()=>{console.log(1)}).task(1200,()=>{console.log(2)}).task(5300,()=>{console.log(3)});
[1,2,3].map(parseInt) 执行结果
let newArray = arr.map(callback(currentValue[, index[, array]]) {
  // return element for newArray, after executing something
}[, thisArg]);

callback中接收3个参数:

  1. 当前被处理的元素;
  2. 当前被处理元素的索引;
  3. 当前遍历的数组;
parseInt(string [, radix])

parseInt中接收2个参数:

  1. 要被转换的字符串;
  2. 为解析时的基数,radix是一个介于2-36之间的整数; 返回解析后的整数值,如果被解析参数的第一个字符无法被转化成数值类型,则返回 NaN
parseInt(1,0);//10进制的1,结果为1
parseInt(2,1);//1不属于2~32,结果为NaN
parseInt(3,2);//2进制的3,结果为NaN

所以输出的结果为[1, NaN, NaN]

数组A,数字N,A中找到a,b使a+b=N

怎么样可以更高效一点?这时候要引入哈希表,将数字a和b对应的记录在hash中,如果来了a,直接看hash中是否存在a即可。

字符串,得出最长的没有重复字符的子串长度

思路:

  1. 暴力解法时间复杂度较高,会达到 O(n^2);
  2. 故而采取滑动窗口的方法降低时间复杂度;
  3. 定义一个 map 数据结构存储 (k, v),其中 key 值为字符,value 值为字符位置 +1,加 1 表示从字符位置后一个才开始不重复;
  4. 我们定义不重复子串的开始位置为 start,结束位置为 end;
  5. 随着 end 不断遍历向后,会遇到与 [start, end] 区间内字符相同的情况,此时将字符作为 key 值,获取其 value 值,并更新 start,此时 [start, end] 区间内不存在重复字符;
  6. 无论是否更新 start,都会更新其 map 数据结构和结果 length; 时间复杂度:O(n)

求出一个二维数组[[A, B], [a, b], [1, 2]]所有排列组合

输入[[A, B], [a, b], [1, 2]]

输出[Aa1, Aa2, Ab1, Ab2, Ba1, Ba2, Bb1, Bb2]

实现:

  1. 分析一下,将计算过程拆解为两两相乘的过程;
  2. 首先计算[A, B] * [a, b],得到结果[Aa, Ab, Ba, Bb];
  3. 然后计算[Aa, Ab, Ba, Bb] * [1, 1],得到最终结果[Aa1, Aa2, Ab1, Ab2, Ba1, Ba2, Bb1, Bb2];
  4. 如果还有后续数组,重复上述过程; 关键点就是将上面的乘法用代码表示,用递归实现,关键的计算公式是:计算(已计算的结果 * 当前结果)
实现sum(1)(2)(3).valueOf(),实现这么一个sum函数,返回6

解决思路:

  1. sum里面返回一个闭包函数;
  2. 闭包函数执行的是相加的逻辑;
  3. 重写闭包函数的valueOf,返回结果;
//实现sum(1)(2)(3).valueOf(),实现这么一个sum函数,返回6
function sum(arg1){
    let sum=arg1;
    let tmp = function(arg2){
        sum = sum+arg2;
        return tmp;
    }
    tmp.valueOf = function(){
        return sum;
    }
    return tmp;
}
let result = sum(1)(2)(3).valueOf();
console.log(result);
优化http请求,限制并发请求数

思路:

  1. 用 Promise.race来实现,先并发请求3个图片资源,这样可以得到 3 个 Promise实例,组成一个数组promises;
  2. 然后不断的调用 Promise.race 来返回最快改变状态的 Promise,然后从数组(promises )中删掉这个 Promise 对象实例,再加入一个新的 Promise实例,直到全部的 url 被取完;
var urls = [
    'https://www.kkkk1000.com/images/getImgData/getImgDatadata.jpg', 
    'https://www.kkkk1000.com/images/getImgData/gray.gif', 
    'https://www.kkkk1000.com/images/getImgData/Particle.gif', 
    'https://www.kkkk1000.com/images/getImgData/arithmetic.png', 
    'https://www.kkkk1000.com/images/getImgData/arithmetic2.gif', 
    'https://www.kkkk1000.com/images/getImgData/getImgDataError.jpg', 
    'https://www.kkkk1000.com/images/getImgData/arithmetic.gif', 
    'https://www.kkkk1000.com/images/wxQrCode2.png'
];

function loadImg(url) {
    return new Promise((resolve, reject) => {
        const img = new Image()
        img.onload = function () {
            console.log('一张图片加载完成');
            resolve();
        }
        img.onerror = reject
        img.src = url
    })
};
function limitLoad(urls, handler, limit) {
    // 对数组做一个拷贝
    const sequence = [].concat(urls)
    let promises = [];

    //并发请求到最大数
    promises = sequence.splice(0, limit).map((url, index) => {
        // 这里返回的 index 是任务在 promises 的脚标,
        //用于在 Promise.race 之后找到完成的任务脚标
        return handler(url).then(() => {
            return index
        });
    });

    (async function loop() {
        let p = Promise.race(promises);
        for (let i = 0; i < sequence.length; i++) {
            p = p.then((res) => {
                //promise中替换:将队列中剩余的请求替换已经请求完成的请求
                promises[res] = handler(sequence[i]).then(() => {
                    return res
                });
                return Promise.race(promises)
            })
        }
    })()
}
limitLoad(urls, loadImg, 3);
根据传入的节点id找到对应的到达该节点的路径,并且找到其所有的没有子节点的叶子节点

数据构造:

let treeData = {
    id:1,
    children:[
        {
            id:11,
            children:[
                {
                    id:111
                },
                {
                    id:112
                }
            ]
        },
        {
            id:12,
            children:[
                {
                    id:121,
                    children:[
                        {
                            id:1211
                        }
                    ]
                },
                {
                    id:122,
                    children:[
                        {
                            id:1221,
                            children:[
                                {
                                    id:12211
                                }
                            ]
                        },
                        {
                            id:1222,
                        }
                    ]
                }
            ]
        }
    ]
};

题目描述:

  • 写一个方法,可以根据传入的节点id找到对应的到达该节点的路径,并且找到其所有的没有子节点的叶子节点
  • 比如传入的参数是id=122,则path='1-12-122',leaves为'12211-1222' 采用递归的方法实现
findPathAndLeaves(treeData,122);
function findPathAndLeaves(treeData,id){
    let pResult = [],cResult=[];
    findTarget(treeData,id);
    findAllParents(treeData,id,pResult);
    findChildren(target,cResult);
    console.log('path---:',pResult.join('-'));
    console.log('leaves---:',cResult.join('-'));
}
//查找所有的父节点
function findAllParents(treeData,id,pResult){    
    findParent(treeData,id);
    if(pResult.indexOf(parentId)<0 && parentId){
        pResult.push(parentId);
        let _parentId = parentId;
        parentId = '';
        findAllParents(treeData,_parentId,pResult);
    }
}

var target='';
var parentId;
//根据节点id查找其目标节点
function findTarget(treeData,id){
    if(target){
        return target;
    }
    if(!treeData){
        return;
    }
    if(treeData.id === id){
        return treeData;
    }
    if(treeData.children && treeData.children.length>0){
        for(let item of treeData.children){
            if(item.id === id){
                target = item;          
                break;
            }else{
                findTarget(item,id);
            }
        }
    }  
}
//根据目标节点查找其父节点
function findParent(treeData,id){
    if(parentId){
        return parentId;
    }
    if(!treeData){
        return;
    }
    if(treeData.id === id){
        return treeData;
    }
    if(treeData.children && treeData.children.length>0){
        for(let item of treeData.children){
            if(item.id === id){
                parentId = treeData.id;        
                break;
            }else{
                findParent(item,id);
            }
        }
    } 
}
//根据目标节点查找其没有叶子节点的子节点
function findChildren(target,cResult){
    if(!target || !target.children){
        return;
    }
    for(let item of target.children){
        if(!item.children){
            cResult.push(item.id);
        }else{
            findChildren(item,cResult);
        }
    }
}