JS面试复习,看这个系列就够了!(一)

163 阅读6分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

1.谈谈对this的理解

this是一个关键字,是函数在运行时自动生成的一个内部对象,只能在函数内部使用。

  1. 构造函数被调用,this指向新的对象。new会改变this的指向。
  2. 作为函数调用,this指向全局。
  3. 作为对象的方法调用,this指向新的对象。

2.js内置对象

Object是js中所有对象的父对象。

数据封装类对象:Object,Array,Number,String,Bollen

其他对象:Function,Date,Math,RegExp,Error

3.闭包

在内层函数访问外层作用域。

使用场景:1.创建私有变量。2.延长变量的私有周期。

缺点:容易造成内存泄漏。内存泄漏是指不再用到的内存,没有及时的释放。

image.png

4.垃圾回收

垃圾回收(GC):收回不使用的内存 方法:

  • 引用计数法:跟踪记录每个对象被引用的次数,被引用+1,引用结束-1,当引用次数为0时回收变量。但是当两个变量之间相互引用时,会造成内存泄漏。
  • 标记清除法:从根部出发,清除无法到达的对象。

5.作用域和作用域链

作用域分为全局作用域和局部作用域。

全局作用域:定义的变量和函数,可以在程序的任意地方访问地到。

局部作用域:分为块级作用域和函数作用域,定义的变量或者函数,都只能在它们内部访问。 PS:局部变量会被垃圾回收干掉,所以想延长变量的私有周期,可以使用闭包。

作用域链:寻找变量的过程。

6.JS事件执行顺序

顺序:捕获=》执行=》冒泡

image.png

true时捕获,false是冒泡,默认是false。

7.原型和原型链

原型:js也是一种基于原型的语言,每个对象拥有一个原型对象。

原型链:寻找公共属性的机制。

当访问一个对象的属性时,如果没有,还会搜索对象的原型及对象原型的原型,依次层层向上搜索,直到找到或者Object.prototype.proto=null.这就是原型链。

原型链的继承:父级函数的实例化对象绑定子级的原型对象。

8.new的过程

  1. 创建新对象
  2. 更改新对象的__proto__
  3. 更改this指向,并执行构造函数
  4. 返回这个新对象
function myNew(fn,...args) {
    const obj={}
    obj.__proto__=fn.prototype
    fn.apply(obj.args)
    return obj
}

9.更改this指向的三个方法

  • call

第一个参数是this指向,后面是实参且个数不受限制。可以调用函数。

  • apply

第一个参数是this指向,第二个是数组。可以调用函数。

  • bind

参数跟call一样,但是使用bind不会调用函数。有一个返回值,返回this的指向。

10.浅拷贝和深拷贝

JS有两大类型:基本类型和引用类型。

基本类型:

  • Boolean
  • Number
  • String
  • null
  • undefined
  • symbol

引用类型:

  • Object
  • Array
  • Function
  • Set

基本类型的数据保存在栈中;引用类型的数据保存在堆中,变量是一个指向堆内存的引用且存在栈中。

浅拷贝

如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址。

也就是说,修改一个对象的属性,另一个也发生改变。

三种方式:

  1. 使用Object.assign(),将右边的键值加到左边。
  2. 使用forin循环添加。
  3. 直接赋值添加。
const obj = { name: '浙江', address: '中国' } 
const o = { age: 20 } 

// 第一种,把右边的键值对加到左边 
Object.assign(o, obj) 

// 第二种 
for (let key in obj) { 
    o[key] = obj[key] 
} 

// 第三种 
o.name = obj.name 
o.address = obj.address 

console.log(o);

深拷贝

当对象是引用类型时,开辟一个新栈,两个对象的属性完全相同,但是对应两个完全不同的地址。

修改一个对象的属性,另外一个不会发生改变。

方式:

  • 工作的项目里使用lodash的_cloneDeep()
  • JSON.stringfy()。注意不可以拷贝函数(引用类型Function),undefined,symbol。
  • jq里面的extend()
  • 通过递归来实现

image.png

const obj2=JSON.parse(JSON.stringify(obj1));

11.抛出异常

image.png

12.web常见的攻击方式

  1. SQL注入

恶意的将sql语句插入到表单中,让程序在后台解析。

  1. CSRF

跨站请求伪造:诱导用户登录一个虚假的第三方网站,获取用户的Cookie后,携带Cookie向第三方网站发送跨站请求。

  1. XSS

跨站脚本攻击:允许攻击者将恶意代码植入到提供给其他用户使用的页面中。

12.如何实现上拉加载

上拉加载本质是页面触底,或者快要触底的动作。

判断页面触底,要先了解几个属性:

  • scrolltop:滚动视窗距离window顶部的距离。
  • clientHeight:定值,表示屏幕可视区域的高度。
  • scrollHeight:页面不能滚动时也是存在的,此时scrollHeight等于clientHeight。scrollHeight表示body所有元素的总长度(包括body元素自身的padding)。
let clientHeight  = document.documentElement.clientHeight; //浏览器高度
let scrollHeight = document.body.scrollHeight;
let scrollTop = document.documentElement.scrollTop;
 
let distance = 50;  //距离视窗还用50的时候,开始触发;

if ((scrollTop + clientHeight) >= (scrollHeight - distance)) {
    console.log("开始加载数据");
}
// 拉到底部后,刷新即可在控制台看到数据!

注意这里的scrollHeight与offsetHeight可以替换,也是能达到相同的效果

13.下拉刷新

页面本身置于顶部时,用户下拉时触发的动作。

三个阶段:

  • 当前手势滑动位置与初始位置的差值大于0的时候,提示正在进行下拉操作。((在scrollTop为0的时候进行判断)
  • 下拉到一定值时,提示松手后的操作。
  • 松手,执行更新回调。

14.大文件如何实现断点上传

拿到文件,保存文件的唯一标识,切割文件,逐一上传,同时根据唯一标识同步上传进度。直到文件全部上传完成。

15.防抖与节流

防抖:当用户频繁触发时,前面所有触发都取消,到达规定时间,执行最后一次触发

节流:当用户频繁触发时,不根据用户频繁程度来触发,而是根据设定好的频率来触发。可以触发多次

image.png 采用lodash防抖

image.png

image.png

16解决js数字精度丢失的问题

为什么0.1+0.2不等于0.3?

因为计算机存储浮点数时,要把十进制转化为二进制,由于存储位数有限(64位),所以某些数字在十进制转化为二进制时会出现精度丢失问题。

解决方案:使用toFixed,toPrecision 凑整并 parseFloat,第三方js库(例如bigInt)。

console.log(Number((0.1+0.2).toFixed(1))===0.3)// true

17事件循环

同步任务在执行栈执行完之后,会去异步队列查看是否有待执行的异步任务的回调函数,有就拿到执行栈执行,执行完之后又去异步队列查看。这个反复查看的过程就是事件循环(eventloop)