持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情
1.谈谈对this的理解
this是一个关键字,是函数在运行时自动生成的一个内部对象,只能在函数内部使用。
- 构造函数被调用,this指向新的对象。new会改变this的指向。
- 作为函数调用,this指向全局。
- 作为对象的方法调用,this指向新的对象。
2.js内置对象
Object是js中所有对象的父对象。
数据封装类对象:Object,Array,Number,String,Bollen
其他对象:Function,Date,Math,RegExp,Error
3.闭包
在内层函数访问外层作用域。
使用场景:1.创建私有变量。2.延长变量的私有周期。
缺点:容易造成内存泄漏。内存泄漏是指不再用到的内存,没有及时的释放。
4.垃圾回收
垃圾回收(GC):收回不使用的内存 方法:
- 引用计数法:跟踪记录每个对象被引用的次数,被引用+1,引用结束-1,当引用次数为0时回收变量。但是当两个变量之间相互引用时,会造成内存泄漏。
- 标记清除法:从根部出发,清除无法到达的对象。
5.作用域和作用域链
作用域分为全局作用域和局部作用域。
全局作用域:定义的变量和函数,可以在程序的任意地方访问地到。
局部作用域:分为块级作用域和函数作用域,定义的变量或者函数,都只能在它们内部访问。 PS:局部变量会被垃圾回收干掉,所以想延长变量的私有周期,可以使用闭包。
作用域链:寻找变量的过程。
6.JS事件执行顺序
顺序:捕获=》执行=》冒泡
true时捕获,false是冒泡,默认是false。
7.原型和原型链
原型:js也是一种基于原型的语言,每个对象拥有一个原型对象。
原型链:寻找公共属性的机制。
当访问一个对象的属性时,如果没有,还会搜索对象的原型及对象原型的原型,依次层层向上搜索,直到找到或者Object.prototype.proto=null.这就是原型链。
原型链的继承:父级函数的实例化对象绑定子级的原型对象。
8.new的过程
- 创建新对象
- 更改新对象的__proto__
- 更改this指向,并执行构造函数
- 返回这个新对象
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
基本类型的数据保存在栈中;引用类型的数据保存在堆中,变量是一个指向堆内存的引用且存在栈中。
浅拷贝
如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址。
也就是说,修改一个对象的属性,另一个也发生改变。
三种方式:
- 使用Object.assign(),将右边的键值加到左边。
- 使用forin循环添加。
- 直接赋值添加。
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()
- 通过递归来实现
const obj2=JSON.parse(JSON.stringify(obj1));
11.抛出异常
12.web常见的攻击方式
- SQL注入
恶意的将sql语句插入到表单中,让程序在后台解析。
- CSRF
跨站请求伪造:诱导用户登录一个虚假的第三方网站,获取用户的Cookie后,携带Cookie向第三方网站发送跨站请求。
- 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.防抖与节流
防抖:当用户频繁触发时,前面所有触发都取消,到达规定时间,执行最后一次触发
节流:当用户频繁触发时,不根据用户频繁程度来触发,而是根据设定好的频率来触发。可以触发多次
采用lodash防抖
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)