原生js面试题(一)

一、深拷贝和浅拷贝
  - 1 js的数据类型 基本类型和复杂类型
  - 2 堆和栈 基本类型的值和复杂类型的地址存在栈中,复杂类型的地址指向堆中的内存
  - 3 深拷贝和浅拷贝的概念 深拷贝的前提是复杂类型的复制

  - 4 举例说明
  如果有个变量a和一个变量b 如果a是一个对象 此时let b = a a中的属性发生变化
  则b中的属性也会发生变化,原因是因为赋值的过程中他们a,b都
  指向堆中同一块内存空间,因此他们的属性会一起改变,这就是一个浅拷贝的过程
  深拷贝就是使得a和b指向不同的内存空间 互不影响

  - 5 实现方式
  通常我在开发中一般使用json.stringify 去将对象转为字符串 再通过json.parse
  转为对象 这样实现一个简单的深拷贝,但是这个有一定的缺陷(什么缺陷?),所以
  在特定情况下我会自己封装一个深拷贝的函数完成深拷贝!

var deepClone = function(obj) {
  if (typeof obj !== 'object') return;
  var newObj = obj instanceof Array ? [] : {};
  for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
      newObj[key] = typeof obj[key] === 'object' ? deepClone(obj[key]) :
      obj[key];
    }
  }
  return newObj;
}

  

二、原型\原型链\构造函数

  显式原型:prototype

  隐式原型:__proto__

  - 1 构造函数才有显式原型 String.prototype 对 str.prototype错!
  let str; //没有原型
  let str = new String()

  - 2 原型本质上是个对象

  - 3 构造函数(constructor)其实就是new关键字后面那个函数

  - 4 只有对象才有隐式原型(__proto__)

  - 5 普通对象的隐式原型(__proto__)等于构造函数的显示原型(prototype),普通对象就可以调用构造函数的
  原型方法,原型本质上是个对象,只要是对象就会有隐式原型,如果一个__proto__找不到需要的原型方法他可以
  一直向上找,直到为null为止,这个形成的就称为原型链

 

三、promise

  - 1 Promise是一个构造函数(class) 生成promise的实例对象用来解决异步
  - 2 Promise 是一个只要存在就有结果 状态有三个 resolve成功 reject失败 pending 等待
  - 3 可以解决传统的异步编程嵌套太多带来的回调地狱的问题 可以使用链式调用以同步的方式呈现
  - 4 通常可以使用Promise对一些异步编程进行封装
  有些Promise内置的函数可以提供相应的扩展 如.all的方法可以使得发送多个请求

 

四、宏任务和微任务

  -1  js 代码的执行顺序是按照代码书写的先后顺序执行的
  -2 如果代码出现阻塞或者代码运行时间过长怎么办?
  -3 如果发生异步请求,等待异步结果返回再接着执行

  在js中任务分为宏任务和微任务,分别各自维护一个队列
  均采用先进先出的原则,***同步的任务在宏任务上执行!!!***

    宏任务:script中代码,setTimeout,setInterval,

    微任务:Promise.then(),process.nextTick()-node环境中

 

五、事件循环机制(eventloop)
  -1 先从宏任务中的头部取出一个任务执行
  -2 执行过程中如果遇到微任务怎将其添加到微任务的列表中
  -3 宏任务执行完毕以后看微任务队列中是否存在任务如果存在则挨个执行,直到全部执行完毕
  -4 渲染页面(GUI渲染)
  -5 回到第一步直到宏任务全部执行完毕

 

六、闭包(简单说下闭包?你了解闭包? )

  闭包的概念:函数嵌套函数且在内部函数中可以访问外部函数作用域中的变量就称为闭包.
  首先,js中的作用域分为全局作用域和局部作用域,全局作用域任何地方都可以访问,

  但是局部作用域只能在局部或者函数内部才可以访问.

  然后,有时候需要得到函数内的局部变量,但是在正常情况下,这是不能读取到的,这时候就需要用到闭包.


  ①闭包形成的条件
    1.函数嵌套
    2.内部函数引用外部函数的变量

  ②闭包的使用场景
    1.防抖和节流
    2.延长的变量的生命周期


  闭包的优缺点去谈垃圾回收机制
  // GC 垃圾回收机制 js在运行的过程中如有不用的变量或者用完的变量会被回收
  JavaScript中的垃圾回收机制主要有两种:
    标记清除算法(Mark-and-Sweep)和引用计数(Reference Counting)。
  标记清除是JavaScript中主流的垃圾回收算法,而引用计数则已经很少被使用。

  实现标记清除(Mark-and-Sweep)算法的主要步骤如下:

    -1 创建一个根对象,例如window对象;
    -2 遍历根对象及其所有引用的对象,并标记它们是可达对象;
    -3 遍历内存中所有对象,如果发现某个对象未被标记,就将其清除。
    -4 在JavaScript中,标记清除算法是由浏览器自动完成的,开发者无需手动实现。

 

七、防抖、节流

  -1 防抖:在一段时间内如果再次触发,则会重新计时,直到你不触发,展示最后一次触发的事件

let debounce = function (handler,delay) {
    let timer=null;
    return function () {
        if(timer) clearTimeout(timer);
        timer = setTimeout(()=>{
            fn.apply(this,arguments)
        },delay)
    }
}

  

  -2 节流:在一段时间内只能触发一次,如果重复触发不管用只有等时间过完才会再触发

let throttle = function(handler,delay) {
    let timer = null;
    return function () {
        if(timer) return;
        timer = setTimeout(() => {
            fn.apply(this,arguments)
            timer = null
        })
    }
}

  

  应用场景:
    ①防抖:
      search搜索联想,用户在不断输入值时,用防抖来减少http请求,提升性能
      window触发resize的时候,不断的调整浏览器窗口大小会不断的触发这个事件,用防抖来让其只触发一次

    ②节流:
      鼠标不断点击触发,mousedown(单位时间内只触发一次)
      监听滚动事件,比如是否滑到底部自动加载更多

 

posted @ 2023-10-09 14:25  祢豆子_persist  阅读(220)  评论(0)    收藏  举报