JS面试真题 part4

embedded/2024/9/19 5:44:02/ 标签: 面试, javascript, 类型转换, 拷贝, 字符串, 数组

JS面试真题 part4

  • 16、谈谈JavaScript中的类型转换机制
    • 标准回答:
  • 17、深拷贝拷贝的区别?如何实现深拷贝
    • 标准回答:
  • 18、JavaScript中如何实现函数缓存?函数缓存有哪些应用场景?
    • 标准回答:
  • 19、JavaScript字符串的常用方法有哪些
    • 标准回答:
  • 20、数组的常用方法有哪些
    • 标准回答:

16、谈谈JavaScript中的类型转换机制

自己回答:

基础类型里:

  • 数字和字符串==比较,字符串转为数字比较。加号+运算,数字转字符串
  • 布尔和数字比较,布尔转成数字
  • 引用类型,转成valueof比较

标准回答:

常见的类型转换有:

  • 强制转换(显示转换)
  • 自动转换(隐式转换)

强制转换(显示转换):我们很清楚看见发生类型转换,常见的方法有:

  • Number()
  • parseInt()
  • String()
  • Boolean()

自动转换(隐式转换):

  • 比较运算符(==!=><)、ifwhile需要布尔值的地方
  • 算木运算(+-*/%

1、自动转换为布尔值
在需要布尔值的地方,将非布尔值转为布尔值,比如if,while

  • undefined
  • null
  • false
  • +0
  • -0
  • NaN
  • “”
    除了上面几种会被转成false,其他转成true

2、自动转换为字符串

遇到预期为字符串的地方,就会将非字符串的值自动转为字符串
常发生在+运算中,一旦存在字符串,就会进行字符串拼接操作

javascript">'5' + 1 // '51'
'5' + true // "5true"
'5' + false // "5false"
'5' + {} // "5[object Object]"
'5' + [] // "5"
'5' + function (){} // "5function (){}"
'5' + undefined // "5undefined"
'5' + null // "5null"

3、自动转换成数值
除了+有可能转为字符串,其他运算符转成数值

javascript">'5' - '2' // 3
'5' * '2' // 10
true - 1 // 0
false - 1 // -1
'1' - 1 // 0
'5' * [] // 0
false / '5' // 0
'abc' - 1 // NaN
null + 1 // 1
undefined + 1 // NaN

null转为数值时,值为0,undefined转为数值时,值为NaN

17、深拷贝拷贝的区别?如何实现深拷贝

自己回答:
基础数据存在栈里,引用类型存在堆里,引用类型的地址存在栈里,深拷贝和浅拷贝是对于引用类型来说,深拷贝是将堆里的数据拷贝一份,浅拷贝拷贝引用类型存在栈里的地址,新旧地址指向同一个堆数据
实现:
最常用 JSON.parse(JSON.stringify(obj))
或者遍历循环赋值

标准回答:

基本类型数据保存在栈内存中,引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中。

拷贝 创建新数据,这个数据有原始数据属性值的一份精确拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址。即浅拷贝拷贝一层,深层次的引用类型则共享内存地址

实现浅拷贝

javascript">function shallowClone(obj) {const newObj = {};for(let prop in obj) {if(obj.hasOwnProperty(prop)){newObj[prop] = obj[prop];}}return newObj;
}

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

  • Object.assign
  • Array.prototype.slice(),Array.prototype.concat()
  • 使用拓展运算符实现的复制

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

常见的深拷贝对象有:

  • _.cloneDeep()
  • jQuery.extend()
  • JSON.stringify()
  • 手写循环递归

区别:
拷贝和深拷贝都是创建一个新的对象,但是在复制对象属性的时候,行为就不一样,浅拷贝只复制属性指向某个对象的指针,而不是复制对象本身,新旧对象还是共享同一颗内存,修改对象属性会影响原对象

javascript">const obj1 = {name : 'init',arr : [1,[2,3],4],arr2: [1,[2,3],4],};const obj3=shallowClone(obj1) // obj3.name = "update";obj3.arr[1] = [5,6,7] ; // console.log('obj1',obj1) // obj1 { name: 'init', arr: [ 1, [ 5, 6, 7 ],4 ], arr2: [ 1, [3,4,2],4 ] }console.log('obj3',obj3) // obj3 { name: 'update', arr: [ 1, [ 5, 6, 7 ],4 ], arr2: [ 1, [3,4,2],4 ] }const obj2=obj1obj2.name = "222";obj2.arr2[1] = [3,4,2] ; // obj2 { name: '222',, arr: [ 1, [ 5, 6, 7 ],4 ],  arr2: [ 1, [3,4,2],4 ] }console.log('obj2',obj2)

赋值的话不管改变的是基础类型还是引用类型,新数据的改变都会影响原数据,浅拷贝拷贝了一层,基础数据不会变
拷贝会另外创造一个一模一样的对象,新对象跟原对象不共享内存,修改新对象不会改到原对象

javascript">// 深拷贝
const obj1 = {name : 'init',arr : [1,[2,3],4],
};
const obj4=deepClone(obj1) // 
obj4.name = "update";
obj4.arr[1] = [5,6,7] ; // 
console.log('obj1',obj1) // obj1 { name: 'init', arr: [ 1, [ 2, 3 ], 4 ] }
console.log('obj4',obj4) // obj4 { name: 'update', arr: [ 1, [ 5, 6, 7 ],
4 ] }

小结:
拷贝类型是引用类型的情况下:

  • 拷贝拷贝一层,属性为对象时,浅拷贝是复制,两个对象指向同一个地址
  • 拷贝是递归拷贝深层次,属性为对象时,深拷贝是新开栈,两个对象指向不同的地址

18、JavaScript中如何实现函数缓存?函数缓存有哪些应用场景?

自己回答:
函数缓存?

标准回答:

函数缓存,就是函数运算过的结果进行缓存
本质就是用空间(缓存存储)换时间(计算过程)
常用于缓存数据计算结果和缓存对象

javascript">const add = (a,b) => a+b;
const calc = memoize(add); // 函数缓存
calc(10,20);// 30
calc(10,20);// 30 缓存

缓存只是一个临时的数据存储,它保存数据,以便将来对该数据的请求能够更快地得到处理

如何实现
实现函数缓存主要依靠闭包、柯里化、高阶函数,这里再简单复习下:
闭包: 函数+函数体内可访问的变量总和

javascript">(function() {var a = 1;function add() {const b = 2let sum = b + aconsole.log(sum); // 3}add()
})()

add函数本身,以及其内部可访问的变量,即 a=1,这两个组合在一起就形成了闭包

柯里化:
把接受多个参数的函数转换成接受一个单一参数的函数

javascript">  // 非函数柯里化var add = function (x,y) {return x+y;}add(3,4) //7// 函数柯里化var add2 = function (x) {//** **return function (y) {return x+y;}}add2(3)(4) //7

将一个二元函数拆分成两个一元函数

高阶函数:
通过接收其他函数作为参数或返回其他函数的函数

javascript">function foo(){var a = 2;function bar() {console.log(a);}return bar;
}
var baz = foo();
baz();//2

函数foo返回另一个函数bar,baz持有对foo中定义的bar函数的引用,由于闭包特性,a的值能够得到。

开始实现函数函数。原理:把参数和对应的结果数据存在一个对象中,调用时判断参数对应的数据是否存在,存在就返回对应结果,否则就返回计算结果

javascript">const memoize = function (func, content) {let cache = Object.create(null)content = content || thisreturn (...key) => {if (!cache[key]) {cache[key] = func.apply(content, key)}return cache[key]}
}
const calc = memoize(add);
const num1 = calc(100,200)
const num2 = calc(100,200) //缓存得到的结果

过程分析:

  • 在当前函数作用域定义了一个空对象,用于缓存运行结果
  • 运用柯里化返回一个函数,返回的函数由于闭包特性,可以访问到 cache
  • 然后判断输入参数是不是在 cache 中。如果已经存在,直接返回 cache 的内容,如果没有存在,使用函数 func对输入参数求值,然后把结果存储在 cache

应用场景:

虽然使用缓存效率非常高,但并不是所有场景都适用
以下几种情况,适合使用缓存:

  • 对于昂贵的函数调用,执行复杂计算的函数
  • 对于具有有限且高度重复输入范围的函数
  • 对于具有重复输入值的递归函数
  • 对于纯函数,既每次使用特定输入调用时返回相同的函数

19、JavaScript字符串的常用方法有哪些

自己回答:string:chart、splitte、slite、

标准回答:

1、

  • concat()

2、

  • slice()
  • substr()
  • substring()

这三个都返回一个子字符串,都接收一或两个参数

javascript"> let stringValue = "hello world";
console.log(stringValue.slice(3)); // "lo world"
console.log(stringValue.substring(3)); // "lo world"
console.log(stringValue.substr(3)); // "lo world"
console.log(stringValue.slice(3, 7)); // "lo w"
console.log(stringValue.substring(3,7)); // "lo w"
console.log(stringValue.substr(3, 7)); // "lo worl"

3、

  • trimLeft()、trimRight() 、trim() 删除前、后、前后空格符,返回新字符串
  • repeat() 重复几次
  • padStart()、padEnd() 指定字符串长度,如果小于指定长度,第二个参数可以指定填充的字符
  • toLowerCase()、toUpperCase() 大小写转化

4、

  • chatAt() 返回给定索引位置的字符
  • indexOf() 返回传入字符的位置,没找到返回-1
  • startWith() 是否以传入字符串为开头,返回布尔值
  • includes() 是否含有传入发字符串,返回布尔值

5、转化(字符转数组

  • split
javascript">let str = "12+23+34"
let arr = str.split("+") // [12,23,34]

6、模板匹配方法

  • match() 匹配
  • search() 查找匹配的索引
  • replace()、replaceAll()、匹配替换

match:接收一个参数,可以是正则表达字符串,也可以是RegExp对象(提供正则表达式),返回匹配的数组

javascript">	let text = "cat, bat, sat, fat";let pattern = /.at/;let matches = text.match(pattern);console.log(matches[0]); // "cat"

search:接收一个参数,可以是正则表达字符串,也可以是RegExp对象(提供正则表达式),返回匹配索引

javascript">   let text = "ca3t, bat, sat, fat";let pos = text.search(/at/);console.log(pos); // 7

replace、replaceAll:接收两个参数,第一个参数为匹配的内容,第二个参数为替换的元素

javascript">        let text = "cat, bat, sat, fat";let result = text.replace("at", "ond");console.log(result); // "cond, bat, sat, fat"let resultall = text.replaceAll("at", "ond");console.log(resultall); // "cond, bond, sond, fond"

20、数组的常用方法有哪些

自己回答:foreach、map、find、inclued、fitter、concat、push、pop、shift、unshift、join、flat、

标准回答:

分为

  • 操作方法:
    • 增:push、unshift、splice(要删除的位置设为0,为新增)、concat(不会改变原数组
    • 删:pop、shift、splice、slice(不会改变原数组
    • 改:splice
    • 查:indexOf、includes、find
  • 排序方法
    • reverse() 反转数组
    • sort() 排序
  • 转换方法
  • 迭代方法
    • some() 对数组每一项都运行传入测试函数,至少有个一个元素返回true,则方法返回true
    • every() 对数组每一项都运行传入测试函数,如果所有元素都返回true,则方法返回true
    • forEach() 对数组每一项都运行传入的函数,没有返回值
    • filter() 对数组每一项都运行传入的函数,函数返回true的项组成数组之后返回
    • map() 对数组每一项都运行传入的函数,返回每次函数调用的结果构成的数组

http://www.ppmy.cn/embedded/110417.html

相关文章

数据结构——链表

目录 一、链表是什么 二、链表的打印 1.如何走向下一个节点&#xff1f; 2.循环的结束条件是什么&#xff1f; 3.链表遍历代码实现 三、链表的尾插 1.尾插的逻辑及函数参数为什么要传二级指针&#xff1f; 2.尾插的代码 四、链表的尾删 五、链表的头插 六、链表的头…

k8s用StatefulSet部署redis

redis-config.yaml &#xff08;配置文件&#xff09; apiVersion: v1 kind: ConfigMap metadata:name: redis-config data:redis.conf: |# Redis general configuration​ bind 0.0.0.0 ​ protected-mode no ​ port 6379 ​ dir /data ​ appendonly yesse…

Android audioRecord 获取实时音频可视化

Android audioRecord 获取实时音频可视化 在Android开发中,音频处理是一个常见的需求,尤其是在音乐播放器、录音应用或者语音识别等领域。本文将介绍如何使用Android的AudioRecord类来获取实时音频数据,并将其可视化展示。通过这种方式,我们可以更直观地了解音频信号的强度…

Java面试八股文

目录 Java基础 1、Hashmap底层原理 2、如何解决哈希冲突 2.1你知道HahsMap死循环问题吗 &#xff1f; 3、Concurrenthashmap 为什么是线程安全的&#xff1f; TreeMap,HashMap,LinkedHashMap 的区别&#xff1f; 4、super和this的共同点的区别 5、final关键字 6、集合…

软件测试学习笔记丨Docker 安装、管理、搭建服务

本文转自测试人社区&#xff0c;原文链接&#xff1a;https://ceshiren.com/t/topic/32192 容器&#xff08;Docker&#xff09;技术的价值 保证环境一致性&#xff0c;只要使用相同镜像部署就可以保证一致性。轻量级虚拟化访问&#xff0c;运行更快&#xff0c;资源更小。同时…

MongoDB入门教程

这是本人制作的《MongoDB入门教程》PDF版本&#xff0c;包含了MongoDB基本概念&#xff0c;下载安装&#xff0c;文档增删改查&#xff08;CRUD&#xff09;&#xff0c;管道聚合操作&#xff0c;索引优化以及数据导入导出等内容。 这个教程可以帮助初学者从零蛋开始学习Mongo…

633. 平方数之和-LeetCode(C++)

633. 平方数之和 2024.9.11 题目 给定一个非负整数 c &#xff0c;你要判断是否存在两个整数 a 和 b&#xff0c;使得 a2 b2 c 。 0 < c < 2的31次方 - 1 示例 示例 1&#xff1a; 输入&#xff1a;c 5 输出&#xff1a;true 解释&#xff1a;1 * 1 2 * 2 5示…

如何显示Dialog窗口

文章目录 1. 概念介绍2. 使用方法2.1 Overlay效果2.1 Dialog效果 3. 示例代码4. 内容总结 我们在上一章回中介绍了"使用get显示snackBar"相关的内容&#xff0c;本章回中将介绍使用get显示Dialog.闲话休提&#xff0c;让我们一起Talk Flutter吧。 1. 概念介绍 我们在…

基于SpringBoot+Vue+MySQL的房屋租赁管理系统

系统展示 用户前台界面 管理员后台界面 系统背景 二十一世纪互联网的出现&#xff0c;改变了几千年以来人们的生活&#xff0c;不仅仅是生活物资的丰富&#xff0c;还有精神层次的丰富。在互联网诞生之前&#xff0c;地域位置往往是人们思想上不可跨域的鸿沟&#xff0c;信息的…

滑动窗口在算法中的应用

滑动窗口是一种经典的算法技巧&#xff0c;就像在处理一系列动态数据时&#xff0c;用一扇可以滑动的“窗口”来捕捉一段连续的子数组或子字符串。通过不断地移动窗口的起点或终点&#xff0c;我们能够以较低的时间复杂度来解决一系列问题。在这篇文章中&#xff0c;我们将通过…

Linux(驱动中) 时间管理和内核定时器(学习总结)

在Linux内核中&#xff0c;时间管理和内核定时是非常重要的功能&#xff0c;用于实现定时任务、延时操作和周期性事件处理等。内核提供了多种机制来处理时间相关的任务&#xff0c;包括软件定时器&#xff08;software timers&#xff09;、硬件定时器&#xff08;hardware tim…

【Hot100】LeetCode—70. 爬楼梯

目录 1- 思路动规五部曲 2- 实现⭐763. 划分字母区间——题解思路 3- ACM 实现 原题链接&#xff1a;70. 爬楼梯 1- 思路 动规五部曲 1- dp 数组创建&#xff0c;确定含义 dp[i] 代表到达 楼梯 i 的方法数 2- 状态转移方程 因为一共有两种移动的方式&#xff0c;当前 dp[i] …

cat:显示文本内容

‍ 1.简介 ​cat​ 不是猫猫。cat​命令是一个在 Unix 和类 Unix 操作系统中用来查看文件内容的命令。它的名称来源于 concatenate&#xff08;连接&#xff09;的缩写&#xff0c;最初的作用是连接文件&#xff0c;但它也可以用来显示文件内容、创建文件、文件合并以及输出文…

FTP、SFTP安装,整合Springboot教程

文章目录 前言一、FTP、SFTP是什么&#xff1f;1.FTP2.SFTP 二、安装FTP1.安装vsftp服务2.启动服务并设置开机自启动3.开放防火墙和SELinux4.创建用户和FTP目录4.修改vsftpd.conf文件5.启动FTP服务6.问题 二、安装SFTP总结 前言 在一般项目开发工程中&#xff0c;我们大多数会…

如何使用elementui实现一个根据页面进度实时增长/前进的进度条

如何使用elementui实现一个根据页面进度实时增长/前进的进度条&#xff0c;当用户点击已完成进度条部分的任何一个值时&#xff0c;例如已完成70%点击35%可以跳到35%时对应的页面呢&#xff1f; <template><div><el-progress :percentage"progressPercent…

Linux审计系统软件auditd简介

Linux审计系统软件auditd是一个强大的工具&#xff0c;用于监控和记录安全相关的信息。它最初是基于Linux 2.6.11.12版本内核开发的&#xff0c;主要的审计机制代码位于kernel/audit.c和kernel/auditsc.c中[^4]。auditd可以记录系统调用和文件访问等事件&#xff0c;帮助系统管…

协议头,wireshark,http

目录 协议头 ip头 udp头 mac层 网络工具 telnet wireshark Http 一、HTTP 协议介绍 二、HTTP 协议的工作过程 三、使用抓包工具抓取报文 四、获取到http请求报文&#xff1a; 五、http请求&#xff08;request&#xff09; &#xff08;一&#xff09;、认识URL 项…

基于SpringBoot的宠物寄领养网站管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【前后端分离】基于JavaSpringBootVueMySQL的宠物寄领养网站…

Ribbon简介

Ribbon是一个由Netflix开发的客户端负载均衡器&#xff0c;广泛用于微服务架构中&#xff0c;以提高系统的可用性和伸缩性。它通过在客户端应用程序中实现负载均衡逻辑&#xff0c;允许开发人员根据不同的需求选择或定制合适的负载均衡策略。 Ribbon的核心组件包括&#xff1a…

C++当中的多态(一)

&#xff08;一&#xff09;什么是多态 1.现实中的多态&#xff1a; 所谓的多态在我们的生活当中其实很常见。举一个简单的例子&#xff1a;当我们需要买票的时候有很多种不同的票可以供我们购买&#xff0c;如果你是学生就可以享受半价票的优惠&#xff0c;如果你是VIP用户就可…