js 算法
通常采用大 O 表示法来表示复杂度。它并不代表真正的执行时间或存储空间消耗,而是表示代码执行时间随数据规模增长的变化趋势(时间复杂度)或存储空间随数据规模增长的变化趋势(空间复杂度),所以,也叫作渐进时间(或空间)复杂度(asymptotic time complexity),简称时间(或空间)复杂度。
常见复杂度
o(N)
function test(num) {
let total = 0
for(let i =0;i<num;i++) {
total +=i
}
return total
}
console.log(test(100));
O(1)
function test(num) {
let i= num
let j = 2*num
return i+j
}
console.log(test(100));
O(logN)
function test(num) {
let i= 1
while(i <num) {
i = i*2
}
return i
}
console.log(test(100));
O(M+N)
function test(num1,num2) {
let total = 0
for(let i =0;i<num1;i++) {
total += i
}
for(let j =0;j<num2;j++) {
total +=j
}
return total
}
console.log(test(100,90));
o(n*logn)
function test(num1,num2) {
let total =0;
let j =0;
for(let i=0;i<num1;i++) {
while(j <num2) {
total = i + j
j = j+2;
}
}
return total
}
console.log(test(10,100));
多项式量级:
常量阶:O(1):当算法中不存在循环语句、递归语句,即使有成千上万行的代码,其时间复杂度也是Ο(1)
对数阶:O(logn): 简单介绍一下
let i=1;
while (i <= n) {
i = i * 2;
}
-
每次循环 i 都乘以 2 ,直至 i > n ,即执行过程是:20、21、22、…、2k、…、2x、 n 所以总执行次数 x ,可以写成 2x = n ,则时间复杂度为 O(log2n) 。这里是 2 ,也可以是其他常量 k ,时间复杂度也是:O(log~3~n) = O(log32 * log2n) = O(log2n)
-
线性阶:O(n)
-
线性对数阶:O(nlogn)
-
平方阶、立方阶、….、k次方阶:O(n2)、O(n3)、…、O(nk)
非多项式量级
-
指数阶:O(2n)
-
阶乘阶:O(n!)
复杂度的划分最好时间复杂度:在最理想的情况下,执行这段代码的时间复杂度最坏时间复杂度:在最糟糕的情况下,执行这段代码的时间复杂度平均时间复杂度:所有情况下,求一个平均值,可以省略掉系数、低阶、常量
数组
优点:随机访问,可以通过下标随机访问数组中的任意位置上的数据
缺点:对数据的删除和插入不是很友好
查找:根据下标随机访问的时间复杂度为 O(1)
插入或者删除:时间复杂度为 O(n)在 JavaScript 中的数组几乎是万能的,它不光可以作为一个普通的数组使用,可以作为栈或队列使用
广度优先遍历
let obj = {
a: 1,
b: 2,
c: {
e: 3,
f: 4
},
g: null,
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
function copy(obj) {
let bfs = function (obj) {
let queue = [obj], target = {}, list = [target]
while (queue.length != 0) {
let item = queue.shift()
let temp = list.shift()
for (const key in item) {
if (typeof item[key] === "object" && typeof item[key] != null) {
queue.push(item[key])
temp[key] = Array.isArray(item[key]) ? [] : {}
list.push(temp[key])
} else {
temp[key] = item[key]
}
}
}
return target;
}
return bfs(obj)
}
let result = copy(obj)
result.g = 3;
console.log(obj)
console.log(result)
全排列BFS
function permute(nums) {
const list = []
backTrack(list, [], nums)
return list
}
function backTrack(list, templist, nums) {
if (templist.length === nums.length) {
list.push(templist.slice(0))
} else {
for (let i = 0; i < nums.length; i++) {
if (templist.includes(nums[i])) {
continue
}
templist.push(nums[i])
backTrack(list, templist, nums)
templist.pop()
}
}
}
let array = [1, 2, 3]
console.log(permute(array));
二分查找
var arr = [1, 8, 9, 12, 22, 28, 32, 44];
function binarySearch(target) {
var start = 0, end = arr.length - 1, element, middle;
while (start <= end) {
middle = start + Math.floor((end - start) /2)
element = arr[middle]
if(target === element) {
return middle
} else if(target > element) {
start = middle + 1
} else if(target < element){
end = middle - 1
}
}
return -1
}
console.log(binarySearch(28));
无重复最长子串
let s = "abcabcbb"
function longestSubString (str) {
let sub = []
let max = 0
for(let i =0;i<str.length;i++) {
let index = sub.indexOf(str[i])
if(index === -1) {
sub.push(str[i])
} else {
sub = sub.slice(index + 1,sub.length)
sub.push(s[i])
}
max = Math.max(max,sub.length)
}
return max
}
console.log(longestSubString(s))
删除数组中部分元素
function pull(arr, ...args) {
const result = []
for (let i = 0; i < arr.length; i++) {
let item = arr[i]
if (args.includes(item)) {
result.push(item)
arr.splice(i, 1)
i--
}
}
return result
}
function pullAll(arr1,arr2) {
return pull(arr1,...arr2)
}
let array = [1, 2, 3, 4, 5, 6, 8]
// console.log(pull(array,2,3))
console.log(pullAll(array,[1,3,4]))
console.log(array)
数组去重
let array = [1,2,2,2,3,4,3,1,1,2]
let set = new Set(array)
console.log([...set])
let array = [1,2,2,2,3,4,3,1,1,2]
function unique(array) {
return array.filter((item,index,array)=>{
return array.indexOf(item) === index
})
}
console.log(unique(array))
let array = [1,2,2,2,3,4,3,1,1,2]
function unique(array) {
let result = []
array.forEach(element => {
if(result.indexOf(element) === -1) {
result.push(element)
}
});
return result
}
console.log(unique(array))
let array = [1,2,2,2,3,4,3,1,1,2]
function unique(array) {
let result = []
const obj = {}
array.forEach(element => {
if(!obj[element]) {
obj[element] = true
result.push(element)
}
});
return result
}
console.log(unique(array))
字符串反转
function reverseString(strIn, pos, strOut) {
if(pos < 0) {
return strOut
}
strOut += strIn.charAt(pos--)
return reverseString(strIn,pos,strOut)
}
let str = "Hello World"
let pos = str.length - 1
let result = ''
console.log(reverseString(str, pos, result))
function reverseString(str) {
let arr = Array.prototype.slice.call(str)
return arr.reverse().join('')
}
let str = "Hello World"
console.log(reverseString(str))
function reverseString(str) {
return str.split("").reverse().join("")
}
let str = "Hello World"
console.log(reverseString(str))
function reverseString(str) {
let result = []
let array = str.split("")
while(array.length) {
result.push(array.pop())
}
return result.join("")
}
let str = "Hello World"
console.log(reverseString(str))
字符串截取
function truncate(str,size) {
return str.length > num ? str.slice(0, num) + '...' : str
}
let str = "Hello World"
console.log(truncate(str,2))
字符串出现最多的字符
function getMaxCount(str) {
let maxCount = 0
let maxCountChar = ''
let json = {}
for(let i =0;i<str.length;i++) {
let char = str[i]
if(json[char]) {
json[char]++
} else {
json[char] = 1
}
}
for(let key in json) {
if(json[key] > maxCount) {
maxCount = json[key]
maxCountChar = key
}
}
return maxCount
}
console.log(getMaxCount("helloworldddd"))
function getMaxCount(str) {
let maxCount = 0
let maxCountChar = ''
while(str) {
let char = str[0]
let length = str.length
let reg = new RegExp(char,'g')
str = str.replace(reg,'')
let restLength = str.length
let charCount = length - restLength
if(charCount > maxCount) {
maxCount = charCount
maxCountChar = char
}
}
return maxCount
}
console.log(getMaxCount("helloworldddd"))
function getMaxCount(str) {
let maxCount = 0
let maxCountChar = ''
str = str.split('').sort().join('')
for(let i =0,j= str.length;i<j;i++) {
let char = str[i]
let charCount = str.lastIndexOf(char) - i + 1
if(charCount > maxCount) {
maxCount = charCount
maxCountChar =char
}
i = str.lastIndexOf(char)
}
return maxCount
}
console.log(getMaxCount("helloworldddd"))
去除字符串中重复字符
function removeDuplicateChar(str) {
let result = ''
for(let i =0;i<str.length;i++) {
if(result.indexOf(str[i]) < 0) {
result+=str[i]
}
}
return result
}
console.log(removeDuplicateChar("helloworld"))
function removeDuplicateChar(str) {
let result = ''
let json = {}
for(let i =0;i<str.length;i++) {
let char = str[i]
if(!json[char]) {
result +=char
json[char] = true
}
}
return result
}
console.log(removeDuplicateChar("helloworld"))
function removeDuplicateChar(str) {
let array = str.split('')
let newArray = array.filter((item,index,array)=>{
return array.indexOf(item) === index
})
return newArray.join('')
}
console.log(removeDuplicateChar("helloworld"))
function removeDuplicateChar(str) {
let newArray = Array.prototype.filter.call(str,(item,index,array)=>{
return array.indexOf(item) === index
})
return newArray.join('')
}
console.log(removeDuplicateChar("helloworld"))
function removeDuplicateChar(str) {
let set = new Set(str.split(''))
return [...set].join('')
}
console.log(removeDuplicateChar("helloworld"))
素数
let isPrime = function(number) {
if(number === 2) {
return true
}
let square = Math.sqrt(number)
for(let i =2;i<=square;i++) {
if(number % i === 0) {
return false
}
}
return true
}
合并对象
function mergeObject(...objs) {
const result = {}
objs.forEach(obj=>{
Object.keys(obj).forEach(key=>{
if(result.hasOwnProperty(key)) {
result[key] = [].concat(result[key],obj[key])
} else {
result[key] = obj[key]
}
})
})
return result
}
const object = {
a: [{ x: 2 }, { y: 4 }],
b: 1,
c:"bar"
}
const other = {
a: { z: 3 },
b: [2, 3],
c: 'foo'
}
console.log(mergeObject(object, other))
重复字符串
function repeat(target,n) {
if(n === 1) {
return target
}
return [].concat([target],repeat(target,n-1))
}
let str = repeat('abc',4).join('')
console.log(str)
function repeat(target,n) {
return Array(n+1).join(target)
}
let str = repeat('abc',4)
console.log(str)
function repeat(target,n) {
return Array.prototype.join.call({length:n+1},target)
}
let str = repeat('abc',4)
console.log(str)
let str = "abc"
console.log(str.repeat(4))
字符串回文
function palindrome(str) {
return reverseStr(str) === str
}
function reverseStr(str) {
let array = [...str]
return array.reverse().join("")
}
let str = "HeeH"
console.log(palindrome(str))
function isPalindromeStr(str) {
if(!str.length) return true
str = str.toLowerCase().split('')
let start = 0
let end = str.length - 1
while(start < end) {
if(str[start] === str[end]) {
start++
end--
} else {
return false
}
}
return true
}
// let str ="abcdcba"
let str ="abcdcbag"
console.log(isPalindromeStr(str))
function isPalindromeStr(str) {
if (str.length <= 1) {
return true
}
str = str.toLowerCase()
let startValue = str[0]
let endValue = str[str.length - 1]
if (startValue === endValue) {
return isPalindromeStr(str.slice(1, str.length - 1))
} else {
return false
}
}
// let str = "abcdcba"
let str ="abcdcbag"
console.log(isPalindromeStr(str))
生成测试数据
let array = [...Array(100).keys()].map((i,index)=>index + 1)
let array1 = Array.from(Array(100),(i,index)=>index+1)
console.log(array)
console.log(array1)
数组扁平化
let array = [1, 2, 3, [4, 5], [6, 7, 8]]
function flattern(arr) {
var result = []
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flattern(arr[i]))
} else {
result.push(arr[i])
}
}
return result
}
let array = [1, 2, 3, [4, 5], [6, 7, 8, [9, 10]]]
function flattern(arr) {
while(arr.some(item=>Array.isArray(item))) {
arr = [].concat(...arr)
}
return arr
}
console.log(flattern(array))
let array = [1, 2, 3, [4, 5], [6, 7, 8, [9, 10]]]
function flattern(arr) {
arr = arr.toString().split(",")
var result = arr.map(item=>{
return Number(item)
})
return result
}
console.log(flattern(array))
let arr = [1, [2, [3, 4]]];
function flatten(arr) {
return arr.reduce(function(prev, next){
return prev.concat(Array.isArray(next) ? flatten(next) : next)
}, [])
}
console.log(flatten(arr));// [1, 2, 3, 4,5]
let arr = [1, [2, [3, [4, 5]]], 6];
function flatten(arr) {
let str = JSON.stringify(arr);
str = str.replace(/(\[|\])/g, '');
str = '[' + str + ']';
return JSON.parse(str);
}
console.log(flatten(arr)); // [1, 2, 3, 4,5]
concat
let array = [1,2,4]
function concat(array,...args) {
const result =[...array]
args.forEach(item => {
if(Array.isArray(item)) {
result.push(...item)
} else {
result.push(item)
}
});
return result
}
console.log(concat(array,[7,5,6],9,10))
数组map
const array = [1,2,3,4,4,5]
function map(arr,callback) {
let result = []
for(let i=0;i<arr.length;i++) {
result.push(callback(arr[i]))
}
return result;
}
const result = map(array,item=>{
return item*10
})
console.log(result)
数组find
let array = [1,2,1002,111]
function find(array,callback) {
for(let i =0;i<array.length;i++) {
let res= callback(array[i],i)
if(res) {
return array[i]
}
}
return undefined
}
console.log(find(array,item=>item>1000))
数组some
let array =[1,2,3,4,5,3,7]
function some(array,callback) {
for(let i=0;i<array.length;i++) {
if(callback(array[i])) {
return true
}
}
return false
}
console.log(some(array, (item)=>{
return item > 5
}))
数组every
let array = [1, 2, 3, 4, 5, 3, 7]
function every(array, callback) {
for (let i = 0;i<array.length; i++) {
if(!callback(array[i])) {
return false
}
}
return true
}
console.log(every(array, (item)=>{
return item > 10
}))
数组reduce
function reduce(array,callback,initValue) {
let result = initValue
for(let i =0;i<array.length;i++) {
result = callback(result,array[i])
}
return result
}
let array = [1,2,3,4,5]
let result = reduce(array,function(res,value){
return res + value
},10)
console.log(result)
数组filter
let array = [1,3,4,5,5,6]
function filter(array,callback) {
let result =[]
for(let i =0;i<array.length;i++) {
let res = callback(array[i])
if(res) {
result.push(array[i])
}
}
return result
}
let result = filter(array,item=>item%2 === 0)
console.log(result)
数组slice
export function slice (array, begin, end) {
// 如果当前数组是[], 直接返回[]
if (array.length === 0) {
return []
}
// 如果begin超过最大下标, 直接返回[]
begin = begin || 0
if (begin >= array.length) {
return []
}
// 如果end不大于begin, 直接返回[]
end = end || array.length
if (end > array.length) {
end = array.length
}
if (end <= begin) {
return []
}
// 取出下标在[begin, end)区间的元素, 并保存到最终的数组中
const arr = []
for (let index = begin; index < end; index++) {
arr.push(array[index])
}
return arr
}
数字出现的次数
function keywordCount(arr) {
let result = arr.reduce(function(pre,cur) {
if(!pre[cur]) {
pre[cur] = 1
} else {
pre[cur]++
}
return pre
},{})
return result
}
let c = [1,2,3,2,2,5,1]
console.log(keywordCount(c))
获取数组中部分元素
function drop(array,size =1) {
return array.filter((item,index)=>index >= size)
}
let array =[1,2,3,4,5]
console.log(drop(array,2))
删除数组中部分元素
function pull(arr, ...args) {
const result = []
for (let i = 0; i < arr.length; i++) {
let item = arr[i]
if (args.includes(item)) {
result.push(item)
arr.splice(i, 1)
i--
}
}
return result
}
function pullAll(arr1,arr2) {
return pull(arr1,...arr2)
}
let array = [1, 2, 3, 4, 5, 6, 8]
// console.log(pull(array,2,3))
console.log(pullAll(array,[1,3,4]))
console.log(array)
数组trunk
function split(item,num) {
if(item.length <=0) {
return item
}
let groupSize = Math.ceil(item.length / num)
return chunk(item,groupSize)
}
function chunk(item,size) {
if(item.length <=0 || size <=0) {
return item
}
let chunks = []
for(let i =0;i<item.length;i+=size) {
chunks.push(item.slice(i,i+size))
}
return chunks
}
let array = [1,2,3,4,4,5,5,6,5,56,6565,6,566,5,56,65,5665,56,222]
console.log(split(array,6))
function chunk(arr,size = 1) {
if(arr.length === 0) {
return []
}
let result =[]
let tmp = []
arr.forEach(item => {
if(tmp.length === 0) {
result.push(tmp)
}
tmp.push(item)
if(tmp.length === size) {
tmp =[]
}
});
return result
}
let array = [1,2,3,4,4,5,5,6,5,56,6565,6,566,5,56,65,5665,56,222]
console.log(chunk(array,6))
数组差异化
function difference(arr1,arr2) {
if(arr1.length === 0) {
return []
}
if(arr2.length === 0) {
return arr1
}
return arr1.filter(item => !arr2.includes(item))
}
let arr1= [1,3,4]
let arr2 =[2,5,6,1]
console.log(difference(arr1,arr2))
数组转tree
const arr = [
{ id: 1, parentId: null, name: 'a' },
{ id: 2, parentId: null, name: 'b' },
{ id: 3, parentId: 1, name: 'c' },
{ id: 4, parentId: 2, name: 'd' },
{ id: 5, parentId: 1, name: 'e' },
{ id: 6, parentId: 3, name: 'f' },
{ id: 7, parentId: 4, name: 'g' },
{ id: 8, parentId: 7, name: 'h' },
]
function array2Tree(array) {
const result = []
const map = array.reduce((pre,cur)=>{
pre[cur.id] = cur
return pre
},{})
for(let item of array) {
if(item.parentId === null) {
result.push(item)
continue
}
if(item.parentId in map) {
const parent = map[item.parentId]
parent.children = parent.children || []
parent.children.push(item)
}
}
return result
}
console.log(array2Tree(arr))
tree转array
const data = [{
"id": 1, "parentId": null, "name": "a",
"children": [{
"id": 3, "parentId": 1, "name": "c",
"children": [{ "id": 6, "parentId": 3, "name": "f" }]
},
{ "id": 5, "parentId": 1, "name": "e" }]
},
{
"id": 2, "parentId": null, "name": "b",
"children": [{
"id": 4, "parentId": 2, "name": "d",
"children": [{
"id": 7, "parentId": 4, "name": "g",
"children": [{ "id": 8, "parentId": 7, "name": "h" }]
}]
}]
}]
function flattern(array) {
return array.reduce((pre,cur)=>{
const {id,name,parentId,children = []} = cur
return pre.concat([{id,name,parentId}],flattern(children))
},[])
}
console.log(flattern(data))
获取数组中元素最小值和最大值
Array.prototype.min = function() {
let min = this[0]
let len = this.length
for(let i=1;i<len;i++) {
if(this[i] < min) {
min = this[i]
}
}
return min
}
Array.prototype.max = function() {
let max = this[0]
let len = this.length
for(let i=1;i<len;i++) {
if(this[i] > max) {
max = this[i]
}
}
return max
}
let array = [2,10,6,8,7,1,88]
console.log(array.min(),array.max())
Array.prototype.min = function() {
return Math.min.apply(null,this)
}
Array.prototype.max = function() {
return Math.max.apply(null,this)
}
let array = [2,10,6,8,7,1,88]
console.log(array.min(),array.max())
Array.prototype.min = function () {
return this.reduce((pre, cur) => {
const result = pre > cur ? cur : pre
return result
})
}
Array.prototype.max = function () {
return this.reduce((pre, cur) => {
const result = pre < cur ? cur : pre
return result
})
}
let array = [2, 10, 6, 8, 7, 1, 88]
console.log(array.min(), array.max())
let array = [2, 10, 6, 8, 7, 1, 88]
const sort = array.sort((a,b)=> a-b)
console.log(sort)
let array = [2, 10, 6, 8, 7, 1, 88]
console.log(Math.min(...array),Math.max(...array))
数字千分化
function thousandNum(number = 0) {
const arr = (+number).toString().split('.')
const intNum = arr[0]
const floatNum = arr[1]
const getInt = (nums) => {
return nums.split('').reverse().reduceRight((t, v, i) => {
let result =t + (i % 3 ? v : `${v},`)
return result
}, '').replace(/^,|,$/g, '')
}
const getFloat = (nums) => {
return nums.split('').reduce((t, v, i) => {
return t + ((i + 1) % 3 ? v : `${v},`)
}, '').replace(/^,|,$/g, '')
}
return arr.length > 1 ? `${getInt(intNum)}.${getFloat(floatNum)}` : `${getInt(intNum)}`
}
console.log(thousandNum(1234.5678))
apply
function apply(fn, obj, args) {
if (obj === null || obj === undefined) {
obj = window
}
obj.tempFn = fn;
const result = obj.tempFn(...args)
delete obj.tempFn
return result
}
var m = 11
function f(a, b) {
console.log(a, b, this.m, this)
return a + b
}
const obj = { m: 22 }
console.log(apply(f, obj, [1, 2, 3]))
// Function.prototype.myApply = function(context,args) {
// context = context || window;
// args = args ? args : []
// const key = Symbol()
// context[key] = this;
// const result =context[key](...args)
// delete context[key]
// return result;
// }
// let map = {}
// map["1"] = ["1","2","3"]
// map["2"] = ["4","5","6"]
// map["3"] = ["7","8","9"]
// array.set("1",["1","2","3"])
// array.set("2",["4","5","6"])
// array.set("3",["7","8","9"])
// let array1 = [...array.get("1") , ...array.get("2"),...array.get("3")]
// console.log(array.keys().length)
// console.log(array1)
// console.log(Object.keys(map).length)
bind
function call(fn, obj, ...args) {
if (obj === null || obj === undefined) {
obj = window
}
obj.tempFn = fn
const result = obj.tempFn(...args)
delete obj.tempFn
return result
}
function bind(fn, obj, ...args) {
console.log("bind")
return (...args2) => {
return call(fn, obj, ...args, ...args2)
}
}
var m = 11
function f(a, b) {
console.log(a, b, this.m, this)
return a + b
}
const obj = { m: 22 }
console.log(bind(f, obj, 4)(1, 2))
call
function call(Fn, obj, ...args) {
if (obj === undefined || obj === null) {
obj = globalThis
}
obj.tempFn = Fn
let result = obj.tempFn(...args)
delete obj.tempFn
return result
}
function add(a, b) {
return a + b + this.c
}
let obj = {
c: 21
}
window.c = 1314
console.log(call(add, obj, 10, 20))
console.log(call(add, null, 10, 20))
map
function myMap(array,callback) {
const arr =[]
for(let i =0;i<array.length;i++) {
arr.push(callback(array[i],i))
}
return arr
}
事件总线
const eventBus = {}
let callbackObj = {}
eventBus.on = function(eventName,callback) {
const callbacks = callbackObj[eventName]
if(callbacks) {
callbacks.push(callback)
} else {
callbackObj[eventName] = [callback]
}
}
// eventBus.on('delete', (data) => {
// console.log('delete', data)
// })
// eventBus.off('add')
// eventBus.off()
// eventBus.emit('add', 123)
// eventBus.emit('delete', 'abc')
函数节流
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
// 减少一段时间的触发频率
// function throttle(callback,wait) {
// let start = 0
// return function(e) {
// let now = Date.now()
// if(now - start >=wait) {
// callback.call(this,e)
// start = now
// }
// }
// }
function throttle(callback,wait) {
let start = 0
return function(e) {
let now = Date.now()
if(now - start>= wait) {
callback.call(this,e)
start = now
}
}
}
window.addEventListener('scroll', throttle(function(e){
console.log(e);
}, 500));
</script>
<style>
body{
height:2000px;
background:linear-gradient(#125, #eae);
}
</style>
<script>
</script>
</head>
<body>
</body>
</html>
函数防抖
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<input type="text">
<script>
// 在一定时间间隔内,将多次触发变成一次触发
// 高频触发N秒只会执行一次
// function debounce(fn, delay) {
// let timerId = null
// return function (e) {
// if (timerId != null) {
// clearTimeout(timerId)
// }
// timerId = setTimeout(() => {
// fn.call(this, e)
// timerId = null
// }, delay)
// }
// }
// function debounce(fn,delay) {
// let timerId = null
// return ()=>{
// if(timerId) {
// clearTimeout(timerId)
// }
// timerId = setTimeout(() => {
// fn()
// }, delay);
// }
// }
// function debounce(fn,delay) {
// let t = null
// return function() {
// if(t) {
// clearTimeout(t)
// }
// t = setTimeout(() => {
// fn.apply(this,arguments)
// }, delay);
// }
// }
function debounce(fn,delay) {
let timerId = null
return function() {
if(timerId) {
clearTimeout(timerId)
}
timerId = setTimeout(() => {
fn.apply(this,arguments)
}, delay);
}
}
function getInputValue() {
console.log(input.value)
}
let input = document.querySelector("input")
input.addEventListener("input",debounce(getInputValue,1000))
</script>
</body>
</html>
触发第一次
var btn = document.getElementById("btn")
btn.addEventListener("click",debounce(submit,1000),false)
function debounce(fn, delay) {
var t = null
return function() {
var firstClick = !t
if (t) {clearTimeout(t)}
if (firstClick) {
fn.apply(this, arguments)
}
t = setTimeout(() => {
t = null
}, delay);
}
}
function submit(e) {
console.log(1)
}
instanceof
function Person() {
}
let p = new Person()
function myInstanceOf(obj,Fn) {
let prototype = Fn.prototype
let proto = obj.__proto__
while(proto) {
if(proto === prototype) {
return true
}
proto = proto.__proto__
}
return true
}
console.log(myInstanceOf(p,Person))
newInstance
function Person(name,age) {
this.name = name
this.age = age
}
function newInstance(Fn,...args) {
// 创建新对象 修改函数内部this指向并执行 返回新对象
const obj = {}
const result =Fn.call(obj,...args)
// 修改新对象的原型对象
obj.__proto__ = Fn.prototype
return result instanceof Object ? result: obj
}
let obj = newInstance(Person,"张三",18)
console.log(obj)
浅拷贝
function shallowCopy(obj) {
if (typeof obj !== "object") return
let newObj = Array.isArray(obj) ? [] : {}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
newObj[key] = obj[key]
}
}
return newObj
}
let obj = {
a: 1,
b: 2,
c: {
e: 3,
f: 4
},
g: null,
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
let newObj = shallowCopy(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
function clone1(target) {
if(typeof target === "object" &&target!== null) {
if(Array.isArray(target)) {
return [...target]
} else {
return {...target}
}
} else {
return target
}
}
let obj = {
a: 1,
b: 2,
c: {
e: 3,
f: 4
},
g: null,
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
let newObj = clone1(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
深拷贝
简写版本
var deepClone = function (obj) {
if (typeof obj !== "object") {
return obj
}
let newObj = Array.isArray(obj) ? [] : {}
for (let key in obj) {
newObj[key] = typeof obj[key] === "object" ? deepClone(obj[key]) : obj[key]
}
return newObj
}
let obj = {
a: 1,
b: ['e','f','g'],
c:{f:20},
d:{h:20},
g: null,
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
obj.b.push(obj.d)
obj.d.h = obj.b
function deepClone(obj,map = new WeakMap()) {
if (typeof obj === "object" && obj !== null) {
let cache = map.get(obj)
if(cache) {
return cache
}
const result =Array.isArray(obj)? []:{}
map.set(obj,result)
for(let key in obj) {
if(obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key],map)
}
}
return result
} else {
return obj
}
}
let newObj = deepClone(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
let obj = {
a: 1,
b: ['e', 'f', 'g'],
c: { f: 20 },
d: { h: 20 },
g: null,
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
obj.b.push(obj.d)
obj.d.h = obj.b
// for in 的循环性能循环很差。性能差的原因是因为: for in 会迭代对象原型链上一切 可以枚举的属性
function deepClone(obj, map = new WeakMap()) {
if(typeof obj ==="object" && obj !== null) {
let cache = map.get(obj)
if(cache) {
return cache
}
let isArray = Array.isArray(obj)
let result = isArray ?[]:{}
map.set(obj,result)
if(isArray) {
obj.forEach((item,index) => {
result[index] = deepClone(item,map)
});
} else {
Object.keys(obj).forEach(key=>{
result[key] = deepClone(obj[key],map)
})
}
return result
} else {
return obj
}
}
let newObj = deepClone(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
let obj = {
a: 1,
b: 2,
c: {
e: 3,
f: 4
},
g: null,
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
function deepClone(obj) {
var _obj = JSON.stringify(obj)
var objClone = JSON.parse(_obj)
return objClone
}
let newObj = deepClone(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
// lodash函数库实现深拷贝 let result = _.cloneDeep(test)
function deepClone(obj) {
if(typeof obj ==="object" && obj !== null) {
const result = Array.isArray(obj)?[]:{}
for (let key in obj) {
if (obj.hasOwnProperty(key)) {
result[key] = deepClone(obj[key])
}
}
return result
} else {
return obj
}
}
let obj = {
a: 1,
b: 2,
c: {
e: 3,
f: 4
},
g: null,
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
let newObj = deepClone(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
const isObject = (target)=>{
if((typeof target === "object" || typeof target === "function")&&target!=null){
return true
}
return false
}
function deepClone(target,map = new WeakMap()) {
if(map.get(target)) {
return target
}
let constructor = target.constructor
if(/^(RegExp|Date)$/i.test(constructor.name)) {
return new constructor(target)
}
if(isObject(target)) {
map.set(target,true)
let cloneTarget = Array.isArray(target)?[]:{}
for(let prop in target) {
if(target.hasOwnProperty(prop)) {
cloneTarget[prop] = deepClone(target[prop],map)
}
}
return cloneTarget
} else {
return target
}
}
let obj = {
a: 1,
b: 2,
c: {
e: 3,
f: 4
},
g: {},
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
let newObj = deepClone(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
const isObject = (target) => (typeof target === "object" || typeof target === "function") && target !== null;
function deepClone(target, map = new WeakMap()) {
if (map.get(target)) {
return target;
}
// 获取当前值的构造函数:获取它的类型
let constructor = target.constructor;
// 检测当前对象target是否与正则、日期格式对象匹配
if (/^(RegExp|Date)$/i.test(constructor.name)) {
// 创建一个新的特殊对象(正则类/日期类)的实例
return new constructor(target);
}
if (isObject(target)) {
map.set(target, true); // 为循环引用的对象做标记
const cloneTarget = Array.isArray(target) ? [] : {};
for (let prop in target) {
if (target.hasOwnProperty(prop)) {
cloneTarget[prop] = deepClone(target[prop], map);
}
}
return cloneTarget;
} else {
return target;
}
}
let obj = {
a: 1,
b: 2,
c: {
e: 3,
f: 4
},
g: {},
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
let newObj = deepClone(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
const _toString = Object.prototype.toString
function getType(obj) {
return _toString.call(obj).slice(8, -1)
}
function DFSDeepClone(obj, visited = new Set(), level = 0) {
let res = {}
if (getType(obj) === "Object" || getType(obj) === "Array") {
if (visited.has(obj)) {
res = obj
} else {
visited[level] = obj
visited.add(obj)
res = getType(obj) === "Object" ? {} : []
Reflect.ownKeys(obj).forEach(k => {
res[k] = DFSDeepClone(obj[k], visited, level + 1)
})
}
} else if(typeof obj === "function") {
res = eval(`${obj.toString()}`)
} else {
res = obj
}
return res
}
let obj = {
a: 1,
b: 2,
c: {
e: 3,
f: 4
},
g: {},
h: [8, 9, 10],
name: 'test',
i: { j: 1, k: 2 }
}
let newObj = DFSDeepClone(obj)
newObj.i.j = 8
console.log(newObj)
console.log(obj)
寄生式组合继承
// 经典继承
function Animal() {
this.colors = ['black', 'white']
}
Animal.prototype.say = function() {
console.log("say")
}
function Dog() {
Animal.call(this)
}
if(!Object.create) {
Object.create = function(proto) {
function F(){}
F.prototype = proto
return new F()
}
}
Dog.prototype = Object.create(Animal.prototype)
var dog1 = new Dog()
dog1.colors.push("yellow")
var dog2 = new Dog()
console.log(dog1.colors)
console.log(dog2.colors)
dog1.say()
构造函数继承
// 构造函数继承没有办法拿到原型对象上的方法
function Animal() {
this.colors = ["black", 'green']
}
Animal.prototype.getColors = function () {
console.log(this.colors)
}
function Dog(name) {
Animal.call(this)
}
Dog.prototype = new Animal()
var dog1 = new Dog()
dog1.colors.push("yellow")
var dog2 = new Dog()
dog1.getColors()
dog2.getColors()
组合继承
// https://mp.weixin.qq.com/s/_hbGus_Yo2yi18dQEZqwXg
// 伪经典继承
function Animal(name) {
this.name = name
this.colors = ["black", "white"]
}
Animal.prototype.say = function () {
console.log("say")
}
Animal.prototype.getName = function () {
return this.name
}
function Dog(name, age) {
Animal.call(this, name)
this.age = age
}
Dog.prototype = new Animal()
Dog.prototype.constructor = Dog
let dog1 = new Dog('奶昔', 2)
dog1.colors.push('brown')
let dog2 = new Dog('哈赤', 1)
console.log(dog1)
console.log(dog2)
dog1.say()
dog2.say()
console.log(Dog.prototype === dog1.__proto__)
console.log(Dog.__proto__ === Function.prototype)
class继承
class Animal {
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
class Dog extends Animal {
constructor(name,age) {
super(name)
this.age = age
}
}
var dog1 = new Dog("大狗",1)
var dog2 = new Dog("二狗",2)
console.log(dog1.getName())
console.log(dog2.getName())
圣杯模式
var inherit = (function () {
var Buffer = function () { }
return function (Target, Origin) {
Buffer.prototype = Origin.prototype
Target.prototype = new Buffer()
Target.prototype.constructor = Target
Target.prototype.super_class = Origin
}
})()
function Teacher() { }
function Student() {
}
function Buffer() {
}
inherit(Student, Teacher)
Student.prototype.age = 18
var s = new Student()
var t = new Teacher()
console.log(s)
console.log(t)
手写题目
死磕 36 个 JS 手写题

浙公网安备 33010602011771号