2024年前端面试第一版问题(附答案和代码解析)

大家好,相信很多朋友在面试过程中遇到过这些问题,也查阅了很多相关资料,发现很多的教学都是copy复制,完美的展现了程序员的“优良传统”~开个小玩笑嘿嘿,今天我们就去看看这些问题到底是怎么个事!在工作中什么情况下会遇到?如何解决他们产生的问题~那么废话不多说!我们走起!

1、作用域的概念

什么是作用域?什么情况下我们会遇到?很简单,同学们看一下代码就懂了

// 定义一个名为outer函数
function outer() {  

  // 函数内部定义一个名为X,值为10的变量
  var x = 10; 
  
  // 在函数内部定义内部函数
  function inner() { 

    var y = 5; // 在内部函数中定义名为Y,值为5的函数
    console.log(x + y);  // 输出 15

  }
  
  // 在outer函数中调用inner函数
  inner(); 
}

// 执行outer函数
outer(); 

// 错误提示 :在外部无法调用函数内部的变量和内部函数,因为超出了作用域,变量X和Y只在函数内部中使用。
 

在这个例子中,outer函数中定义了一个变量x。然后,outer函数内部又定义了一个函数inner,并在inner函数内部定义了一个变量y。在inner函数中,我们可以访问并使用来自outer函数作用域的变量x。当我们调用outer函数时,它会执行inner函数并输出xy的和,即15

这个案例展示了JavaScript的作用域链特性,即内部函数可以访问外部函数中定义的变量。在这个例子中,inner函数可以访问和使用outer函数中定义的变量x。这种嵌套的作用域关系允许我们在函数内部创建私有变量,同时保护这些变量不被外部访问到。

2、原型链的概念

原型链是什么?可以解决什么问题?我们从这两个问题出发!

原型链是 JavaScript 中的一个重要概念,它决定了对象之间如何继承属性和方法。

当我们声明一个函数时,会自动生成prototype等价于obj._proto_,它指向了另一个对象,我们称之为原型对象。当我们访问一个对象的属性或方法时,JavaScript 引擎会首先在该对象本身上查找,如果找不到,则继续在原型对象上查找,如果还找不到,则继续在原型对象的原型对象上查找,依次类推,直到找到属性或方法或达到原型链的末端。

当我们把原型串联在一起的时候,它就称之为“原型链”,原型链的顶端为null~

解决了对象共享属性和方法

3、闭包的概念

什么是闭包?在什么情况下我们会用到?闭包给我们带来什么好处?闭包的缺点在哪?如何解决?我们先来看 两个经典的案例!

一、案例一:
function outer() {
  var x = 10;

  function inner() {
    console.log(x);
  }

  return inner;
}

var innerFunc = outer();
innerFunc(); // 输出 10
 

在上面的代码中,inner函数被定义在outer函数内部,并且在outer函数的外部被调用。

当调用outer函数时,它返回了内部函数inner的引用。由于inner函数的作用域链仍然保留着对outer函数作用域的引用,所以在调用inner函数时,它仍然可以访问和使用outer函数的局部变量x

这就是闭包的经典案例,通过闭包,我们可以在函数外部访问到函数内部的变量。

二、案例二:
for (var i = 0; i < 5; i++) {
  setTimeout(function() {
    console.log(i); // 期望的输出:0,1,2,3,4
  }, 1000);
}

这段代码中,就会遇到一个问题,我们期望的输出是0,1,2,3,4,每隔1秒输出一个数字。然而,实际上输出的结果是5,5,5,5,5。这是因为setTimeout是异步的,js会先执行同步代码,后执行异步代码,当计时器到期时,for循环已经执行完毕,并且i的值已经变为5。因此,在闭包函数中访问的是同一个i,它的值始终是5, 重点来了我们如何解决呢? 有聪明的小伙伴说:我可以用es6中的let啊,对!我也是这么想的,既然人家都已经解决了,还非得问这些问题,很无奈啊,所以我们还得知其所以然,我们就当做没有se6,我们就是远古的开发战士!如何解决这个问题?

三、闭包所带来的问题

for (var i = 0; i < 5; i++) {
  (function(i) {
    setTimeout(function() {
      console.log(i); // 输出的结果为 0, 1, 2, 3, 4
    }, 1000);
  })(i);
}
 

在这个修正后的代码中,通过使用立即执行函数(IIFE)创建了一个新的作用域,并将当前的i的值作为参数传入该函数。这样,在每次循环中,都会创建一个新的闭包,而不是共享同一个变量i。

大家请仔细观看上面的代码还会有问题吗?3秒钟回答~

是的,依然还是存在使用闭包后存在的问题

1、我们所声明的变量会存在内存中,无法被回收掉,所以会导致大量的内存占用。我们应该优化一下~

解决方案:需要把闭包的函数设置为Null

2、内存泄露的问题只会出现在远古版本的IE浏览器(这个可回答,可不回答,如果面试官问到了,一定要把内存泄露在特定的浏览器上才会出现的问题指出!)

闭包的总结:

闭包是指一个函数内部定义的函数,该函数可以访问外部函数的变量。由于闭包会保留外部函数的变量和作用域链,因此可能会导致内存占用问题。

以下是一些解决闭包带来的内存占用问题的方法:

1. 避免过度使用闭包:只有在必要的情况下使用闭包,避免不必要的内存占用。

2. 及时释放闭包:当不再使用闭包时,手动将其置为null,以释放内存。

3. 使用箭头函数:箭头函数是匿名函数的简写形式,它没有自己的this值和arguments对象,并且不能作为构造函数使用。由于箭头函数没有自己的作用域,因此不会产生闭包,也不会导致内存占用问题。

4. 使用事件解绑:当使用闭包来处理事件时,确保在不需要时解绑事件,避免事件处理函数一直保留在内存中。

5. 使用模块化开发:将代码拆分成多个模块,通过导入和导出来引用变量,避免使用闭包。

6. 使用WeakMap对象:使用WeakMap对象来存储闭包中的变量,WeakMap对象的键是弱引用,当其他对象不再引用某个对象时,该对象会被垃圾回收。

总之,要解决闭包带来的内存占用问题,需要合理使用闭包,及时释放闭包,使用箭头函数等方法。

4、浅拷贝/深拷贝

浅拷贝:只复制引用,并没有复制真正的值

例如:

let arr1 = [1,2,3]
let arr2 = arr1

arr1[0] = 4
arr2[1] = 5

conslo.log(arr1,arr2)
// 输出结果
// [4,5,3]

深拷贝: 深拷贝是指创建一个完全独立的对象,与原对象拥有相同的值但是不共享任何引用。

例如:

function deepCopy(obj) {
  // 首先检查传入的参数是否是对象
  if (typeof obj !== 'object' || obj === null) {
    return obj;
  }
  
  // 创建一个空对象来保存拷贝的结果
  let copy = {};
  
  // 遍历原对象的属性
  for (let key in obj) {
    // 使用递归来拷贝每个属性的值
    copy[key] = deepCopy(obj[key]);
  }
  
  return copy;
}
 

该方法首先检查传入的参数是否是对象,如果不是对象则直接返回参数。然后创建一个空对象用来保存拷贝的结果。接着遍历原对象的属性,并使用递归来拷贝每个属性的值。最后返回拷贝的结果对象。

例如,假设有一个对象 obj

let obj = {
  name: 'John',
  age: 25,
  address: {
    street: '123 Main St',
    city: 'New York',
    state: 'NY'
  }
};
 

可以使用 deepCopy 方法来深拷贝 obj

let copy = deepCopy(obj);
console.log(copy);
 

输出结果将是一个与 obj 值相同但是完全独立的对象。

补充一条:localstorage\ sessionstorage\ cookie的区别?

共同点:在客户端存放特定的数据

区别:

sessionStorage.setItem(key,value)

localStorage.setItem(key,value)

document.cookie

localstorage:持久化存储页面关闭再次打开页面依然存在数据。

sessionstorage:当浏览器关闭就会失效。

cookie:可自定义cookie的到期时间,默认为半个小时。

小伙伴们看完后记得给一个免费的赞叭~你们的鼓励对我真的很重要  : ) 

  • 9
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

仔仔 v1.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值