前端 2024-07-16 面试题记录

是的,还是没有合适的工作,焯,我就不信了。

1、rem和em单位的区别

本人回答:

        rem是相对于根元素html上的font-size的大小,em是相对于当前元素的直接父元素的大小。

搜索一手:

  • remrem是相对于根元素(通常是<html>元素)的字体大小的单位。这意味着,无论页面上的元素嵌套有多深,1rem始终等于根元素<html>font-size属性值。浏览器默认的字体大小通常是16px,因此如果未对<html>font-size进行更改,1rem就等于16px
  • emem是相对于其直接父元素的字体大小的单位。如果父元素的字体大小是16px,那么子元素中1em就等于16px。在嵌套结构中,em单位会继承并受到父元素字体大小的影响,因此在嵌套较深的元素中,字体大小可能会逐级累加。

2、如何实现将"I am a developer" 转换成 "developer a am I"

const a = "I am a developer"
console.log(a.split(" ").reverse().join(" "))

3、 如何实现如下布局,在PC端和IPad端显示一行三列,在移动端显示三行一列,请给出html以及主要的css代码

<div class="container">
    <div class="item"></div>
    <div class="item"></div>
    <div class="item"></div>
</div>
@media  (min-width: 769px) and (max-width: 1024px){
    .container {
        display:flex;
        justify-content: space-between;
    }
}

@media(max-width: 768px){
    .container {
        display:flex;
        flex-direction:column;
    }
    
}

4、怎么判断一个js变量是否是对象,并且是否是空对象

本人回答:

function judge(target) {
    return target instanceof Object && !Object.keys(target).length
}

上述回答没得分,因为如果target是个数组,target instanceof Object 返回的结果也会为true。

同时如果该变量是基础数据类型并且是通过构造函数显示创建,那么instanceof也会返回为true。在之前的文章记录过这个问题,但是紧张没考虑全面,我的我的。

// 例如:
const a = new Number(123)
console.log(a instanceof Object) // true

 搜索一手:

function isPlainObjectAndEmpty(target) {  
    // 首先检查target是否不为null且为对象  
    if (target === null || typeof target !== 'object') {  
        return false;  
    }  
  
    // 排除数组、日期等特殊对象类型  
    // 这里使用了Object.prototype.toString.call来准确判断类型  
    // 注意:这里可以根据需要排除更多特殊对象类型  
    const type = Object.prototype.toString.call(target);  
    if (type !== '[object Object]') {  
        return false;  
    }  
  
    // 检查对象是否为空(即没有自身属性)  
    // 或者可以使用Reflect.ownKeys(target),在Symbol类型数据存在的情况下
    return Object.keys(target).length === 0;  
}  
  
// 示例  
console.log(isPlainObjectAndEmpty({})); // true  
console.log(isPlainObjectAndEmpty(new Object())); // true  
console.log(isPlainObjectAndEmpty([])); // false,因为数组不是普通对象  
console.log(isPlainObjectAndEmpty(null)); // false  
console.log(isPlainObjectAndEmpty(undefined)); // false  
console.log(isPlainObjectAndEmpty(new Date())); // false,因为Date是特殊对象类型  
console.log(isPlainObjectAndEmpty(function() {})); // false,因为函数不是普通对象  
console.log(isPlainObjectAndEmpty({ a: 1 })); // false,因为对象包含属性

5、如下的代码输出什么

var a = 8
var func = (function (){
   var a = 10
    return function (){
      a++
      alert(a)
    }
})()

func()
func()

func对应的是一个立即执行函数,因此内部的代码会执行一次,同时内部因为返回的是一个函数。所以该函数会赋值给func, 当第一次调用func 的时候,a++, 此时a = 11 ,弹框输出11,第二次调用的时候,由于闭包作用域,经过a++,a变为12,因此弹框输出12。(注意:a++和++a独自调用的时候,就相当于a+=1,没有先后顺序)


6、实现如下once函数

const onlyFireOnce = once(() => {
    console.log("running")
})

onlyFireOnce() // 无输出
onlyFireOnce() // 无输出
onlyFireOnce() // 输出: running

其实题目的主旨是实现一个once函数,即无论调用多少次,最终都只执行一次。但是题目给出调用三次,最后一次才有输出,要实现最后一次才输出,因为无法确实哪一次才是最后一次,所以应该是题目有点问题。题目的主要主题还是实现执行一次,而不是只执行最后一次。

本人回答:

(虽然满足提议了,但是很丑陋,之前遇到过once函数的实现,但是没仔细看,忘记了,活该)

function once(Fn){
    let a = 1
    return function(){
       return a == 3 ? Fn() : a++
    }
}
// 超过三次调用就老实了

搜索一手:

function once(Fn){
    let called = false
    return function(...arg){
        if(!called){
            called = true
            Fn.apply(this,arg)
        }
    }
}




7、如何实现1.235四舍五入为1.24

const a = 1.235
console.log(Number(a.toFixed(2))) // '1.24'

8、去除数组最大最小值,求剩余数据均值,同时格式化输出

有如下数据:

let data = [
        { number:"p1",score:[80,75,30,90,89,50,78,56,68,88] },

        ......
]

去除score中的最大值、最小值,求剩余成绩的平均值,最后格式化输出

p1得到的平均成绩为xx分

p2得到的平均城市为xx分

......

os:第一眼,简单,用sort排序,去除头尾,求均值,简单。格式化输出,更加简单。

写的时候,焯,sort方法忘记咋用进行排序了,所以有了如下代码

function getAvg(arr){
    let max = min = arr[0]

    let maxIndex = 0
    let minIndex = 0


    arr.forEach((item,index) => {
        if(item > max) {
            max = item
            maxIndex = index
        }
        if(item < min){
            min = item
            minIndex = index
        }
    })

    return arr.splice(max,1).aplice(min,1).reduce((total,item) => total+=item, 0) / 8

}

function formatData(data){
    data.forEach(item => {
        console.log(`${item.number}得到的平均成绩为${getAvg(item.score)}分`)
    })
}

牛逼,我到底在写的什么鬼,splice会改变元素组,但是返回的结果是被去除的元素数组,所以上面的链式调用是错误的,真就是基础不牢地动山摇了。(借此也回顾一下slice,返回的结果也是被去除的元素数组,但是不会改变原数组)

实际只要

function getAvg(arr){
    arr.sort((a,b) => a - b) // sort会改变元素组
    arr.shift() // 删除开头
    arr.pop() // 删除尾部
    return arr.reduce((total,item) => total += item,0) / 8
}

function formatData(data){
    data.forEach(item => {
        console.log(`${item.number}得到的平均成绩为${getAvg(item.score)}分`)
    })
}

9、给出css代码实现文字截取样式,限制长度为200px

其实就是文本溢出隐藏

.text {
    width:200px;
    overflow:hidden;
    white-space:nowrap;
    text-overflow: ellipsis;
}

10、如何查看当前的函数是谁在调用的

1. 使用浏览器的断点调试,查看对应的调用栈

2. 或者使用console.trace(),当对应函数被调用时就会显示当前执行的代码在堆栈中的调用路径


11、(场景题)当用户连续进行货物扫码的时候,如何根据用户扫码的顺序发起请求,即确保用户扫码之后发起的请求的有序性

// 扫码结果的队列
let dataQueue = []
let isRequestInProgress = false


// 用户扫码
function scanCode(){
    uni.scanCode({
        successL:(res) => {
            // 扫码结果
            dataQueue.push({data:res})

            // 如果队列不为空且当前没有正在进行的请求,则开始处理队列 
            if(dataQueue.length && !isRequestInProgress){
                sendRequestFromQueue()
            }
        }
    })
}


// 将扫码的结果作为参数发起请求
function sendRequest(data,callback){
    uni.request({
        url:"/testScan",
        data,
        success:(res) => {
            // 请求成功的逻辑
        },
        fail:(err) => {
            // 请求失败的逻辑
        },
        complete:() => {
            callback()    
            isRequestInProgress = false
        }
    })  
}

// 发送队列中第一个请求的函数
function sendRequestFromQueue(){
    if(dataQueue.length > 0){
        isRequestInProgress = true
        let currentRequestData = dataQueue.shift()
        sendRequest(currentRequestData.data, () => {
            if(dataQueue.length > 0){
                sendRequestFromQueue()
            }
        })
    }
}

12、防抖和节流

防抖:多次事件只执行最后一次

节流:单位时间内事件只执行一次

封装防抖函数:

function debance(fn,limit){
    let timer;
    return function(...args){
        clearTimeout(timer)
        const that = this
        timer = setTimeout(() => {
            fn.apply(that,args)
        }, limit)
        
    }
}

// 使用实例
const Search = debance((query) => {
    console.log("Searching for:", query)
}, 500)

document.querySelector(".searchInput").addEvenlistener("input",function(e){
    Search(e.target.value)
})

封装节流函数:

function throttle(func, limit) {  
    let lastFunc;  
    let lastRan;  
    return function() {  
        const context = this;  
        const args = arguments;  
        if (!lastRan) {  
            // 如果这是第一次运行,立即执行函数  
            func.apply(context, args);  
            lastRan = Date.now(); // 记录上次执行的时间  
        } else {  
            // 如果不是第一次,则设置定时器  
            clearTimeout(lastFunc); // 清除之前的定时器(如果有的话)  
            lastFunc = setTimeout(function() {  
                // 检查当前时间与上次执行时间之间的差是否大于等于限制时间  
                if ((Date.now() - lastRan) >= limit) {  
                    func.apply(context, args); // 如果足够长,则执行函数  
                    lastRan = Date.now(); // 更新上次执行时间  
                }  
            }, limit - (Date.now() - lastRan)); // 计算剩余时间以设置定时器  
        }  
    };  
}

13、节流阀

节流阀防止事件重复执行,例如发送请求的时候,为了防止请求重复发起,可以使用节流阀,其实就是定义一个boolean类型的数据,默认设置为false,表示当前没有请求在执行。在请求的函数内部,初始判断对应的节流阀是否为true,如果为true直接退出当前函数的执行,否则执行对应的请求,请求结束后设置节流阀为false,表示当前没有请求在执行。

14、typeof和instanceof判断变量类型的区别

1. typeof 适合用来检测普通数据类型。

typeof检测引用数据类型返回的都是"object"

注意:特殊情况,使用typeof 检测null 返回的结果也是"object",这是js设计之初遗留的一个问题。

2. instanceof 适合用来检测引用数据类型。

instanceof 用于检测对象是否是另一个对象(构造函数)的实例。

如果想准确的判断对应的数据类型,可以使用Object.prototype.toString.call(对应变量),来检测。

例如:

Object.prototype.toString.call(123)  // "[object Number]"

Object.prototype.toString.call("sss")  // "[object String]"

Object.prototype.toString.call({})  // "[object Object]"

....


15、浏览器的工作原理

浏览器的工作原理是一个复杂而精细的过程,它涉及从用户输入URL到最终在屏幕上呈现网页的多个步骤。在前端面试中,当被问及浏览器的工作原理时,可以按照以下结构进行回答:

一、浏览器的基本组成

首先,简要介绍浏览器的基本组成,包括但不限于用户界面(如地址栏、标签页等)、浏览器引擎、渲染引擎(也称为浏览器内核)、网络模块、JavaScript解释器、UI后端、数据存储等部分。这些部分共同协作,完成浏览器的各项功能。

二、浏览器处理URL请求的过程

  1. 解析URL
    • 当用户在地址栏输入URL并按下回车键时,浏览器首先会解析这个URL,包括协议(如http、https)、域名(如www.example.com)和路径(如/index.html)等部分。
  2. DNS解析
    • 如果URL中包含域名,浏览器需要将其解析为对应的IP地址。这个过程可能会涉及浏览器缓存、系统缓存、路由器缓存以及向DNS服务器查询等步骤。
  3. 建立TCP连接
    • 浏览器使用解析得到的IP地址和端口号(默认为80或443),通过TCP协议与服务器建立连接。TCP连接是可靠的连接服务,通过三次握手建立。
  4. 发送HTTP请求
    • 连接建立后,浏览器会向服务器发送HTTP请求,请求中包含了请求方法(如GET、POST)、请求URL、HTTP版本协议等信息。
  5. 服务器处理请求
    • 服务器接收到请求后,会根据请求的内容进行相应的处理,并返回响应结果。响应结果通常包括响应行、响应头和响应体三部分。
  6. 接收响应并渲染页面
    • 浏览器接收到响应后,会开始解析HTML文档,构建DOM树。同时,如果遇到CSS文件和JavaScript文件,浏览器会并行下载这些资源,并构建CSSOM树。
    • DOM树和CSSOM树构建完成后,浏览器会合并它们生成渲染树。渲染树包含了所有需要显示的内容以及它们的样式信息。
    • 接下来,浏览器会进行布局和绘制操作,将渲染树的内容绘制到屏幕上,最终呈现给用户。

三、浏览器的渲染过程

浏览器的渲染过程可以细分为以下几个步骤:

  1. 解析HTML构建DOM树
    • 浏览器将HTML文档解析成一系列的DOM节点,并按照层级关系构建成DOM树。
  2. 构建CSSOM树
    • 浏览器将CSS文件解析成CSSOM(CSS Object Model)树,这个树包含了所有的样式信息。
  3. 合并DOM树和CSSOM树生成渲染树
    • 浏览器将DOM树和CSSOM树合并成渲染树,渲染树中包含了所有需要显示的内容以及它们的样式信息。
  4. 布局(Layout)
    • 浏览器根据渲染树中的信息,计算每个节点的位置和大小,这个过程称为布局。
  5. 绘制(Paint)
    • 浏览器将布局后的渲染树绘制到屏幕上,用户就可以看到最终的页面了。

四、浏览器的优化机制

在回答中,还可以提到浏览器的优化机制,如缓存机制、并行下载、异步加载等,这些机制可以提高网页的加载速度和性能。

五、总结

最后,总结浏览器的工作原理,强调它是一个复杂但高效的过程,涉及多个组件和步骤的协同工作。同时,可以根据面试的具体要求,进一步展开或深入讨论某个方面的内容。

通过以上结构化的回答,可以清晰地展示你对浏览器工作原理的理解和掌握程度,有助于在前端面试中脱颖而出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值