前端面试题—中级

总结一波, 先这样吧,慢慢再补充,有问题…

react篇传送门

目录

一、JS部分:

1.原型链

当访问一个对象的属性时,如果在对象的内部不存在,就会通过__proto__一直向上去找,直到null。

  1. 对象(除了null)中都有__proto__属性,函数是特殊的对象有__proto__和prototype两种属性。
  2. __proto__为隐式原型,指向它的构造函数的原型对象(prototype)。
  3. prototype为显式原型,是函数独有的(能够被当作构造函数使用的函数才有),指向函数的原型对象。它的作用就是让该函数所实例化的对象们,共享属性和方法

PS:
基本数据类型也有__proto__属性,但基本类型的值本质是个密封对象,不能增加、修改、删除属性。
在这里插入图片描述

  • 引用类型和基本类型的主要区别,就是对象的生存期。
  • 使用new操作符创建的引用类型的实例,在执行流离开当前作用域之前都一直保存在内存中。
  • 而自动创建的基本类型,它的对象只存在于一行代码执行的瞬间,然后立即被销毁。这以意味着我们不能在运行时为基本类型添加属性和方法。

2.闭包

含义:访问了另一个函数作用域内的变量的函数。通常通过嵌套函数去实现。

function foo() {
   
	var a = 1
	function bar() {
   
		a++
		console.log(a)
	}
	return bar
}

const myFoo = foo()
myFoo()

好处:

  1. 缓存变量,参数和变量不会被垃圾回收机制回收
  2. 保存私有变量
  3. 实现方法和属性的私有化

坏处:容易导致内存泄漏

3.手写Promise

手写promise

4.数据类型判断

  • typeof:返回7种数据类型:number,string,boolean,undefined,symbel,object,function
  • instanceof:用来判断对象和数组 ([ ] instanceof Array)
  • Array.isArray([ ]) 判断数组的方法
  • Array.isPrototypeOf([ ]) 判断数组
  • constructor: 指向构造函数,原型链上的方法,所以不能用来判断null和undefined
    在这里插入图片描述
  • Object.prototype.toString.call()- - 相对来说最准确的方式
    在这里插入图片描述

综合:

function gettype(obj) {
   
  var type = typeof obj;
  if (type !== 'object') {
   
    return type;
  }
  //如果不是object类型的数据,直接用typeof就能判断出来
  //如果是object类型数据,准确判断类型必须使用Object.prototype.toString.call(obj)的方式才能判断
  return Object.prototype.toString.call(obj).replace(/^\[object (\S+)\]$/, '$1');
}

5.Map和Set

  • Map()
    map是一组键值对的结构,具有极快的查找速度。解决了JavaScript的对象键必须是字符串的问题。在map中,Number或者其他数据类型也可以作为键。
var m = new Map(); // 空Map
m.set('Adam', 67); // 添加新的key-value /或修改
m.has('Adam'); // 是否存在key 'Adam': true
m.delete('Adam'); // 删除key 'Adam'
m.get('Adam'); // undefined
  • Set()
    Set和Map类似,也是一组key的集合,但不存储value。由于key不能重复,所以,在Set中,没有重复的key。
var s1 = new Set(); // 空Set
var s = new Set([1, 2, 3, 3, '3']);
s; // Set {1, 2, 3, "3"}
s.add(4);
s; // Set {1, 2, 3, "3", 4}
s.delete(3);
s; // Set {1, 2, "3", 4}

//数组去重 百试不爽
var arr=[...new Set([1,2,1,2,3])]
// [1, 2, 3]

6.垃圾回收机制

  • 标记清除:在运行时给内存所有变量加上标记,然后去除掉在执行环境中的变量和被这些变量引用的变量。剩下的带有标记的变量视为准备删除的变量,最后垃圾回收机制在下周期运行时,释放这些变量,回收占用的空间
  • 引用计数:引用表保存了内存里所有资源的引用次数。这个数为0时,就说明用不到了,就释放。

7.安全随机数

Math.random() : 返回介于 0(包含) ~ 1(不包含) 之间的一个随机数。该函数不是加密安全的随机数生成器。
window.crypto.getRandomValues(typedArray) : 返回非0的正整数,可以获取符合密码学安全性要求的随机值。
typedArray是一个基于整数的 TypedArray,其可以是 Int8Array、Uint8Array、Int16Array、 Uint16Array、 Int32Array 或 Uint32Array。

//生成随机随机数
 var arr = new Uint16Array(8);
  var crypto = window.crypto || window.webkitCrypto 
  			|| window.mozCrypto || window.oCrypto || window.msCrypto;
  window.crypto.getRandomValues(arr);
// 生成UUID
  window.crypto.randomUUID();

详情参考:
1.JS 安全随机数 window.crypto及其兼容性
2.深入JS getRandomValues和Math.random方法
瞻仰一下大佬博客:张鑫旭的个人主页

总的来说:
Math.random() 随机数并不是实时生成的,而是直接生成一组随机数(64个),并放在缓存中。当这一组随机数取完之后再重新生成一批,放在缓存中。并且是可以被模拟、计算出来的。
getRandomValues() 方法的底层实现是没有缓存的,并且是实时生成的,因此,性能上是要比 Math.random() 差的

8.贪心算法

贪心算法以迭代的方式作出相继的贪心选择,每作一次贪心选择就将所求问题简化为规模更小的子问题。对于一个具体问题,要确定它是否具有贪心选择性质,必须证明每一步所作的贪心选择最终导致问题的整体最优解。

//你有两个孩子和三块小饼干,2个孩子的胃口值分别是1,2。
//你拥有的饼干数量和尺寸都足以让所有孩子满足。
//所以你应该输出2.
输入: g = [1,2], s = [1,2,3]
输出: 2
var findContentChildren = function(g, s) {
   
        g.sort(asc);
        s.sort(asc);
        let gp = 0,
            sp = 0;
        while (sp < s.length && gp < g.length) {
   
            // 发现满足条件的饼干,喂饱一个孩子
            if (s[sp] >= g[gp]) {
   
                gp++;
            }
            // 继续找下一块饼干
            sp++;
        }
        return gp;
        function asc(a, b) {
   
            return a - b;
        }
    };
    console.log(findContentChildren([1,2,2,4,6,7,8,8,8,9,9], [1,3,4,4,5,8,9]))//6

具体参考:

  1. JS贪心算法,含图解
  2. 五大常用算法——贪心算法详解及经典例子

9.js循环

  • for...of语句在可迭代对象包括: Array,Map,Set,String,TypedArray,arguments 对象等等.弥补了弥补了forEachfor-in循环的短板
  • for in 遍历的是可枚举属性,for of 遍历的是可迭代属性

10.ES6数组新方法

  1. forEach()map()
    forEach()会修改原来的数组,不会返回执行结果。map()方法会得到一个新的数组并返回。
    map的执行速度会更快。

  2. filter()
    创建一个新数组, 返回符合条件的元素。

  3. reduce()
    官方:对数组中的每个元素执行一个由您提供的reducer函数(升序执行),将其结果汇总为单个返回值。
    简单来讲,他的主要作用,就是可以取到上次遍历的返回值。进而做累加等操作

  4. some()
    判断数组中是不是,至少有1个元素,通过了被提供的函数。

  5. every()
    指数组内的所有元素是否都能通过某个指定函数

  6. Array.from()
    用于将类似数组的对象和可遍历对象转为真正的数组

  7. Array.of()
    用于将一组值,转换为数组。
    用来弥补数组构造函数Array()的不足,基本上可以用来替代Array()new Array()

  8. copyWithin()
    将指定位置的成员复制到其他位置,然后返回当前数组,会修改当前数组。

  9. find()findIndex()
    find:找出 第一个 符合条件的数组成员
    findIndex: 返回 第一个 符合条件的数组成员的位置,如果所有成员都不符合条件,则返回-1

  10. fill()
    使用给定值,填充一个数组。用于空数组的初始化非常方便。

  11. entries()keys() values()
    用于遍历数组。它们都返回一个遍历器对象
    keys()是对键名的遍历、values()是对键值的遍历,entries()是对键值对的遍历

  12. includes()
    表示某个数组是否包含给定的值,方法返回一个布尔值。

  13. flat()flatMap()
    flat:用于将嵌套的数组“拉平”,变成一维的数组。返回一个新数组
    flatMap:对原数组的每个成员执行一个函数,然后对返回值组成的数组执行flat()方法,返回一个新数组。

  14. at()
    接受一个整数作为参数,返回对应位置的成员,主要是为了解决运算符[]不支持负索引。

使用方法列举太臃肿,都放在另一篇了;
实例移步:
ES6数组新方法

旧的数组方法:
js数组方法

11.Math方法

  • Math.abs() 返回绝对值
  • Math.ceil(),Math.floor() 向上取整和向下取整
  • Math.max(),Math.min() 最大值和最小值
  • Math.round() 四舍五入
  • Math.random() 随机数
  • Math.pow() 指数运算
  • Math.sqrt() 平方根
  • Math.log() 自然对数
  • Math.exp() e的指数

12.深拷贝&浅拷贝

基本类型:
在这里插入图片描述
引用类型:
在这里插入图片描述
访问一个引用类型,需要先从栈中获取该对象的指针,然后再通过指针访问堆内存对应的数据。
浅拷贝只拷贝这个对象的指针,原来的对象和拷贝的对象指向的是堆内存中的同一个东西,彼此之间的操作会互相影响。
深拷贝则会在堆内存中重新分配内存,拥有不同的地址,但值是一样的。

  • 浅拷贝的方法:“=”赋值、"…"展开运算符、Object.assign() // 一层深拷贝
  • 深拷贝: JSON.parse(JSON.stringify())、递归拷贝、var newObj = Object.create(oldObj)、第三方库lodash.clonedeep

详情:
关于深浅拷贝的那些事

13.es2019了解多少

  1. String.prototype.trimStart() / String.prototype.trimEnd() 头\尾的空格文本去掉
  2. Object.fromEntries() 键值对还原成对象结构
  3. Array.prototype.flat() / Array.prototype.flatMap() 数组展平
    [1, 2, [3, 4]].flat();// [ 1, 2, 3, 4 ]
  4. try...catch catch的参数改为可选
  5. JSON.stringify() 加强格式转化
  6. JSON.parse() 添加了对行分隔符(\u2028) 和段落分隔符(\u2029)的支持

14. 隐式转换

  1. 数字运算:
    ​“+”:将表达式的值转换为String(仅当有一个是String类型);
    ​“-”:将表达式的值转换为Number;
  2. “.”
    被隐式转换为对象;
    var a = 2;
    console.log(a.toString()); // ‘2’; a被转换为对象,可以调用方法
  3. “if语句”
    判断的条件表达式会被隐式转换为Boolean类型
  4. “==”
    JS的非严格匹配时,会进行隐式类型转换

15.在地址栏中输入一个网址,这个过程中发生了什么

先查找缓存,有缓存直接返回资源给浏览器进程,网络请求结束
没有缓存文件或者缓存过期,则会 真正进入网络请求流程:

  1. 使用DNS解析,寻找服务器的ip
  2. TCP连接
  3. 发送HTTP请求
  4. 服务器处理HTTP请求并返回报文
  5. 浏览器解析渲染页面
  6. 连接结束

16.js中哪些方法可以实现异步操作

(1)定时器都是异步操作
(2)事件绑定都是异步操作
(3)promise
(4)回调函数可以理解为异步
(5)async await
(6)$nextTick

17.常用的数组、字符串方法

  • 数组:

    1. 增(添加元素)
      push(…items):用途: 向数组末尾添加一个或多个元素。是否改变原数组: 是。
      unshift(…items):用途: 向数组开头添加一个或多个元素。是否改变原数组: 是。
      concat(…arrays):用途: 合并数组,返回一个新数组。是否改变原数组: 否。

    2. 删(删除元素)
      pop():用途: 移除并返回数组的最后一个元素。是否改变原数组: 是。
      shift():用途: 移除并返回数组的第一个元素。是否改变原数组: 是。
      splice(start, deleteCount):用途: 从指定位置删除元素。是否改变原数组: 是。
      slice(start, end):用途: 返回子数组,不改变原数组。是否改变原数组: 否。

    3. 改(修改元素或顺序)
      splice(start, deleteCount, …items):用途: 删除或替换元素,并可插入新元素。是否改变原数组: 是。
      reverse():用途: 反转数组顺序。是否改变原数组: 是。
      sort([compareFunction]):用途: 对数组排序。是否改变原数组: 是。
      fill(value, start, end):用途: 用固定值填充数组的一部分或全部。是否改变原数组: 是。

    4. 查(查找元素或信息)
      indexOf(item):用途: 返回元素第一次出现的索引,不存在则返回 -1。是否改变原数组: 否。
      lastIndexOf(item):用途: 返回元素最后一次出现的索引,不存在则返回 -1。是否改变原数组: 否。
      includes(item):用途: 判断数组是否包含某个元素。是否改变原数组: 否。
      find(callback):用途: 返回第一个满足条件的元素。是否改变原数组: 否。
      findIndex(callback):用途: 返回第一个满足条件的元素的索引。是否改变原数组: 否。
      some(callback):用途: 判断是否有元素满足条件。是否改变原数组: 否。
      every(callback):用途: 判断是否所有元素都满足条件。是否改变原数组: 否。

  • 对象

    1. 增(添加属性)
      Object.assign(target, …sources):用途: 将一个或多个源对象的属性复制到目标对象。

    2. 删(删除属性)
      delete 操作符 用途: 删除对象的属性。

    3. 改(修改属性)
      Object.defineProperty(obj, prop, descriptor):用途: 定义或修改对象的属性(可设置属性特性如 writable, enumerable 等)。
      Object.freeze(obj):用途: 冻结对象,使其不可修改。

    4. 查(查找属性或信息)
      Object.keys(obj):用途: 返回对象自身可枚举属性的数组。是否改变原对象: 否。
      Object.values(obj):用途: 返回对象自身可枚举属性值的数组。是否改变原对象: 否。
      Object.entries(obj):用途: 返回对象自身可枚举属性的键值对数组。是否改变原对象: 否。
      obj.hasOwnProperty(prop):用途: 判断对象是否包含指定属性(不包括原型链)。是否改变原对象: 否。
      Object.getOwnPropertyDescriptor(obj, prop):用途: 返回对象指定属性的描述符。是否改变原对象: 否。
      Objec

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

1234Wu

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

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

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

打赏作者

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

抵扣说明:

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

余额充值