1.谈谈JS的类型转换机制
1.显示转换 --> (方法触发) such as: Number、String、Boolean、ParseInt
2.隐式转化 -->(计算时触发)
2.深拷贝浅拷贝的区别?如何实现一个深拷贝?
1.浅拷贝
(1.1)浅拷贝是拷贝基本数据的值和拷贝复杂数据的地址,当原数据或者拷贝数据其中之一发生变化时,两者都会改变。
(1.2)实现方式:Object.assign() 注意:当原数据只有一层时,该方法是深拷贝。
2.深拷贝
(2.1)深拷贝是开辟一个新的空间存储原数据的初始数据,当原数据或者拷贝数据其中之一发生变化时,两者互不干扰。
(2.2)实现方式:JSON.parse(JSON.stringify(obj))、或者写个循环递归函数。
3.说说对闭包的理解
1.函数套函数
2.作用:创建私有变量、延长变量的生命周期
4.说说你对作用域链的理解
1.一般将作用域分成:全局作用域、函数作用域、块级作用域
2.由局部作用域向上查找、直到找到全局作用域的整个过程形成一种链式结构叫做作用域链。
5.JavaScript原型,原型链 ?
1.每个对象的__proto__都是指向它的构造函数的原型对象prototype的
person1.__proto__ === Person.prototype
2.构造函数是一个函数对象,是通过 Function构造器产生的
Person.__proto__ === Function.prototype
3.原型对象本身是一个普通对象,而普通对象的构造函数都是Object
Person.prototype.__proto__ === Object.prototype
4.刚刚上面说了,所有的构造器都是函数对象,函数对象都是 Function构造产生的
Object.__proto__ === Function.prototype
5.Object的原型对象也有__proto__属性指向null,null是原型链的顶端
Object.prototype.__proto__ === null
6.下面作出总结:
一切对象都是继承自 Object 对象,Object 对象直接继承根源对象null
一切的函数对象(包括 Object 对象),都是继承自 Function 对象
Object 对象直接继承自 Function 对象
Function对象的__proto__会指向自己的原型对象,最终还是继承自Object对象
6.typeof与instance of的区别?Object.prototype.toString.call的使用
1.typeof 会返回一个变量的基本类型 <--> instanceof 返回的是一个布尔值
2.typeof 能检测除null外的基本数据类型,引用类型除了function外都不能检测。 <--> instanceof 只能检测复杂数据类型。
3.Object.prototype.toString.call() 的使用
function getType(obj) {
let type = typeof obj;
if (type !== "object") {
return type;
}
return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');
}
console.log(null)
console.log(undefined)
console.log([])
console.log({})
console.log(function(){})
7.ajax原理是什么?如何实现?
1.原理:通过XmlHttpRequest对象来向服务器发异步请求,从服务器获得数据,然后用JavaScript来操作DOM而更新页面
2.如何实现?
(2.1)创建XMLHttpRequest对象 const xhr = new XMLHttpRequest();
(2.2)与服务器建立连接 xhr.open(method, url, [async][, user][, password])
(2.3)给服务端发送数据 xhr.send([body])
(2.4)绑定onreadystatechange事件
request.onreadystatechange = function(e){
if(request.readyState === 4){
if(request.status >= 200 && request.status <= 300){
console.log(request.responseText)
}else if(request.status >=400){
console.log("错误信息:" + request.status)
}
}
}
8.bind、call、apply 区别?
1.第一个参数为undefined或者null,默认指向全局window。
2.call是参数列表,apply是参数数组,bind都可。
3.call、apply是一次性传入参数,bind可多次传入。
4.call、apply会立即执行一次函数,bind会返回一个改变this指向后的函数。
call/apply: fn.call(obj, options) / fn.aplly(obj, [options])
bind: const resFn = fn.bind(obj, 1/[options])
resFn() / fn.bind(obj, 1/[options])()
9.说说你对事件轮询(事件循环) EventLoop 的理解
1.JS代码执行的一种机制。
2.微任务:Promise.then()、MutaionObserver、Proxy、process.nextTick(Node.js)
3.宏任务:计时器、setImmediate、I/O(Node.js)、
4.执行机制
首先整个JS代码是宏任务,执行完所有同步任务,然后执行异步任务,因为最外层是宏任务,所以从微任务开始执行,清空全部微任务,再 进入下一次宏任务,执行完宏任务,然后再判断是否有微任务,没有则进行下一次宏任务,有则清空微任务,直到所有宏、微任务清空 完为止,最后执行宏任务。
例子:
console.log(1)
setTimeout(()=>{
console.log(2)
}, 0)
new Promise((resolve, reject)=>{
console.log('new Promise')
resolve()
}).then(()=>{
console.log('then')
})
console.log(3)
10.说说你对尾递归的理解。有哪些应用场景?
1.什么是尾递归?在函数尾部调用的是函数自身
例如:(1.1)普通递归
function factorial(n) {
if (n === 1) return 1;
return n * factorial(n - 1);
}
factorial(5)
(1.2) 尾递归
function factorial(n, total) {
if (n === 1) return total;
return factorial(n - 1, n * total);
}
factorial(5, 1)
2.应用场景:阶乘、数组求和、斐波那契
11.什么是内存泄漏?垃圾回收机制是什么?说说JS中内存泄漏的几种情况?
1.什么是内存泄漏?
由于疏忽或错误造成程序未能释放已经不再使用的内存
2.不及时释放内存会有什么影响?
轻则影响系统性能,重则导致进程崩溃
3.什么是垃圾回收机制? 两种方式:(3.1)标记清除(最常用) (3.2)引用计数
(3.1)回收规则:
1.全局变量不会被回收。
2.局部变量会被回收,也就是函数⼀旦运⾏完以后,函数内部的东西都会被销毁。
3.只要被另外⼀个作⽤域所引⽤就不会被回收 (闭包中引⽤的变量不会被回收)
(3.1)标记清除
例如:function fn() {
let a = 100;
}
fn()
当声明一个fn函数时,进入环境,给a标记‘进入环境’,然后机制会清除所有被标记的变量,当fn()执行后,会给a标记‘离开环 境’,最后垃圾回收机制会释放内存,回收空间。
(3.2)引用计数
例如:const arr = [1, 2, 3, 4];
console.log('hello world');
语言引擎有一张引用表-保存了所有资源的引用次数:数组[1, 2, 3, 4]是一个值,arr是对这个值的引用,所以引用次数是1, 所有它会持续占用内存。
当arr = null;引用次数就变为0,就会被垃圾回收,内存就会被释放。
3.常见内存泄漏情况:定时器、函数内对全局变量的赋值、通过this赋值的全局变量
12.什么是防抖和节流?如何实现?
1.节流: n 秒内只运行一次,若在 n 秒内重复触发,只有一次生效
function throttled2(fn, delay = 500) {
let timer = null
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args)
timer = null
}, delay);
}
}
}
2.防抖: n 秒后在执行该事件,若在 n 秒内被重复触发,则重新计时
function debounce(func, wait) {
let timeout;
return function () {
let context = this;
let args = arguments;
clearTimeout(timeout)
timeout = setTimeout(function(){
func.apply(context, args)
}, wait);
}
}
3.目的都是,降低回调执行频率。节省计算资源
4.应用场景?
防抖在连续的事件,只需触发一次回调的场景有:搜索框搜索输入。只需用户最后一次输入完,再发送请求。
节流在间隔一段时间执行一次回调的场景有:滚动加载,加载更多或滚到底部监听。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?