前端知识点
1、JS基本数据类型有哪些?引用数据类型有哪些?
在 JS 中,存在着 8 种原始值,分别是: boolean null undefined number string symbol 、Bigint(ES2020新增)
引用数据类型:
对象Object(包含普通对象-Object,数组对象-Array,正则对象-RegExp,日期对象-Date,数学函数-Math,函数对象-Function)
null和undefined 有什么区别?
(1)null是一个表示”无”的对象,转我数值是为0,undefined是一个表示”无”的原始值,转为数值时为NaN。当声明的变量还未被初始化时,能量的默认值为undefined
(2)Null用来表示尚未存在的对象,常用来表示函数企图返回一个不存在的对象
(3)Undefined表示”缺少值”,就是此处应该有一个值,但是还没有定义。
典型用法是:
a、变量被声明了,但没有赋值时,就等于undefined
b、调用函数时,应该提供的参数没有提供,该参数等于undefined
c、对象没有赋值属性,该属性的值为undefined
d、函数没有返回值时,默认返回undefined
(4)null表示”没有对象”,即该处不应该有值。典型用法是: a、作为函数的参数,表示该函数的参数不是对象 b、作为对象原型链的终点
2、CSS中 link 和@import 的区别是?
link属于HTML标签,而@import是CSS提供的;页面被加载的时link会同时被加载,而@import引用的CSS会等到页面被加载完再加载;link方式的样式的权重 高于@import的权重.
3、position的absolute与fixed共同点与不同点
相同:改变行内元素的呈现方式,display被置为block;让元素脱离普通流,不占据空间;默认会覆盖到非定位元素上
不同点:absolute的”根元素“是可以设置的,而fixed的”根元素“固定为浏览器窗口。当你滚动网页,元素与浏览器窗口之间的距离是不变的。
4、什么是闭包?
我的理解是,闭包就是能够读取其他函数内部变量的函数。由于在Javascript语言中,只有函数内部的子函数才能读取局部变量,因此可以把闭包简单理解成"定义在一个函数内部的函数"。所以,在本质上,闭包就是将函数内部和函数外部连接起来的一座桥梁。
5、谈谈你对原型链的理解
在JavaScript中,每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象。
当函数经过new调用时,这个函数就成为了构造函数,返回一个全新的实例对象,这个实例对象有一个__proto__属性,指向构造函数的原型对象。
JavaScript对象通过__proto__ 指向父类对象,直到指向Object对象为止,这样就形成了一个原型指向的链条, 即原型链。
实现一个instanceof
function myInstanceof(left,right) { if(typeof left !== 'object' || left === null) return false //获取原型 let proto = Object.getPrototypeOf(left) while(true){ //如果原型为null,则已经到了原型链顶端,判断结束 if(proto === null) return false //左边的原型等于右边的原型,则返回结果 if(proto === right.prototype) return true //否则就继续向上获取原型 proto = Object.getPrototypeOf(proto) } }
6、关于setTimeout的一些冷知识
-
由于消息队列的机制,不一定能按照自己设置的时间执行
-
settimeout嵌套settimeout时,系统会设置最短时间间隔为4ms
-
未激活的页面,settimeout最小时间间隔为1000ms
-
延时执行时间最大值为2147483647(32bit),溢出这个值会导致定时器立即执行
7、常见兼容性问题
浏览器默认的margin和padding不同。解决方案是加一个全局的*{margin:0;padding:0;}来统一。
IE下,可以使用获取常规属性的方法来获取自定义属性, 也可以使用getAttribute()获取自定义属性; Firefox下,只能使用getAttribute()获取自定义属性. 解决方法:统一通过getAttribute()获取自定义属性.
IE下,event对象有x,y属性,但是没有pageX,pageY属性; Firefox下,event对象有pageX,pageY属性,但是没有x,y属性
解决方法:(条件注释)缺点是在IE浏览器下可能会增加额外的HTTP请求数。
Chrome 中文界面下默认会将小于 12px 的文本强制按照 12px 显示, 可通过加入 CSS 属性 -webkit-text-size-adjust: none; 解决.
超链接访问过后hover样式就不出现了 被点击访问过的超链接样式不在具有hover和active了解决方法是改变CSS属性的排列顺序: L-V-H-A : a:link {} a:visited {} a:hover {} a:active {}
上下margin重合问题 ie和ff都存在,相邻的两个div的margin-left和margin-right不会重合,但是margin-top和margin-bottom却会发生重合。 解决方法,养成良好的代码编写习惯,同时采用margin-top或者同时采用margin-bottom。
8、节流
比如说事件触发可以让它在每一秒内只触发一次,可以提高性能。
function throttle(fn, wait) { let prev = +new Date() return function() { let now = +new Date() /*当下一次事件触发的时间和初始事件触发的时间的差值大于 等待时间时才触发新事件 */ if(now - prev > wait) { fn.apply(this, arguments) } //重置初始触发时间 prev = +new Date() } }
9、防抖
防抖就是可以限制事件在一定时间内不能多次触发,比如说你疯狂按点击按钮,一顿操作猛如虎,不加防抖的话它也会跟着你疯起来,疯狂执行触发的方法。但是一旦加了防抖,无论你点击多少次,他都只会在你最后一次点击的时候才执行。 防抖常用于搜索框或滚动条等的监听事件处理,可以提高性能。
function debounce(fn, wait = 50) { //初始化一个定时器 let timer return function() { //如果timer存在就将其清除 if(timer) { clearTimeout(timer) } //重置timer timer = setTimeout(() => { //将入参绑定给调用对象 fn.apply(this, arguments) }, wait) } }
深拷贝和浅拷贝
浅拷贝: 顾名思义,所谓浅拷贝就是对对象进行浅层次的复制,只复制一层对象的属性,并不包括对象里面的引用类型数据 , 当遇到有子对象的情况时,子对象就会互相影响 ,修改拷贝出来的子对象也会影响原有的子对象
深拷贝: 深拷贝是对对象以及对象的所有子对象进行拷贝,也就是说新拷贝对象的子对象里的属性也不会影响到原来的对象
let obj = { a: 1, b: 2, c: { d: 3, e: 4 } }
实现浅拷贝
使用Object.assign()
let obj2 = Object.assign({}, obj)
obj2.a = 111
obj2.c.e = 555
console.log(obj)
console.log(obj2)
使用展开运算符
let obj2 = {...obj}
obj2.a = 111
obj2.c.e = 555
console.log(obj)
console.log(obj2)
实现深拷贝
最简单的深拷贝方式
let target = JSON.parse(JSON.stringify(source))
但是这种方法的话只支持object
、array
、string
、number
、true
、false
、null
这几种数据或者值,其他的比如函数、undefined、Date、RegExp等数据类型都不支持。对于它不支持的数据都会直接忽略该属性。
完整版
function deepCopy(source, cache = new Map()) { if (cache.has(source)) { //如果缓存中已经有值则直接返回,解决循环调用的问题 return cache.get(source) } //当入参属于Object复杂数据类型就开始做子类检测-> Function Array RegExp Date 都属于Object类型 if (source instanceof Object) { let target if (source instanceof Array) { //判断数组的情况 target = [] } else if (source instanceof Function) { //判断函数的情况 target = function () { return source.apply(this, arguments) } } else if (source instanceof RegExp) { //判断正则表达式的情况 target = source } else if (source instanceof Date) { target = new Date(source) } else { //普通对象 target = {} } // 将属性和拷贝后的值进行缓存 cache.set(source, target) //开始做遍历递归调用 for (let key in source) { if (source.hasOwnProperty(key)) { target[key] = deepCopy(source[key], cache) } } return target } else { //如果不是复杂数据类型的话就直接返回 return source } }