Skip to content

手写实现相关

深拷贝(deepCopy)

对象浅拷贝可用 Object.assign,或展开运算符...,数组的浅拷贝可以使用slice和concat,而对象或数组的深拷贝简单场景可使用JSON.parse(JSON.stringify(object))解决(缺陷是:

  1. 会忽略 undefined
  2. 会忽略 symbol
  3. 不能序列化函数即无法拷贝函数
  4. 不能解决循环引用的对象 5.无法拷贝特殊对象RegExp, Date, Set, Map)。

数组扁平化(flatten)

数组扁平化是指将多维数组转化为一维数组(可以直接写在Array.prototype上)。

扁平化二维数组

扁平化更高维度数组

数组去重

循环打印红黄绿

红灯 3s 亮一次,绿灯 1s 亮一次,黄灯 2s 亮一次;如何让三个灯不断交替重复亮灯?

每隔一秒打印 0,1,2,3,4

实现图片懒加载

实现思路

  1. 页面放置img标签元素;
  2. 初始化img标签 data-src =真实图片地址,同时设置alt, width, height以及,默认的src (代替的小图片);
  3. JavaScript判断img元素是否出现在窗口内,是则设置src = data-src。

方式一

  1. document.documentElement.clientHeight || window.innerHeight 获取可视窗口的高度,两者区别在于前者除去滚动条的高度,也是为了浏览器之间兼容
  2. document.documentElement.scrollTop || document.body.scrollTop 获取根元素滚动的距离,(或者使用只读属性window.pageXOffset/pageYOffset )
  3. 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 完全构建好:

  1. 方法 scrollBy(x,y) 将页面滚动至相对于当前位置的 (x, y) 位置;
  2. 方法 scrollTo(x-coord, y-coord) 将页面滚动至相对调用对象(element或window)的左上角的指定坐标位置;或scrollTo(options),其中包含以下参数的字典:
    1. top指定沿 Y 轴滚动窗口或元素的像素数。
    2. left指定沿 X 轴滚动窗口或元素的像素数。
    3. behavior确定滚动是即时的还是平滑的动画。此选项是一个字符串,必须采用以下值之一:
      1. smooth:滚动动画应该流畅
      2. instant:滚动应该在一次跳跃中立即发生
      3. auto:滚动行为由scroll-behavior计算值决定
  3. 方法element.scrollIntoView(top) 将element元素滚动至窗口顶部(top=true)或底部(top=false);
  4. 方法element.style.overflow = "hidden",禁止element的滚动(使用时配合padding来防止滚动条消失页面抖动)

document.elementFromPoint(x, y):返回当前文档上处于指定坐标(相对于窗口左上角可见区域的坐标,否则返回null)位置最顶层的元素。

javascript
// 在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()获得。

javascript
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异步自动观察元素是否在视口内

  1. new IntersectionObserver(callback[, options])
  2. callback是当元素可见比例超过指定阈值调用的回调函数,回调函数接受两个参数:
    1. entries:与root可视区域的交叉状态描述IntersectionObserverEntry对象(对象的target即被观察者)构成的数组
    2. observer:被调用的IntersectionObserver实例,注意这不是被观察者,而是观察者。
  3. options是配置observer实例的对象,默认为{ root : 文档对象,rootMargin:undefiend, threshold:0}:
    1. root是作为监听被观察者的视口元素,是否可见是相对于root元素的,在root元素可见区域内之外均视为不可见
    2. rootMargin 用于扩大root元素视口范围
    3. threshold:规定被监听元素与root可见区域的交叉比例值阈值,被监听元素完全出现在root可见区域中为1,完全在之外为0
javascript
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

生成指定长度随机字符串

使用 setTimeout 实现 setInterval

实现 range 函数

实现 lodash 的 countBy 函数

实现 canvas 简易版手写签名

实现 add(1)(2)(3)(4)()

实现远程调用加法