前端面试题大合集

1、bind函数的实现过程
// 简化实现,完整版实现中的第 2 步
Function.prototype.bind = function (context) {var self = this;// 第 1 个参数是指定的 this,截取保存第 1 个之后的参数// arr.slice(begin); 即 [begin, end]var args = Array.prototype.slice.call(arguments, 1); return function () {// 此时的 arguments 是指 bind 返回的函数调用时接收的参数// 即 return function 的参数,和上面那个不同// 类数组转成数组var bindArgs = Array.prototype.slice.call(arguments);// 执行函数return self.apply( context, args.concat(bindArgs) );}
}
2、高阶函数、函数柯里化

简单来说,高阶函数是一个接受函数作为参数传递或者将函数作为返回值输出的函数。

一个经常用到的柯里化函数:


var curry = function (fn) {var args = [].slice.call(arguments, 1);return function() {var newArgs = args.concat([].slice.call(arguments));return fn.apply(this, newArgs);};
};
3、节流

函数节流,指的是在一定的时间间隔内(比如说3秒),只执行一次,在这三秒内无视后来产生的函数调用请求,也不会延长时间间隔。3秒间隔结束后,第一遇到新的函数调用会触发执行,然后在这新的3秒内依旧无视后来产生的函数调用请求,以此类推。

  • 应用场景:非常适用于函数被频繁调用的场景,例如:window.onresize事件,mousemove事件,上传进度等等。
  • 实现方案一:用时间戳来实现
// fn 是需要执行的函数
// wait 是时间间隔
const throttle = (fn, wait = 50) => {// 上一次执行 fn 的时间let previous = 0// 将 throttle 处理结果当作函数返回return function(...args) {// 获取当前时间,转换成时间戳,单位毫秒let now = +new Date()// 将当前时间和上一次执行函数的时间进行对比// 大于等待时间就把 previous 设置为当前时间并执行函数 fnif (now - previous > wait) {previous = nowfn.apply(this, args)}}
}// DEMO
// 执行 throttle 函数返回新函数
const betterFn = throttle(() => console.log('fn 函数执行了'), 1000)
// 每 10 毫秒执行一次 betterFn 函数,但是只有时间差大于 1000 时才会执行 fn
setInterval(betterFn, 10)
  • 实现方案二:用定时器来实现
    //原始函数function add(a:any, b: any) {console.log(a + b, '****本身调用', +new Date());return a + b;};//节流函数const throttle = (fn: any, wait = 50) => {let timer: any = null;return (...args: any) => {if (!timer) {timer = setTimeout(() => {fn.apply(this, [...args])timer = null;}, wait)}}}// betterFn就是节流之后返回的新函数const betterFn = throttle(add, 2000);setInterval(() => {// 如果在此处直接调用add,会出新add频繁触发的情况,加上throttle之后,明显情况好多了betterFn(1, 1)}, 200)
4、防抖

防抖函数debounce指的是某个 函数在某段时间内,无论触发了多少次回调,都只执行最后一次。假如我们设置了一个等待时间3秒的函数,在这3秒内如果遇到函数调用请求就重新计时3秒,直至新的3秒内没有函数请求,此时执行函数,不然就以此类推重新计时。

    //防抖const debounce = (fn: any, wait = 50) => {let timer: any = null;return (...args: any) => {if (timer) {clearTimeout(timer)}timer = setTimeout(() => {fn.apply(this, args);}, wait);};};// betterFn就是防抖之后返回的新函数const betterFn = debounce(() => console.log('****执行了', +new Date()), 2000);document.addEventListener('resize', betterFn)
5、null和undefined的本质区别是什么?

(1)从类型来说:

  • null的数据类型是object,typeof null == object,会被隐式转换成0,不容易发现错误;
  • undefined是一个基本数据类型,转换成数值为NaN;

(2)从变量赋值来说

  • 给一个全局变量赋值为null,相当于将这个变量的指针对象以及值清空,如果给对象的属性赋值为null,或者局部变量赋值为null,相当于给这个属性分配了一块空的内存,然后值为null,JS会回收全局变量为null的对象;
  • 给一个全局变量赋值为undefined,相当于将这个对象的值清空,但是这个对象依旧存在,如果给对象的属性赋值为undefined,说明这个值为空;

总结:

null,已经声明赋值为空;引用数据类型;数值转换成0。

undefined,已经声明未赋值;基本数据类型;数值转换成NaN。

6、ES6语法中的const声明一个只读的常量,那为什么可以修改const的值?
const foo = {};// 为 foo 添加一个属性,可以成功
foo.prop = 123;
foo.prop // 123// 将 foo 指向另一个对象,就会报错
foo = { name: '123' }; // TypeError: "foo" is read-only

解答:

const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。

对于简单类型的数据(number,string,boolean),值就是保存在变量指向的那个内存地址,因此等同于常量。

但是对于复合数据类型的数据(主要是对象和数组),变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的(即总是指向另一个固定的地址),至于它指向的数据结构是不是可变的,就完全不能控制了。

因此将一个对象声明为常量必须非常小心。

7、JS数据类型

(1)分为两大类:基本数据类型和引用数据类型

  • 基本数据类型:Number,String,Boolean,Null,Undefined,Symbol,BigInt
  • 引用数据类型:Object(json,Array,function)

(2)两种数据类型存放机制

  • 基本数据类型,体积小,放在栈内存里面
  • 引用数据类型,体积大,放在堆内存里面
  • 引用数据类型会有一个指针放在栈内存里面,用来定位堆里面存放的引用类型的数据

(3)如何判断这两种数据类型

  • typeof   用来查找基本数据类型,引用类型除了function外,其他的都为object
  • instanceof  用来查找引用数据类型;原理:instanceof在查找的时候会遍历左边变量的原型链,直到找到右边变量的prototype,找得到就返回true,找不到就返回false
  • Object.prototype.toString().call()  所有数据类型,原型链和原型有关,首先toString()这个方法本来应该返回string的字符串形式,但是大多数情况会返回[object,****]这种形式,因为js重写了某些数据类型的toString方法;
    const var1 = typeof 123;const var2 = typeof '哈哈哈';const var3 = typeof true;console.log(var1); // numberconsole.log(var2); // stringconsole.log(var3); // booleanconst date1 = new Date()const var4 = date1 instanceof Date;const var5 = date1 instanceof Array;console.log(var4); // trueconsole.log(var5); // falseconst arr1 = [1, 2];const obj1 = { name: '张三' };const fn1 = () => {};const str1 = 'I am a string';const var6 = Object.prototype.toString.call(arr1);const var7 = Object.prototype.toString.call(obj1);const var8 = Object.prototype.toString.call(fn1);const var9 = Object.prototype.toString.call(str1);console.log(var6); // [object Array]console.log(var7); // [object Object]console.log(var8); // [object Function]console.log(var9); // [object String]

(4)数据类型如何转换

  • 转换为字符串:toString()/String()
  • 转换为数字类型:Number()/ParseInt()/ParseFloat()
  • 转换为布尔值:Boolean()/在实际的开发中,也会调用双感叹号强制转换成布尔类型
  • 隐式转换:js是一门弱类型语言,运行期间,会根据运行环境自动类型转换
    const var1 = String(123);const var2 = !!'哈哈哈';const var3 = Number(true);const var4 = '人民' + 899;console.log(var1); // '123'console.log(var2); // trueconsole.log(var3); // 1console.log(var4); // '人民899'

8、JS的事件循环(Event Loop)

(1)首先得解释一下单线程

js是单线程语言,用途决定了它必须是单线程语言;单线程指同一时间只能做一件事。

(2)然后解释一下代码执行流程

同步任务执行完毕,再去执行异步任务,异步任务分宏任务和微任务;如此循环往复,就构成了事件循环

(3)解释一下事件循环

常见的宏任务:setTimeout,setInterval,I/O操作,UI渲染等等

常见的微任务:Promise.then(回调),MutationObserver等等

执行顺序:

先执行同步任务、再执行微任务、最后执行宏任务(宏任务里面还有微任务,先执行微任务);同步任务、微任务、宏任务;同步任务、微任务、宏任务......如此循环往复.....

记住:要执行宏任务的前提是清空了所有微任务;

    function test () {console.log('start')setTimeout(() => {console.log('children2')Promise.resolve().then(() => {console.log('children2-1')})}, 0)setTimeout(() => {console.log('children3')Promise.resolve().then(() => {console.log('children3-1')})}, 0)Promise.resolve().then(() => {console.log('children1')})console.log('end')}test()/*
以上代码在浏览器的执行顺序是:
* start
* end
* children1
* children2
* children2-1
* children3
* children3-1
* */
9、讲一下前端的深拷贝和浅拷贝

因为js的数据类型分两大类,基本数据类型和引用数据类型,在进行变量赋值的时候,分为下面两部分:

  • 基本数据类型:赋值,赋值之后两个变量互不影响
  • 引用数据类型:赋址,两个变量具有相同的引用,指向同一个对象,相互之间有影响

其实,简单来说,浅拷贝就是把变量A的指针赋值给了变量B,变量A和变量B本质上指向的是同一块内存;而深拷贝,是在内存中重新开辟出来一块新的空间给变量B。

看代码比较直观,如下所示:

    let a = 'Jesus Loves You';let b = a;console.log(b);// Jesus Loves Youa = 'God Loves You'console.log(a);// God Loves Youconsole.log(b);// Jesus Loves You/*从上面的变动中可以看出,a的改动并没有影响到b,因为a为基本数据类型*/

在来看另外一组代码,如下所示:

    let a = {name: 'Holy Bible',book: {title: 'God Loves Everyone',price: 45,},}let b = a;console.log(JSON.stringify(b));// {"name":"Holy Bible","book":{"title":"God Loves Everyone","price":45}}a.name = 'Other Book';a.book.price = 55;console.log(JSON.stringify(a));// {"name":"Other Book","book":{"title":"God Loves Everyone","price":55}}console.log(JSON.stringify(b));// {"name":"Other Book","book":{"title":"God Loves Everyone","price":55}}/*从上面的变动中可以看出,a的改动影响到了b,因为a为引用数据类型*/

(1)常用的浅拷贝方式:

  • Object.assign()
  • 展开语法Spread
  • Array.prototype.slice()

(2)常用的深拷贝方式:

JSON.parse(JSON.stringify(object))

这个深拷贝的方式有bug,不建议在日常的开发中使用,会有以下几个问题:

会忽略undefined,会忽略symbol,不能序列化函数,不能解决循环引用的对象,不能正确处理new Date(),不能处理正则

10、讲一下JS的原型链

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/814213.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringBoot整合Logback日志框架

Logback 是一个灵活而高效的日志框架,它是由 Ceki Glc 开发的,也是 Log4j 的创建者之一。Logback 旨在成为 Log4j 的替代品,并提供了一系列强大的功能和性能改进。 以下是 Logback 的一些主要特点和功能: 模块化结构:…

AIGC示例代码

我们将构建一个端到端的文本到图像的生成系统。这个系统将包括文本编码器、条件GAN的生成器和判别器,以及一个训练循环来优化这些组件。 请注意,以下代码仅作为示例,并不保证能够直接运行,因为它依赖于多个库和未提供的模型实现。…

Pods/Nodes

📕作者简介: 过去日记,致力于Java、GoLang,Rust等多种编程语言,热爱技术,喜欢游戏的博主。 📘相关专栏Rust初阶教程、go语言基础系列、spring教程等,大家有兴趣的可以看一看 📙Jav…

L1-083 谁能进图书馆

为了保障安静的阅读环境,有些公共图书馆对儿童入馆做出了限制。例如“12 岁以下儿童禁止入馆,除非有 18 岁以上(包括 18 岁)的成人陪同”。现在有两位小/大朋友跑来问你,他们能不能进去?请你写个程序自动给…

初步学习node.js文件模块

环境已安装好; 写一个read1.js如下; var fs require("fs"); var data ;// 创建一个流 var stream1 fs.createReadStream(test1.jsp); stream1.setEncoding(UTF8);// 绑定data事件 stream1.on(data, function(mydata) {data mydata; });/…

C++复数的加减运算(友元函数)

###复数加减(友元的应用) 声明一个复数类CComplex(类私有数据成员为double型的real和image)定义构造函数,用于指定复数的实部与虚部。定义成员函数,调用该函数时,以格式realimage i的格式输出当…

掌握 Conventional Commits 规范:提升项目版本控制的清晰度与自动化

在软件开发的过程中,版本控制和变更日志的维护是至关重要的。它们不仅帮助开发者追踪项目的演变历程,也为用户和其他开发者提供了清晰的更新说明。为了实现这一目标,Conventional Commits 规范应运而生,旨在提供一种标准化的 Git …

Vue Router 路由动态缓存组件

文章目录 一、简介基本用法生命周期钩子 二、定义是否缓存组件三、缓存组件1. 通过 :include 属性实现vue2.x中vue3.x中 2. 通过 v-slot 功能实现3. 通过 v-if 来实现 四、注意事项 一、简介 Vue Router 允许你缓存路由组件,这样在用户导航回之前的页面时&#xff…

python:算法竞赛入门之一

计算 斐波那契数列(Fibonacci sequence),不受长整型位数限制。 编写 fibonacci.py 如下 # -*- coding: utf-8 -*- """ 计算 斐波那契数列(Fibonacci sequence)""" import sys from …

Go 认证与授权(Authentication)

场景 我们应用开发经常会遇到认证和授权问题,比如:ERP系统、OA系统、CRM系统等等,这些系统都需要用户登录后才能访问,如何实现用户登录和权限认证呢? 我们来看下对应的解决方案: Python的装饰器模式 熟…

程序员Java.vue,python前端后端爬虫开发资源分享

bat面试资料 bat面试题汇总 提取码:724z 更多资料

项目总体测试计划书

目的:编写此测试方案的目的在于明确测试内容、测试环境、测试人员、测试工作进度计划等,以保证测试工作能够在有序的计划安排进行。 测试目标:确保XXX项目的需求分析说明书中的所有功能需求都已实现,且能正常运行;确保…

【Web】DASCTF 2023 0X401七月暑期挑战赛题解

目录 EzFlask MyPicDisk ez_cms ez_py 让俺看看401web题 EzFlask 进来直接给了源码 import uuidfrom flask import Flask, request, session from secret import black_list import jsonapp Flask(__name__) app.secret_key str(uuid.uuid4())def check(data):for i i…

nuxt.config.js配置

babel 预设在构建客户端/服务端的版本。 默认为 nuxt/babel-preset-app 在client构建中是ie:9,在server构建中是node:current。 build.babel.presets 中配置的预设将应用于客户端和服务器构建。目标将由 Nuxt 相应地设置(客户端/服务器&#…

React ant 点击导航条闪烁

问题 : 点击当前位置会出现闪一下的效果 另一种点击方式 , 不会闪 原因 : 没有传递具体的参数给点击事件 , 导致在函数内部无法准确判断要展示哪个子菜单,可能导致页面状态的短暂变化,出现闪烁效果 代码 : // 左侧子菜单弹出const showSonMenu routeK…

【数据挖掘】实验7:高级绘图(上)

实验7:高级绘图(上) 一:实验目的与要求 1:了解R语言中各种图形元素的添加方法,并能够灵活应用这些元素。 2:了解R语言中的各种图形函数,掌握常见图形的绘制方法。 二:实…

python-study-day1

ps:前言 可做毕设,html,web,app,小程序,bug修改,可加急 作者自述 作为一名前端开发工程师,这个大环境不好的情况下,我试过我前端接单子但是没有后端&#xff0c…

用java实现单链表的头插,尾插和反转

今天来练习以下单链表的一些操作,以下的操作都是带有头节点的链表。 定义链表节点类 定义了节点中的值,节点的下一个节点,和一些基本的方法。 public static class ListNode{int val;ListNode next;public ListNode() {}public ListNode(in…

NPM 命令备忘单

NPM 简介 Node Package Manager (NPM) 是 Node.js 环境中不可或缺的命令行工具,充当包管理器来安装、更新和管理 Node.js 应用程序的库、包和模块。对于每个 Node.js 开发人员来说,无论他们的经验水平如何,它都是一个关键工具。 NPM 的主要…

pom.xml显示灰色并被划线

在使用 IDEA 进行开发的过程中,有时候会遇到 pom.xml 显示灰色并被划线的情况,如下图: 这一般是因为该文件被 Maven 忽略导致的,可以进行如下操作恢复: 设置保存后,可以看到 pom.xml 恢复了正常&#xff1a…