【前端面试题】每日一个前端面试专题

发布时间:2024年01月09日

一、typeof 与 instanceof 区别?如何instanceof的原理

问题回答思路
  1. typeof和instanceof 都可以检测数据类型,typeof检测如果是基本数据类型返回对应的结果。如果检测是对象的话,默认返回一个object,所以无法区分那种对象。

    typeof 数据
    
  2. instanceof是用于判断指定的数据,是否满足和指定构造函数匹配,只要匹配就说明他是同一种数据类型,主要用于判断对象的类型,无法用于基本数据类型,基本数据类型不存在构造器

    [] instanceof Array
    {} instanceof Object
    
回答原理

instanceof的原理就是获取左边数据的构造函数,用于和右边(指定的构造函数)进行判断是否相等。

如果左边获取到的构造函数不等于右边,并不会马上结束,循环继续找对象的原型的函数是否和右边相等,直到找完了原型链对象,都匹配不了,返回false

代码复现:

function myInstanceof(left, right) {
    // 这里先用typeof来判断基础数据类型,如果是,直接返回false
    if(typeof left !== 'object' || left === null) return false;
    // getProtypeOf是Object对象自带的API,能够拿到参数的原型对象
    let proto = Object.getPrototypeOf(left);
    while(true) {                  
        if(proto === null) return false;
        if(proto === right.prototype) return true;//找到相同原型对象,返回true
        proto = Object.getPrototypeof(proto);
    }
}

二、bind、call、apply 区别?如何实现一个bind?

回答思路

从上面可以看到,applycallbind三者的区别在于:

  • 三者都可以改变函数的this对象指向
  • 三者第一个参数都是this要指向的对象,如果如果没有这个参数或参数为undefinednull,则默认指向全局window
  • 三者都可以传参,但是apply是数组,而call是参数列表,且applycall是一次性传入参数,而bind可以分为多次传入
  • bind是返回绑定this之后的函数,applycall 则是立即执行

三、说说 JavaScript 中内存泄漏的几种情况?

内存泄漏不等于内存溢出。完全两个概念。内存泄漏可能导致内存溢出

回答思路

内存泄漏指的就是代码运行过程中,变量使用完毕后无法被垃圾回收机制销毁(回收)。一直占这内存。这种情况称为内存泄漏。

常见的内存泄漏:

  1. 使用闭包,导致延长了变量的声明周期,函数调用完成后,变量无法及时被销毁。
  2. 定时器,组件中开启定时器后,离开了这个组件,但是定时器忘记清除,导致内存一直在运行定时器。
  3. 意外的全局变量。定义变量忘记使用var来声明。导致这个变量是全局的。函数被销毁了,变量无法被销毁
  4. dom元素删除:给dom元素绑定了事件,但是dom元素被删除后,事件绑定函数还存在。

四、说说 Javascript 数字精度丢失的问题,如何解决?

标准答案:

在javascript的世界中,所有的数据要进行处理,都要进行二进制的转换。

整数转化为二进制没有任何问题。但是小数转化二二进制就会出现无法整除的情况。

比如:

0.3-0.2 = 0.99999998

本身0.3和0.2

五、大文件上传如何做断点续传?

标准答案:

大文件上传上传遇到的问题,文件过大,上传很慢,上传中途可能出现网络异常、加上暂停功能解决续传的问题。

所以才出现了大文件断点续传。

思路:

  1. 本地通过<input type="file" onchange="">change事件可以获取文件对象file【size、type、name】

  2. 前端获取file对象后,使用slice对文件进行切片操作。得到多个切片数组。

  3. 前端封装文件上传代码。通过promise.all的方式来进行批量上传。虽然js是单线程的语言。但是浏览器是多线程,可以一次性处理多个文件上传任务。

    promise.all() //同时处理多个promise任务,当所有任务成功。all返回成功,但凡一个失败。all失败
    promise.race() //同时处理多个promise任务,拿到最快的请求结果
    promise.allsetlet() //同时处理多个promise任务,不管成功还是失败,都会返回结果。返回所有结果
    
  4. 如果需要暂停,需要使用axios提供的cancleToken来取消请求。

  5. 所有切片上传完毕后,在调用后端提供的合并接口,要求后端合并所有切片。返回结果给前端

  6. 前端拿到结果在提示用户上传成功

六、web常见的攻击方式有哪些?如何防御?

web攻击指的就是利用前端页面。或者前端身份信息。对服务区发起恶意的请求。

  • XSS (Cross Site Scripting) 跨站脚本攻击:

    • 攻击目标是为了盗取存储在客户端的cookie或者其他网站用于识别客户端身份的敏感信息。一旦获取到合法用户的信息后,攻击者甚至可以假冒合法用户与网站进行交互。
    • 在页面文本框里面容易输入<script>标签,里面写死循环造成对服务器攻击,或者写入特殊的代码。
  • CSRF(Cross-site request forgery)跨站请求伪造

    攻击者诱导受害者进入第三方网站,在第三方网站中,向被攻击网站发送跨站请求

    利用受害者在被攻击网站已经获取的注册凭证,绕过后台的用户验证,达到冒充用户对被攻击的网站执行某项操作的目

    一个典型的CSRF攻击有着如下的流程:

    • 受害者登录a.com,并保留了登录凭证(Cookie)
    • 攻击者引诱受害者访问了b.com
    • b.com 向 a.com 发送了一个请求:a.com/act=xx。浏览器会默认携带a.com的Cookie
    • a.com接收到请求后,对请求进行验证,并确认是受害者的凭证,误以为是受害者自己发送的请求
    • a.com以受害者的名义执行了act=xx
    • 攻击完成,攻击者在受害者不知情的情况下,冒充受害者,让a.com执行了自己定义的操作
  • SQL注入攻击:前端在输入框恶意输入sql语句,传递给后端,后端服务器如果在没有验证的情况,直接拿去进行sql拼接。就可能出现绕过身份,直接访问数据库。

七、如何递归实现一个深度拷贝

递归实现一个深度拷贝,最核心的问题就是知道你每次克隆的属性是基本类型还是引用类型,

如果是基本类型直接返回结果,赋值给新对象,如果是引用类型,我们采用递归来生成新对象,在返回上一层对象

function deepClone(obj, hash = new Map()) {
  if (obj === null) return obj; // 如果是null或者undefined我就不进行拷贝操作
  if (obj instanceof Date) return new Date(obj);
  if (obj instanceof RegExp) return new RegExp(obj);
  // 可能是对象或者普通的值  如果是函数的话是不需要深拷贝
  if (typeof obj !== "object") return obj;
  // 是对象的话就要进行深拷贝
  if (hash.get(obj)) return hash.get(obj);
  let cloneObj = new obj.constructor();
  // 找到的是所属类原型上的constructor,而原型上的 constructor指向的是当前类本身
  hash.set(obj, cloneObj);
  for (let key in obj) {
    if (obj.hasOwnProperty(key)) {
      // 实现一个递归拷贝
      cloneObj[key] = deepClone(obj[key], hash);
    }
  }
  return cloneObj;
}

八、事件代理你在项目中那个地方使用到了?具体说一个场景

标准:

事件代理和事件委托利用了冒泡机制来实现页面优化。

当需要绑定在组件身上的事件冒泡到父组件,我们可以在父组件统一处理业务

比如在React开发过程中,表格的每一行数据都添加删除功能。

如果你每一行数据都绑定一个点击事件,数据多了性能并不好。

可以在表格上面动态获取点击的按钮编号来实现删除。

九、说一下你对this在不同环境下的指向问题

标准:

this指向最核心的概念:

  1. this永远指向一个对象,无论在哪个环境下执行
  2. 箭头函数本身没有this,他的this来源于父级作用域(作用域概念理解清楚)
  3. 普通函数的this,遵循一个原则,谁调用这个函数,this就指向谁。

十、ajax原理是什么?axios和ajax什么关系。

ajax就是浏览器提出的前端异步请求的一种技术。

核心代码如下:

const xmlhttp = new XMLHttpRequest()
//建立连接
xmlhttp.open(method, url, [async][, user][, password])
xmlhttp.open("GET","http://127.0.0.1:8002/users/findUser",false)

//发送请求
xmlhttp.send("username=xiaowang&password=123")

//得到响应结果
//监听浏览器状态码,一旦状态码发生变化,这个事件触发
xnlhttp.onreadystatechange = function(){
    if(xmlhttp.status>=200 && xmlhttp.readystate==4){
        const msg = xmlhttp.responseText
        const data = JSON.parse(msg)
    }
}

步骤:

  1. 创建异步请求对象XMLHttpRequest。
  2. 建立服务器连接,open函数。只有通过TCP三次握手成功后,前端才可以继续后面的操作
  3. 前端可以发送请求,send传递参数
  4. 前端要直到请求成功没有,只能通过状态码来判断。所以需要onreadystatechange监听状态码的变化。当状态码等于200,才代表成功,readystate等于才代表可以获取后端数据

axios是一个第三方的请求工具。

底层:ajax+promise进行封装。调用axios的api函数默认返回的就是promise对象。解决了回调地狱的问题。

并且还提供了请求拦截器、响应拦截器等等功能。

文章来源:https://blog.csdn.net/weixin_42533732/article/details/135462873
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。