部1
1. jsonp
function jsonp({ url, data, success }) {
let script = docuemnt.createElement('script')
var str = ''
for (let k in data) {
str += `&${k}=${data[k]}`
}
let fnName = 'myJsonp' + Math.random().toString().replace('.', '')
window[fnName] = success
script.src = url + '?callback=' + fnName + str
document.body.appendChild(script)
script.onload = function () {
document.body.removeChild(script)
}
}
jsonp({
url: ' ',
data: {},
success: function (data) {},
})
2. 栈解题
/*
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
1. 左括号必须用相同类型的右括号闭合。
2. 左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。
示例 1:
输入:s = "()"
输出:true
示例 2:
输入:s = "()[]{}"
输出:true
示例 3:
输入:s = "(]"
输出:false
示例 4:
输入:s = "([)]"
输出:false
示例 5:
输入:s = "{[]}"
输出:true
*/
function isValid(str) {
if (str.length % 2 !== 0) {
return false
}
let items = []
for (let i = 0; i < str.length; i++) {
let letter = items[items.length - 1]
switch (str[i]) {
case '(':
items.push('(')
break
case '[':
items.push('[')
break
case '{':
items.push('{')
break
case ')':
if (letter === '(') {
items.pop()
}
break
case ']':
if (letter === '[') {
items.pop()
}
break
case '}':
if (letter === '{') {
items.pop()
}
break
}
}
return items.length === 0
}
4. 实现斐波那契数列
// 递归
function fibonacci (n){
if(n==0) return 0
if(n==1) return 1
return fibonacci(n-2)+ fibonacci(n-1)
}
5. 寄生组合继承
function Parent(name) {
this.name = name;
this.say = () => {
console.log(111);
};
}
Parent.prototype.play = () => {
console.log(222);
};
function Children(name) {
Parent.call(this);
this.name = name;
}
Children.prototype = Object.create(Parent.prototype);
Children.prototype.constructor = Children;
6. 类数组转化为数组的方法
const arrayLike=document.querySelectorAll('div')
// 1.扩展运算符
[...arrayLike]
// 2.Array.from
Array.from(arrayLike)
// 3.Array.prototype.slice
Array.prototype.slice.call(arrayLike)
// 4.Array.apply
Array.prototype.splice.call(arrayLike, 0);
// 5.Array.prototype.concat
Array.prototype.concat.apply([], arrayLike)
7. queryString
let urlStr = 'http://www.inode.club?name=koala&study=js&study=node'
function queryString(request) {
let arr = request.split('?')[1].split('&')
let res = {}
arr.forEach((item) => {
let [key, value] = item.split('=')
if (res[key]) {
res[key] = [].concat(res[key], value)
} else {
res[key] = value
}
})
return res
}
console.log(queryString(urlStr))
8. 转化驼峰命名
var s1 = 'get-element-by-id'
// 转化为 getElementById
var f = function (s) {
return s.replace(/-\w/g, function (x) {
return x.slice(1).toUpperCase()
})
}
9. 字符串模板
function render(template, data) {
// 模板字符串正则
const reg = /\{\{(\w+)\}\}/
// 判断模板里是否有模板字符串
if (reg.test(template)) {
// 查找当前模板里第一个模板字符串的字段
const name = reg.exec(template)[1]
// 将第一个模板字符串渲染
template = template.replace(reg, data[name])
// 递归的渲染并返回渲染后的结构
return render(template, data)
}
// 如果模板没有模板字符串直接返回
return template
}
let template = '我是{{name}},年龄{{age}},性别{{sex}}'
let person = {
name: '布兰',
age: 12,
}
// 我是布兰,年龄12,性别undefined
render(template, person)
部2
1. 函数柯里化
function curry(fn) {
return function judge(...args) {
if (args.length >= fn.length) return fn(...args)
return function (...arg) {
judge(...args, ...arg)
}
}
}
function add(a, b, c) {
return a + b + c
}
add(1, 2, 3)
let addCurry = curry(add)
addCurry(1)(2)(3)
2. Object.is 实现
// Object.is不会转换被比较的两个值的类型,这点和===更为相似,他们之间也存在一些区别。
// 1. NaN在===中是不相等的,而在Object.is中是相等的
// 2. +0和-0在===中是相等的,而在Object.is中是不相等的
// 实现代码如下:
Object.is = function (x, y) {
if (x === y) {
// 当前情况下,只有一种情况是特殊的,即 +0 -0
// 如果 x !== 0,则返回true
// 如果 x === 0,则需要判断+0和-0,则可以直接使用 1/+0 === Infinity 和 1/-0 === -Infinity来进行判断
return x !== 0 || 1 / x === 1 / y
}
// x !== y 的情况下,只需要判断是否为NaN,如果x!==x,则说明x是NaN,同理y也一样
// x和y同时为NaN时,返回true
return x !== x && y !== y
}
数组排序
1. 冒泡排序
function bubble(arr) {
for (let i = arr.length - 1; i > 0; i--) {
for (let j = 0; j < i; j++) {
if (arr[j+1] < arr[j]) {
let temp = arr[j + 1]
arr[j + 1] = arr[j]
arr[j] = temp
}
}
}
return arr
}
2. 选择排序
function selection(arr) {
for (let i = 0; i < arr.length - 1; i++) {
for (let j = i + 1; j < arr.length; j++) {
if (arr[j] < arr[i]) {
;[arr[i], arr[j]] = [arr[j], arr[i]]
}
}
}
return arr
}
3. 插入排序
function insertionSort(arr) {
let len = arr.length
let preIndex, current
for (let i = 1; i < len; i++) {
preIndex = i - 1
current = arr[i]
while (preIndex >= 0 && arr[preIndex] > current) {
arr[preIndex + 1] = arr[preIndex]
preIndex--
}
arr[preIndex + 1] = current
}
return arr
}
图片懒加载
1.clientHeight, scrollTop, offsetTop
let imgs = document.getElementsByTagName('img')
let count = 0
// 首次加载
lazyLoad()
// 通过监听 scroll 事件来判断图片是否到达视口,别忘了防抖节流
window.addEventListener('scroll', throttle(lazyLoad, 160))
function lazyLoad() {
let clientHeight = document.documentElement.clientHeight //视口高度
//滚动条卷去的高度
let scrollTop = document.documentElement.scrollTop || document.body.scrollTop
for (let i = count; i < imgs.length; i++) {
// 元素现在已经出现在视口中
if (imgs[i].offsetTop < scrollTop + clientHeight) {
if (imgs[i].getAttribute('src') !== 'default.jpg') continue
imgs[i].src = imgs[i].getAttribute('data-src')
count++
}
}
}
2.getBoundingClientRect
dom 元素的 getBoundingClientRect().top 属性可以直接判断图片是否出现在了当前视口。
// 只修改一下 lazyLoad 函数
function lazyLoad() {
for (let i = count; i < imgs.length; i++) {
if (
imgs[i].getBoundingClientRect().top <
document.documentElement.clientHeight
) {
if (imgs[i].getAttribute('src') !== 'default.jpg') continue
imgs[i].src = imgs[i].getAttribute('data-src')
count++
}
}
}
3. IntersectionObserver
IntersectionObserver 浏览器内置的 API,实现了监听 window 的 scroll 事件、判断是否在视口中 以及 节流 三大功能。该 API 需要 polyfill。
let imgs = document.getElementsByTagName('img')
const observer = new IntersectionObserver((changes) => {
for (let i = 0, len = imgs.length; i < len; i++) {
let img = imgs[i]
// 通过这个属性判断是否在视口中,返回 boolean 值
if (img.isIntersecting) {
const imgElement = img.target
imgElement.src = imgElement.getAttribute('data-src')
observer.unobserve(imgElement) // 解除观察
}
}
})
Array.from(imgs).forEach((item) => observer.observe(item)) // 调用