js相关面试题(总结版)

不属于vue、react、css、html、wepack、项目功能方面的面试题都放这个文档中总结。
(欢迎补充。)

基本变量和引用类型变量

基本数据类型:number、string、boolean、symbol、null、undefined、BigInt

引用数据类型:array、function、Date、Math、正则RegExp

两者之间的区别:

  • 存储位置不同:基本数据类型存储在栈中,引用数据类型在栈中存储地址值、在堆中存储数据
  • 传递方式不同:基本变量值传递;引用数型变量,引用传递。
symbol类型的应用
  • symbol类型是唯一的,可以用来解决命名冲突问题
  • 可以用来作为对象的key值(这时候只能被Obect.getOwnPropertySymbols和Reflect.ownkeys()读取到)
bigInt 类型的应用
  • 用来表示超过number类型数字限制(-2^53 - 1 , 2 ^53 - 1)的数

值传递和引用传递

值传递:函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递:是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

  • 值传递针对基本数据类型,引用传递针对引用数据类型 *

浅拷贝和深拷贝

引用数据类型在栈中存储地址值、在堆中存储数值
深拷贝:在堆中开辟一块新的内存,保存和原对象一模一样的值,因此当原对象改变时,不影响拷贝对象。
浅拷贝:浅拷贝时,只拷贝了一层地址值,所以当拷贝对象改变时,原对象也会改变。

//浅拷贝
 let a = [1,2,3,4,5]
     let b = a;
     b[0] = 999
     console.log(a,b)// [999, 2, 3, 4, 5] , [999, 2, 3, 4, 5]
 //深拷贝
   let a = [1,2,3,4,5]
     let b = JSON.parse(JSON.stringify(a));
     b[0] = 999
     console.log(a,b)// [1, 2, 3, 4, 5] (5) [999, 2, 3, 4, 5] 

forEach 和 map的相同和区别

相同点:

  • 都可以遍历数组
  • 参数相同,第一个参数是数组元素、第二个参数是索引值、第三个参数是原数组

不同点:

  • map返回一个新数组、forEach不返回数据
  • forEach改变原数组、map不改变原数组

数组的迭代方法

返回新数组的:map、filter
改变原数组的:forEach
非空判断:findIndex(有返回索引,没有返回-1)、some(有返回true,没有返回false)、find(有返回true,没有返回undefined)
every(fn):全部符合条件返回true,有一个不符合返回false
累加器:reduce

//reduce使用
let arr = [1, 1, 1, 1, 1, 5];
      let a = arr.reduce((total, currentValue) => {
        return total + currentValue;
      });
      let b = arr.reduce((total, currentValue) => {
        console.log(total, currentValue, "ddsajd");
        // 10 1 'ddsajd'
        // 11 1 'ddsajd'
        // 12 1 'ddsajd'
        // 13 1 'ddsajd'
        // 14 1 'ddsajd'
        // 15 5 'ddsajd'
        return total + currentValue;
      }, 10);
      console.log(a, b); //10 , 20

数组的常用方法

数组转字符串:join,toString

     //有返回值
      let arr = [1,2]
      let a = arr.push(4)//返回数组长度3,添加最后一个元素
      let b = arr.pop() //返回删除的元素2,弹出最后一个元素
      let c = arr.shift()//返回删除的元素1,弹出第一个元素
      let d = arr.unshift(4)//返回数组长度3,添加第一个元素
    //   concat:连接两个数组,返回一个新数组
    //   let f = arr.slice(0,1) // 截取新数组并返回,左闭右开区间


    //改变原数组 
    //sort:数组排序
    //reserve:数组反转
     arr.splice(0,1,2) //start,删除的元素个数,要在删除元素的位置添加的元素

数组去重

数组去重的几种方法

数组排序

数组扁平化

arr.flat()

对象拼接

object.assign(obj1,obj2)

js中 0.1 + 0.2 = 0.3

不等于

js关于浮点数的处理

  • 使用toFixed方法将数字转成一个指定位数的字符串
  • 使用Math.round()
  • 使用 Decimal.js 库
  • 使用 Big.js 库

字符串常用方法(待补)

字符串转数组:split


作用域链

作用域是变量可以合法使用的范围。

作用域分为:块级作用域(const、let)、全局作用域、函数作用域

作用域链是层层嵌套的作用域,形成的由内向外的结构,用来查找变量

变量提升和函数提升

变量提升:js会进行预解析处理,会把变量声明放到最前面执行

函数提升:同理,在函数定义之前,就可以执行该函数

闭包

理解:外部函数内返回一个内部函数,这个内部函数使用外部函数的变量,并且调用了这个外部函数

function outer(){
   let a = 111
	function inner(){
		a++;
		console.log(a)
	}
	return inner
}
let f = outer()
f = null

作用:延长局部变量的生命周期,让函数外部可以使用函数内的变量
缺点:内存泄露

解决办法:赋空值

闭包的使用场景(待补充)

  • 函数的防抖节流
  • 封装私有变量

防抖和节流

防抖:高频触发事件时,只触发最后一次(王者回城、搜索框搜索输入、文本框实时保存文本)

//手写防抖
     function debounce(fn, delay) {
        let timer = null;
        const _debounce = () => {
          if (timer != null) {
            clearTimeout(timer);
          }
          timer = setTimeout(() => {
            fn();
          }, delay);
        };
        return _debounce
      }

节流:高频触发事件时,一段时间只触发一次(王者技能冷却、下拉加载、页面滚动)

//手写节流
 function throttle(fn, delay) {
        let timer = null;
        const _throttle = () => {
          if (timer != null) {
           return ;
          }
          timer = setTimeout(() => {
            fn();
            timer = null
          }, delay);
        };
        return _throttle
      }

关于this的指向

函数直接调用:window
new 一个构造函数 : 指向构造出来的对象
obj.fn() :指向对象obj
使用call、apply: 指向call、apply函数的参数
箭头函数:指向外部的this
回调函数:

  • 定时器、ajax、promise、数组方法回调:指向window
  • vue中的回调函数:指向组件实例
  • react:类组件:组件实例;函数组件:undefined

apply、call、bind的用法和区别

都是用来改变this指向的
apply:function.apply ( this, [a,b,c,…])
call:function.call(thisArg, arg1, arg2, …),call和apply的区别就在于apply传参是数组形式,call是字符串形式
bind:bind会改变this指向后,返回一个绑定新this的函数;

原型和原型链

原型:

1.每个函数都有一个显式原型:prototype
2. 隐式原型:每个实例都有一个隐式原型:proto
3. 实例上的隐式原型和原型都指向同一个原型对象
4. 原型对象包含一个construor和一个隐式原型

原型链:从对象的隐式原型开始,一层层链接所有对象

原型链的使用场景(?)

  1. 继承
  2. 原型扩展
  3. 模块化开发
  4. 原型查找

判断数据类型的几种方式

typeof:判断数组、null、对象时返回的都是 Object。

instanceof:instanceof 是用来 判断数据是否是某个对象的实例,返回一个布尔值。对于基本类型的数据,instanceof是不能直接判断它的类型的,因为实例是一个对象或函数创建的,是引用类型,所以需要通过基本类型对应的 包装对象 来判断。所以对于 null 和 undefined 判断不了。

object.prototype.toString:都能判断。

同步和异步

同步:js是单线程语言,在主线程上的任务只能一项一项任务完成、前一项完不成、后一项只能排队
异步:不进入主线程,而是进入任务队列,宏任务进入宏队列,微任务进入微队列

宏任务和微任务

宏任务:setTimeout 、setInterval 、Ajax 、DOM事件、script(整体代码)
微任务:promise async/await

执行顺序(事件循环-eventloop):script 主线程> script上创建的微任务 > 宏任务中的所有微任务(重复)

具体代码练习参考 一沓纸稿 大佬的原创文章

new操作符做了什么

//手写new操作符
 //Fn为构造函数
      function myNew(Fn) {
        //JS内部首先会先生成一个对象
        let obj = {};
        //使空对象的隐式原型指向构造函数的显式原型
        obj.__proto__ = Fn.prototype;
        // 把函数中的this指向该对象并执行构造函数中的语句
        let res = Fn.apply(obj);
        console.log(res, "res");
        //返回该对象实例
        return res instanceof Object ? res : obj;
      }
        function Person() {
        this.name = "小红";
        this.hhh = "哈哈哈";
      }
      var obj1 = myNew(Person);
      console.log(obj1);

promise(?)

promise是用来解决回调地狱问题的工具,promise对象有三种状态、pending、fullfilled、rejected。promise.then()返回一个新的promise,结果由then指定的函数执行结果而定。

//手写promise(建议面试前写三遍)

promise引申

  • promis.all([p1,p2,p3]) (一荣俱荣,一损俱损)
  • promise.race([p1,p2,p3])(有一个成功,就返回成功)

继承方式(?)

事件冒泡和事件委托

元素之间是相互关联的,当一个元素被触发后、会触发到其他的元素。
事件冒泡:当一个元素接收到事件的时候 会把他接收到的事件传给自己的父级,一直到window。(e.stopPropagation() )
事件委托:事件委托也叫事件代理,“事件代理”即是把原本需要绑定在子元素的响应事件(click、keydown…)委托给父元素,让父元素担当事件监听的职务。事件代理的原理是DOM元素的事件冒泡。

——ES6——

es5和es6的区别

es6新增特性

  1. const、let
  2. 解构赋值
  3. 拓展运算符
  4. 箭头函数
  5. async、await
  6. 新数据类型Symbol
  7. map对象、set对象
  8. 模板字符串
  9. 模块化语法

const、let、var的区别

const 和 let 存在块级作用域、var不存在块级作用域
var 可以变量提升、const 和 let不可以
var可以重复声明变量、const 和 let 不可以
const 声明的是常量,不可以重复赋值

箭头函数的特点

  • 箭头函数不绑定this,会捕获其所在上下文的this,作为自己的this。
  • 语法上更简洁
  • 箭头函数本身是匿名函数、本身不可以作为构造函数、不可以使用new关键字
  • 不绑定arguments,使用rest参数解决
  • 使用call、apply和bind不会改变箭头函数中this的指向
  • 没有原型对象
什么情况不使用箭头函数?

async和defer的相同点和区别

浏览器解析HTML时,遇到script时,会停下来下载和执行script标签内的代码,这样便会造成阻塞。
async可以让HTML解析和 script 下载执行同时进行,但是这种情况不知道页面加载和script执行哪一个先完成,所以如果遇到要操作dom的情况,就有可能出错。

defer可以让HTML解析和 script 下载同时进行,但defer多了一个推迟的作用,可以推迟script的执行,直到HTML解析完

fetch API

fetch是原生js发送网络请求的一种方式,本身返回一个promise,这个promise的结果值就是后端的响应值。

axios 的封装流程

回调地狱

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值