手写实现相关
深拷贝(deepCopy)
对象浅拷贝可用 Object.assign,或展开运算符...,数组的浅拷贝可以使用slice和concat,而对象或数组的深拷贝简单场景可使用JSON.parse(JSON.stringify(object))解决(缺陷是:
- 会忽略 undefined
- 会忽略 symbol
- 不能序列化函数即无法拷贝函数
- 不能解决循环引用的对象 5.无法拷贝特殊对象RegExp, Date, Set, Map)。
数组扁平化(flatten)
数组扁平化是指将多维数组转化为一维数组(可以直接写在Array.prototype上)。
扁平化二维数组:
扁平化更高维度数组:
数组去重
循环打印红黄绿
红灯 3s 亮一次,绿灯 1s 亮一次,黄灯 2s 亮一次;如何让三个灯不断交替重复亮灯?
每隔一秒打印 0,1,2,3,4
实现图片懒加载
实现思路:
- 页面放置img标签元素;
- 初始化img标签 data-src =真实图片地址,同时设置alt, width, height以及,默认的src (代替的小图片);
- JavaScript判断img元素是否出现在窗口内,是则设置src = data-src。
方式一:
- document.documentElement.clientHeight || window.innerHeight 获取可视窗口的高度,两者区别在于前者除去滚动条的高度,也是为了浏览器之间兼容
- document.documentElement.scrollTop || document.body.scrollTop 获取根元素滚动的距离,(或者使用只读属性window.pageXOffset/pageYOffset )
- element.offsetTop 获取元素对于其 offsetParent 元素的顶部内边距的距离。
注意:offsetParent是指向包含层级上最近的包含该元素的定位元素(position:absolute/relative/fixed)或者最近的 table,td,th,body元素。当元素的 style.display 设置为 "none" 时,offsetParent 返回 null。如果元素存在fixed定位,offsetParent为null(firefox浏览器例外是body),因为fixed定位的元素包含层级的父元素为null(firefox为body)。 补充:
JavaScript操作页面的坐标系分为页面坐标(自称为pageY/pageX)和窗口坐标(自clientY/clientX),分别相对于文档左上角和可视窗口左上角。
获取文档完整高度/宽度: Math.max(document.body.scrollHeight/width,document.documentElement.scrollHeight/width,document.body.offsetHeight/width,document.documentElement.offsetHeight/width,document.body.clientHeight/width,document.documentElement.clientHeight/width ); JavaScript操作页面滚动须等 DOM 完全构建好:
- 方法 scrollBy(x,y) 将页面滚动至相对于当前位置的 (x, y) 位置;
- 方法 scrollTo(x-coord, y-coord) 将页面滚动至相对调用对象(element或window)的左上角的指定坐标位置;或scrollTo(options),其中包含以下参数的字典:
- top指定沿 Y 轴滚动窗口或元素的像素数。
- left指定沿 X 轴滚动窗口或元素的像素数。
- behavior确定滚动是即时的还是平滑的动画。此选项是一个字符串,必须采用以下值之一:
- smooth:滚动动画应该流畅
- instant:滚动应该在一次跳跃中立即发生
- auto:滚动行为由scroll-behavior计算值决定
- 方法element.scrollIntoView(top) 将element元素滚动至窗口顶部(top=true)或底部(top=false);
- 方法element.style.overflow = "hidden",禁止element的滚动(使用时配合padding来防止滚动条消失页面抖动)
document.elementFromPoint(x, y):返回当前文档上处于指定坐标(相对于窗口左上角可见区域的坐标,否则返回null)位置最顶层的元素。
// 在img元素定位不是fixed的情况下且display不为none且不是table,td,th 的子元素的时候适用
// 3 - 2 < 1 的时候,元素在可视区域
const isVisible = function(element) {
let windowVisibleHeight = document.documentElement.clientHeight || window.innerHeight
let documentScrollHeight = document.documentElement.scrollTop || document.body.scrollTop
let elTopToDocument = element.offsetTop
if (elTopToDocument === null) throw new Error(’the position of element is non-compliant’)
return elTopToDocument - documentScrollHeight < windowVisibleHeight
}
const lazyLoadImg = function(element) {
if (isVisible(element)) {
element.src = element.dataset.src
}
}
方式二:
那么相对于文档左上角坐标:pageY/pageX = clientY / clientX + 文档的垂直/水平滚动出的部分的高度/宽度。clientY / clientX 由getBoundingClientRect()获得。
const isVisible = function(element) {
let windowVisibleHeight = document.documentElement.clientHeight || window.innerHeight
return element.getBoundingClientRect().top <= windowVisibleHeight + 50
}
const lazyLoadImg = function(element) {
if (isVisible(element)) {
element.src = element.dataset.src
}
}
方式三:IntersectionObserver异步自动观察元素是否在视口内
- new IntersectionObserver(callback[, options])
- callback是当元素可见比例超过指定阈值调用的回调函数,回调函数接受两个参数:
- entries:与root可视区域的交叉状态描述IntersectionObserverEntry对象(对象的target即被观察者)构成的数组
- observer:被调用的IntersectionObserver实例,注意这不是被观察者,而是观察者。
- options是配置observer实例的对象,默认为{ root : 文档对象,rootMargin:undefiend, threshold:0}:
- root是作为监听被观察者的视口元素,是否可见是相对于root元素的,在root元素可见区域内之外均视为不可见
- rootMargin 用于扩大root元素视口范围
- threshold:规定被监听元素与root可见区域的交叉比例值阈值,被监听元素完全出现在root可见区域中为1,完全在之外为0
const lazyLoadImg = function(element) {
element.src = element.dataset.src
}
const callback = (entries, observer) => { // 交叉状态对象数组和观察者
entries.forEach((entry) => {
let element = entry.target // 被观察者
lazyLoadImg(element) //替换真实src
observer.unobserve(element) //移除执行过回调的被观察者
})
}
const lazyLoadImgObserver = new IntersectionObsever(callback) //观察者
// 使用观察者观察指定元素
elements = document.querySelectorAll(selectorOfElement)
elements.forEach((element) => {
lazyLoadImgObserver.obseve(element) //观察每个元素
}
比较两个版本号的大小
比较两个应用版本的大小,如果v1 > v2返回1;如果v1 < v2返回0;如果 v1 = v2返回0。比如,1.2.4 < 1.3.0.alpha.1 < 1.3.0.alpha.2 < 1.3.0.beta.1 < 1.3.0.rc.1 < 1.3.0
;