JavaScript相关面试题2:1.深拷贝和浅拷贝区别;2. [“1“,“2“,“3“].map(parselInt)的返回值;3.预防按钮的重复点击

简介: 解决方案1.控制按钮,在短时间内被多次点击,第一次以后的点击无效。2.控制按钮,在点击按钮触发的请求响应之前,再次点击无效。3.配置特殊的URL,然后控制这些URL请求的最小时间间隔。如果再次请求跟前一-次请求间隔很小,弹窗二次提示,是否继续操作。防止无意识复点击按钮给按钮添加控制,在control 毫秒内,第一次点击事件之后的点击事件不执行。

文章目录

深拷贝浅拷贝有什么区别?怎么实现深拷贝?

["1","2","3"].map(parselInt)的返回值是什么?

怎么预防按钮的重复点击?

深拷贝浅拷贝有什么区别?怎么实现深拷贝?

浅拷贝

浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝

如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址

即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址

下面简单实现一个浅拷贝


function shallowClone(obj) {

   const newObj = {};

   for(let prop in obj) {

       if(obj.hasOwnProperty(prop)){

           newObj[prop] = obj[prop];

       }

   }

   return newObj;

}

1

2

3

4

5

6

7

8

9

在JavaScript中,存在浅拷贝的现象有:

Object.assign

Array.prototype.slice(), Array.prototype.concat()

使用拓展运算符实现的复制


深拷贝

深拷贝开辟一个新的栈,两个对象属完成相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性

常见的深拷贝方式有:

_.cloneDeep()

jQuery.extend()

JSON.stringify()

手写循环递归


_.cloneDeep()


const _ = require('lodash');

const obj1 = {

   a: 1,

   b: { f: { g: 1 } },

   c: [1, 2, 3]

};

const obj2 = _.cloneDeep(obj1);

console.log(obj1.b.f === obj2.b.f);// false

1

2

3

4

5

6

7

8

jQuery.extend()


const $ = require('jquery');

const obj1 = {

   a: 1,

   b: { f: { g: 1 } },

   c: [1, 2, 3]

};

const obj2 = $.extend(true, {}, obj1);

console.log(obj1.b.f === obj2.b.f); // false

1

2

3

4

5

6

7

8

JSON.stringify()


const obj2=JSON.parse(JSON.stringify(obj1));


1

2

循环递归


function deepClone(obj, hash = new WeakMap()) {

 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;

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

区别



从上图发现,浅拷贝和深拷贝都创建出一个新的对象,但在复制对象属性的时候,行为就不一样

浅拷贝只复制属性指向某个对象的指针,而不复制对象本身,新旧对象还是共享同一块内存,修改对象属性会影响原对象


[“1”,“2”,“3”].map(parselInt)的返回值是什么?

首先整个题目考校的是两个函数,和一个字符串转数字的概念

1.数组的map函数,接受三个参数,当前值,当前索引,当前数组。

2. parselnt接受两个参数,需要转换的字符串,基数(基数取值范围2~36)

3. 根据上面的两个函数的解释,我们可以发现实际上,上面的[‘1’,‘2’,‘3’].map(parseInt) 其实就是等价于下面的代码。


['1','2','3'].map((item, index) => {  

   return parseInt(item, index)  

})  

//  parseInt('1', 0)  1  

//  parseInt('2', 1)  NaN  

//  parseInt('3', 2)  NaN

1

2

3

4

5

6

4.如果我们需要返回1,2,3需要怎么办?


function parseIntFun(item) {  

   return parseInt(item, 10)  

}  

['1','2','3'].map(parseIntFun)  

//  parseInt('1', 10)  1  

//  parseInt('2', 10)  2  

//  parseInt('3', 10)  3

1

2

3

4

5

6

7

怎么预防按钮的重复点击?

先看看在那些场景会导致重复请求:

1.手速快,不小心双击操作按钮。

2.很小心的点击了一次按钮,因为请求响应比较慢,页面没有任何提示,怀疑上次点击没生效,再次点击操作按钮。

3.很小心的点击了一次按钮, 因为请求响应比较慢,页面没有任何提示,刷新页面,再次点击操作按钮。


解决方案

1.控制按钮,在短时间内被多次点击,第一次以后的点击无效。

2.控制按钮,在点击按钮触发的请求响应之前,再次点击无效。

3.配置特殊的URL,然后控制这些URL请求的最小时间间隔。如果再次请求跟前一-次请求间隔很小,弹窗二次提示,是否继续操作。


防止无意识复点击按钮

给按钮添加控制,在control 毫秒内,第一次点击事件之后的点击事件不执行。


<template>

   <button @click="handleClick"></button>

</templage>

<script>

export default {

   methods: {

       handleClick(event) {

           if (this.disabled) return;

           if (this.notAllowed) return;

           // 点击完多少秒不能继续点

           this.notAllowed = true;

           setTimeout(()=>{

               this.notAllowed = false;

           }, this.control)

           this.$emit('click', event, this);

       }

   }

}

</script>


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

按钮点击立马禁用,等响应回来才能继续点击

触发点击的button实例传入fetch配置,代码如下:


doQuery: function (button) {

   this.FesApi.fetch(`generalcard/query`, {

       sub_card_type: this.query.sub_card_type,

       code_type: this.query.code_type,

       title: this.query.title,

       card_id: this.query.card_id,

       page_info: {

           pageSize: this.paginationOption.page_info.pageSize,

           currentPage: this.paginationOption.page_info.currentPage

       }

   }, {

       //看这里,加上下面一行代码就行。。so easy

       button: button

   }).then(rst => {

       // 成功处理

   });

}


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

在fetch函数内部,设置button的disabled=true,当响应回来时,设置disabled=false代码如下:


const action = function (url, data, option) {

   // 如果传了button

   if (option.button) {

       option.button.currentDisabled = true;

   }

   // 记录日志

   const log = requsetLog.creatLog(url, data);


   return param(url, data, option)

       .then(success, fail)

       .then((response) => {

           requsetLog.changeLogStatus(log, 'success');

           if (option && option.button) {

               option.button.currentDisabled = false;

           }

           return response;

       })

       .catch((error) => {

           requsetLog.changeLogStatus(log, 'fail');

           if (option && option.button) {

               option.button.currentDisabled = false;

           }

           error.message && window.Toast.error(error.message);

           throw error;

       });

};


目录
相关文章
|
7月前
|
存储 算法 架构师
阿里面试:PS+PO、CMS、G1、ZGC区别在哪?什么是卡表、记忆集、联合表?问懵了,尼恩来一个 图解+秒懂+史上最全的答案
阿里面试:PS+PO、CMS、G1、ZGC区别在哪?什么是卡表、记忆集、联合表?问懵了,尼恩来一个 图解+秒懂+史上最全的答案
|
9月前
|
自然语言处理 JavaScript 前端开发
当面试官再问我JS闭包时,我能答出来的都在这里了。
闭包(Closure)是前端面试中的高频考点,广泛应用于函数式编程中。它不仅指函数内部定义的函数,还涉及内存管理、作用域链和垃圾回收机制。闭包可以让函数访问其外部作用域的变量,但也可能引发内存泄漏等问题。通过合理使用闭包,可以实现模块化、高阶函数和回调函数等应用场景。然而,滥用闭包可能导致代码复杂度增加、调试困难以及潜在的性能问题。为了避免这些问题,开发时应谨慎处理闭包,避免不必要的嵌套,并及时清理不再使用的变量和监听器。
408 16
当面试官再问我JS闭包时,我能答出来的都在这里了。
|
10月前
|
JavaScript 前端开发 容器
this、self、window、top 在 JavaScript 中的区别深入研究
在 JavaScript 开发中,`this`、`self`、`window` 和 `top` 是四个常用的概念。`this` 指向当前执行上下文的对象,其值取决于函数调用方式;`self` 在全局作用域中等同于 `window`,常用于 Web Workers;`window` 代表浏览器窗口,是全局变量的容器;`top` 指向最顶层窗口,用于判断是否在框架中。理解这些概念有助于编写健壮的代码。
315 1
this、self、window、top 在 JavaScript 中的区别深入研究
|
10月前
|
Java 程序员 调度
Java 高级面试技巧:yield() 与 sleep() 方法的使用场景和区别
本文详细解析了 Java 中 `Thread` 类的 `yield()` 和 `sleep()` 方法,解释了它们的作用、区别及为什么是静态方法。`yield()` 让当前线程释放 CPU 时间片,给其他同等优先级线程运行机会,但不保证暂停;`sleep()` 则让线程进入休眠状态,指定时间后继续执行。两者都是静态方法,因为它们影响线程调度机制而非单一线程行为。这些知识点在面试中常被提及,掌握它们有助于更好地应对多线程编程问题。
448 9
|
8月前
|
移动开发 运维 供应链
通过array.some()实现权限检查、表单验证、库存管理、内容审查和数据处理;js数组元素检查的方法,some()的使用详解,array.some与array.every的区别(附实际应用代码)
array.some()可以用来权限检查、表单验证、库存管理、内容审查和数据处理等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
8月前
|
供应链 JavaScript 前端开发
通过array.every()实现数据验证、权限检查和一致性检查;js数组元素检查的方法,every()的使用详解,array.some与array.every的区别(附实际应用代码)
array.every()可以用来数据验证、权限检查、一致性检查等数据校验工作,核心在于利用其短路机制,速度更快,节约性能。 博客不应该只有代码和解决方案,重点应该在于给出解决方案的同时分享思维模式,只有思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
10月前
|
安全 Java 程序员
Java面试必问!run() 和 start() 方法到底有啥区别?
在多线程编程中,run和 start方法常常让开发者感到困惑。为什么调用 start 才能启动线程,而直接调用 run只是普通方法调用?这篇文章将通过一个简单的例子,详细解析这两者的区别,帮助你在面试中脱颖而出,理解多线程背后的机制和原理。
510 12
|
10月前
|
编译器 Android开发 开发者
Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
Lambda表达式和匿名函数都是Kotlin中强大的特性,帮助开发者编写简洁而高效的代码。理解它们的区别和适用场景,有助于选择最合适的方式来解决问题。希望本文的详细讲解和示例能够帮助你在Kotlin开发中更好地运用这些特性。
253 9
|
11月前
|
存储 缓存 安全
只会“有序无序”?面试官嫌弃的List、Set、Map回答!
小米,一位热衷于技术分享的程序员,通过与朋友小林的对话,详细解析了Java面试中常见的List、Set、Map三者之间的区别,不仅涵盖了它们的基本特性,还深入探讨了各自的实现原理及应用场景,帮助面试者更好地准备相关问题。
282 20