防抖
function debounce ( func, ms = 1000 ) {
let timer;
return function ( ... args) {
if ( timer) {
clearTimeout ( timer)
}
timer = setTimeout ( ( ) => {
func. apply ( this , args)
} , ms)
}
}
const task = ( ) => { console. log ( 'run task' ) }
const debounceTask = debounce ( task, 1000 )
window. addEventListener ( 'scroll' , debounceTask)
节流
function throttle ( func, ms = 1000 ) {
let canRun = true
return function ( ... args) {
if ( ! canRun) return
canRun = false
setTimeout ( ( ) => {
func. apply ( this , args)
canRun = true
} , ms)
}
}
const task = ( ) => { console. log ( 'run task' ) }
const throttleTask = throttle ( task, 1000 )
window. addEventListener ( 'scroll' , throttleTask)
new
function myNew ( Func, ... args) {
const instance = { } ;
if ( Func. prototype) {
Object. setPrototypeOf ( instance, Func. prototype)
}
const res = Func. apply ( instance, args)
if ( typeof res === "function" || ( typeof res === "object" && res !== null ) ) {
return res
}
return instance
}
function Person ( name) {
this . name = name
}
Person. prototype. sayName = function ( ) {
console. log ( `My name is ${ this . name} ` )
}
const me = myNew ( Person, 'Jack' )
me. sayName ( )
console. log ( me)
bind
Function. prototype. myBind = function ( context = globalThis) {
const fn = this
const args = Array. from ( arguments) . slice ( 1 )
const newFunc = function ( ) {
const newArgs = args. concat ( ... arguments)
if ( this instanceof newFunc ) {
fn. apply ( this , newArgs)
} else {
fn. apply ( context, newArgs)
}
}
newFunc. prototype = Object. create ( fn. prototype)
return newFunc
}
const me = { name: 'Jack' }
const other = { name: 'Jackson' }
function say ( ) {
console. log ( `My name is ${ this . name || 'default' } ` ) ;
}
const meSay = say. myBind ( me)
meSay ( )
const otherSay = say. myBind ( other)
otherSay ( )
call
Function. prototype. myCall = function ( context = globalThis) {
const key = Symbol ( 'key' )
context[ key] = this
const args = [ ... arguments] . slice ( 1 )
const res = context[ key] ( ... args)
delete context[ key]
return res
} ;
const me = { name: 'Jack' }
function say ( ) {
console. log ( `My name is ${ this . name || 'default' } ` ) ;
}
say. myCall ( me)
apply
Function. prototype. myApply = function ( context = globalThis) {
const key = Symbol ( 'key' )
context[ key] = this
let res
if ( arguments[ 1 ] ) {
res = context[ key] ( ... arguments[ 1 ] )
} else {
res = context[ key] ( )
}
delete context[ key]
return res
}
const me = { name: 'Jack' }
function say ( ) {
console. log ( `My name is ${ this . name || 'default' } ` ) ;
}
say. myApply ( me)
deepCopy
function deepCopy ( obj, cache = new WeakMap ( ) ) {
if ( ! obj instanceof Object ) return obj
if ( cache. get ( obj) ) return cache. get ( obj)
if ( obj instanceof Function ) {
return function ( ) {
return obj. apply ( this , arguments)
}
}
if ( obj instanceof Date ) return new Date ( obj)
if ( obj instanceof RegExp ) return new RegExp ( obj. source, obj. flags)
const res = Array. isArray ( obj) ? [ ] : { }
cache. set ( obj, res)
Object. keys ( obj) . forEach ( ( key) => {
if ( obj[ key] instanceof Object ) {
res[ key] = deepCopy ( obj[ key] , cache)
} else {
res[ key] = obj[ key]
}
} ) ;
return res
}
const source = {
name: 'Jack' ,
meta: {
age: 12 ,
birth: new Date ( '1997-10-10' ) ,
ary: [ 1 , 2 , { a: 1 } ] ,
say ( ) {
console. log ( 'Hello' ) ;
}
}
}
source. source = source
const newObj = deepCopy ( source)
console. log ( newObj. meta. ary[ 2 ] === source. meta. ary[ 2 ] ) ;
console. log ( newObj. meta. birth === source. meta. birth) ;
事件总线 | 发布订阅模式
class EventEmitter {
constructor ( ) {
this . cache = { }
}
on ( name, fn) {
if ( this . cache[ name] ) {
this . cache[ name] . push ( fn)
} else {
this . cache[ name] = [ fn]
}
}
off ( name, fn) {
const tasks = this . cache[ name]
if ( tasks) {
const index = tasks. findIndex ( ( f) => f === fn || f. callback === fn)
if ( index >= 0 ) {
tasks. splice ( index, 1 )
}
}
}
emit ( name) {
if ( this . cache[ name] ) {
const tasks = this . cache[ name] . slice ( )
for ( let fn of tasks) {
fn ( ) ;
}
}
}
emit ( name, once = false ) {
if ( this . cache[ name] ) {
const tasks = this . cache[ name] . slice ( )
for ( let fn of tasks) {
fn ( ) ;
}
if ( once) {
delete this . cache[ name]
}
}
}
}
const eventBus = new EventEmitter ( )
const task1 = ( ) => { console. log ( 'task1' ) ; }
const task2 = ( ) => { console. log ( 'task2' ) ; }
eventBus. on ( 'task' , task1)
eventBus. on ( 'task' , task2)
setTimeout ( ( ) => {
eventBus. emit ( 'task' )
} , 1000 )
柯里化:只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
function curry ( func) {
return function curried ( ... args) {
if ( args. length >= func. length) {
return func. apply ( this , args)
}
return function ( ... args2) {
return curried. apply ( this , args. concat ( args2) )
}
}
}
function sum ( a, b, c) {
return a + b + c
}
const curriedSum = curry ( sum)
console. log ( curriedSum ( 1 , 2 , 3 ) )
console. log ( curriedSum ( 1 ) ( 2 , 3 ) )
console. log ( curriedSum ( 1 ) ( 2 ) ( 3 ) )
es5 实现继承
function create ( proto) {
function F ( ) { }
F . prototype = proto;
return new F ( ) ;
}
function Parent ( name) {
this . name = name
}
Parent. prototype. sayName = function ( ) {
console. log ( this . name)
} ;
function Child ( age, name) {
Parent. call ( this , name)
this . age = age
}
Child. prototype = create ( Parent. prototype)
Child. prototype. constructor = Child
Child. prototype. sayAge = function ( ) {
console. log ( this . age)
}
const child = new Child ( 18 , 'Jack' )
child. sayName ( )
child. sayAge ( )
instanceof
function isInstanceOf ( instance, klass) {
let proto = instance. __proto__
let prototype = klass. prototype
while ( true ) {
if ( proto === null ) return false
if ( proto === prototype) return true
proto = proto. __proto__
}
}
class Parent { }
class Child extends Parent { }
const child = new Child ( )
console. log ( isInstanceOf ( child, Parent) , isInstanceOf ( child, Child) , isInstanceOf ( child, Array) ) ;
异步并发数限制
function limit ( count, array, iterateFunc) {
const tasks = [ ]
const doingTasks = [ ]
let i = 0
const enqueue = ( ) => {
if ( i === array. length) {
return Promise. resolve ( )
}
const task = Promise. resolve ( ) . then ( ( ) => iterateFunc ( array[ i++ ] ) )
tasks. push ( task)
const doing = task. then ( ( ) => doingTasks. splice ( doingTasks. indexOf ( doing) , 1 ) )
doingTasks. push ( doing)
const res = doingTasks. length >= count ? Promise. race ( doingTasks) : Promise. resolve ( )
return res. then ( enqueue)
} ;
return enqueue ( ) . then ( ( ) => Promise. all ( tasks) )
}
const timeout = i => new Promise ( resolve => setTimeout ( ( ) => resolve ( i) , i) )
limit ( 2 , [ 1000 , 1000 , 1000 , 1000 ] , timeout) . then ( ( res) => {
console. log ( res)
} )
异步串行 | 异步并行
function asyncAdd ( a, b, callback) {
setTimeout ( function ( ) {
callback ( null , a + b) ;
} , 500 ) ;
}
const promiseAdd = ( a, b) => new Promise ( ( resolve, reject) => {
asyncAdd ( a, b, ( err, res) => {
if ( err) {
reject ( err)
} else {
resolve ( res)
}
} )
} )
async function serialSum ( ... args) {
return args. reduce ( ( task, now) => task. then ( res => promiseAdd ( res, now) ) , Promise. resolve ( 0 ) )
}
async function parallelSum ( ... args) {
if ( args. length === 1 ) return args[ 0 ]
const tasks = [ ]
for ( let i = 0 ; i < args. length; i += 2 ) {
tasks. push ( promiseAdd ( args[ i] , args[ i + 1 ] || 0 ) )
}
const results = await Promise. all ( tasks)
return parallelSum ( ... results)
}
( async ( ) => {
console. log ( 'Running...' ) ;
const res1 = await serialSum ( 1 , 2 , 3 , 4 , 5 , 8 , 9 , 10 , 11 , 12 )
console. log ( res1)
const res2 = await parallelSum ( 1 , 2 , 3 , 4 , 5 , 8 , 9 , 10 , 11 , 12 )
console. log ( res2)
console. log ( 'Done' ) ;
} ) ( )
vue reactive
class Dep {
static stack = [ ]
static target = null
deps = null
constructor ( ) {
this . deps = new Set ( )
}
depend ( ) {
if ( Dep. target) {
this . deps. add ( Dep. target)
}
}
notify ( ) {
this . deps. forEach ( w => w. update ( ) )
}
static pushTarget ( t) {
if ( this . target) {
this . stack. push ( this . target)
}
this . target = t
}
static popTarget ( ) {
this . target = this . stack. pop ( )
}
}
function reactive ( o) {
if ( o && typeof o === 'object' ) {
Object. keys ( o) . forEach ( k => {
defineReactive ( o, k, o[ k] )
} )
}
return o
}
function defineReactive ( obj, k, val) {
let dep = new Dep ( )
Object. defineProperty ( obj, k, {
get ( ) {
dep. depend ( )
return val
} ,
set ( newVal) {
val = newVal
dep. notify ( )
}
} )
if ( val && typeof val === 'object' ) {
reactive ( val)
}
}
class Watcher {
constructor ( effect) {
this . effect = effect
this . update ( )
}
update ( ) {
Dep. pushTarget ( this )
this . value = this . effect ( )
Dep. popTarget ( )
return this . value
}
}
const data = reactive ( {
msg: 'aaa'
} )
new Watcher ( ( ) => {
console. log ( '===> effect' , data. msg) ;
} )
setTimeout ( ( ) => {
data. msg = 'hello'
} , 1000 )
promise
class MyPromise {
constructor ( func) {
this . status = 'pending'
this . value = null
this . resolvedTasks = [ ]
this . rejectedTasks = [ ]
this . _resolve = this . _resolve. bind ( this )
this . _reject = this . _reject. bind ( this )
try {
func ( this . _resolve, this . _reject)
} catch ( error ) {
this . _reject ( error)
}
}
_resolve ( value) {
setTimeout ( ( ) => {
this . status = 'fulfilled'
this . value = value
this . resolvedTasks. forEach ( t => t ( value) )
} )
}
_reject ( reason) {
setTimeout ( ( ) => {
this . status = 'reject'
this . value = reason
this . rejectedTasks. forEach ( t => t ( reason) )
} )
}
then ( onFulfilled, onRejected) {
return new MyPromise ( ( resolve, reject) => {
this . resolvedTasks. push ( ( value) => {
try {
const res = onFulfilled ( value)
if ( res instanceof MyPromise ) {
res. then ( resolve, reject)
} else {
resolve ( res)
}
} catch ( error ) {
reject ( error)
}
} )
this . rejectedTasks. push ( ( value) => {
try {
const res = onRejected ( value)
if ( res instanceof MyPromise ) {
res. then ( resolve, reject)
} else {
reject ( res)
}
} catch ( error ) {
reject ( error)
}
} )
} )
}
catch ( onRejected) {
return this . then ( null , onRejected) ;
}
}
new MyPromise ( ( resolve) => {
setTimeout ( ( ) => {
resolve ( 1 ) ;
} , 500 ) ;
} ) . then ( ( res) => {
console. log ( res) ;
return new MyPromise ( ( resolve) => {
setTimeout ( ( ) => {
resolve ( 2 ) ;
} , 500 ) ;
} ) ;
} ) . then ( ( res) => {
console. log ( res) ;
throw new Error ( 'a error' )
} ) . catch ( ( err) => {
console. log ( '==>' , err) ;
} )
数组扁平化
function recursionFlat ( ary = [ ] ) {
const res = [ ]
ary. forEach ( item => {
if ( Array. isArray ( item) ) {
res. push ( ... recursionFlat ( item) )
} else {
res. push ( item)
}
} )
return res
}
function reduceFlat ( ary = [ ] ) {
return ary. reduce ( ( res, item) => res. concat ( Array. isArray ( item) ? reduceFlat ( item) : item) , [ ] )
}
const source = [ 1 , 2 , [ 3 , 4 , [ 5 , 6 ] ] , '7' ]
console. log ( recursionFlat ( source) )
console. log ( reduceFlat ( source) )
对象扁平化
function objectFlat ( obj = { } ) {
const res = { }
function flat ( item, preKey = '' ) {
Object. entries ( item) . forEach ( ( [ key, val] ) => {
const newKey = preKey ? ` ${ preKey} . ${ key} ` : key
if ( val && typeof val === 'object' ) {
flat ( val, newKey)
} else {
res[ newKey] = val
}
} )
}
flat ( obj)
return res
}
const source = { a: { b: { c: 1 , d: 2 } , e: 3 } , f: { g: 2 } }
console. log ( objectFlat ( source) ) ;
图片懒加载
function isVisible ( el) {
const position = el. getBoundingClientRect ( )
const windowHeight = document. documentElement. clientHeight
const topVisible = position. top > 0 && position. top < windowHeight;
const bottomVisible = position. bottom < windowHeight && position. bottom > 0 ;
return topVisible || bottomVisible;
}
function imageLazyLoad ( ) {
const images = document. querySelectorAll ( 'img' )
for ( let img of images) {
const realSrc = img. dataset. src
if ( ! realSrc) continue
if ( isVisible ( img) ) {
img. src = realSrc
img. dataset. src = ''
}
}
}
window. addEventListener ( 'load' , imageLazyLoad)
window. addEventListener ( 'scroll' , imageLazyLoad)
window. addEventListener ( 'scroll' , throttle ( imageLazyLoad, 1000 ) )