debounce/throttle
debounce一段时间内持续触发事件时,只执行最后一次
function debounce(fn, delay = 1000){
let timer = null
return function(...args){
timer && clearTimeout(timer)
timer = setTimeout(() => {
fn(...args)
}, delay)
}
}
throttle一段时间内持续触发事件时,只执行第一次
function throttle(fn, delay = 1000){
let flag = true
return function(...args){
if(flag){
flag = false
setTimeout(() => {
flag = true
}, delay)
}
}
}
call/apply/bind
三者都可以改变函数运行时的this指向
call()方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。
function call(context, ...args){
const ctx = context || window
const func = Symbol()
ctx[func] = this
const res = ctx[func](...args)
delete ctx[func]
return res
}
apply()方法使用一个指定this值,以及一个数组(或者类数组)形式的参数
function apply(context, ...args){
const ctx = context || window
const func = Symbol()
ctx[func] = this
const res = ctx[func](...args)
delete ctx[func]
return res
}
bind()方法创建一个新的函数,在bind被调用时,这个新函数的this被指定为bind函数的第一个参数,而其余参数将作为新函数的参数。
function bind(context, ...args){
const fn = this
return function(...newArgs){
fn.call(context, ...args, ...newArgs)
}
}
new
new关键字会进行如下操作
- 创建一个空的简单JavaScript对象(即{})
- 链接该对象(设置该对象的constructor)到另一个对象
- 将新创建的对象作为this上下文
- 如果该函数没有返回值就返回this
function myNew(ctor, ...args){
// 创建新对象
const obj = Object.create()
// 链接该对象
obj.prototype = ctor.prototype
// 设置上下文
const res = ctor.call(obj, ...args)
// 返回
return res instanceof Object? res: obj
}
instanceOf
instanceOf 运算符用于检测构造函数的prototype是否出现在某个实例的原型链上
// 用法 object instanceof constructor
function C(){}
function D(){}
const cExp = new C()
const dExp = new D()
// true 因为Object.getPrototypeOf(cExp) === C.prototype
cExp instanceof C
// false D.prototype不在cExp的原型上
// 实现
function myInstanceof(obj=实例, Cla=类){
let leftPro = Object.getPrototypeOf(obj)
const rightPro = Cla.prototype
while(true){
if(!leftPro) trun false
if(leftPro === rightPro) return true
leftPro = Object.getPrototypeOf(leftPro)
}
}
Object.create
Object.create()方法创建一个新对象,使用现有的对象来提供新对象的__proto__
function myCreate(ctor){
function C(){}
C.prototype = ctor
return new C()
}
Object.assign
Object.assign()方法用于将所有可枚举的属性从一个或多个源对象分配到目标对象,它将返回目标对象
function myAssign(target, args){
const to = Object(target)
for(let i = 1; i< args.length; i++){
const nextSource = args[i]
for(let nextKey in nextSource){
if(Object.prototype.hasOwnProperty(nextSource,nextKey)){
to[nextKey] = nextSource[nextKey]
}
}
}
}
deepClone
function deepClone(target){
if(target instanceOf RegExp) return new RegExp(target)
if(target instanceOf Date) return new Date(target)
if(target !== null || typeof target !== 'object') return target
let ctor = new target.constructor()
for(let key in target){
if(target.hasOwnProperty()key){
ctor = deepClone(target[key])
}
}
return ctor
}
数组扁平化
function myFlat(data){
return Array.reduce((prev,cur) => {
return prev.concat(myFlat(cur))
},[])
}
节点遍历
function traverse(node, nodeList = []){
nodeList.push(node)
const children = node.children
for(let i = 0; i < children.length; i++){
traverse(children[i], nodeList)
}
return nodeList
}
function traverse2(node){
let nodeList = []
nodeList.push(node)
const children = node.children
for(let i = 0;i < children.length; i++){
nodeList = nodeList.concat(traverse2(children[i]))
}
return nodeList
}
function traverse3(node){
let nodeList = []
let stack = []
stack.push(node)
while(stack.length){
const item = stack.pop()
nodeList.push(item)
const children = item.children
for(let i = 0; i< children.length; i++){
stack.push(children[i])
}
}
return nodeList
}
function traverse4(node){
let nodeList = []
let stack = []
stack.push(node)
while(stack.length){
const item = stack.shift()
const children = item.children
for(let i = 0; i < children.length; i++){
stack.push(children[i])
}
}
return nodeList
}
函数柯里化
function sum(a, b, c){
return a + b + c
}
const sum = curry(sum)
sum(1)(2)(3) // 6
function curry(fn, ...args){
const fnLen = fn.length
const argsLen = args.length
//如果参数不够就继续返回curry
//若参数够了就执行函数
if(fnLen > argsLen){
return function(...args2){
return curry(fn, ...args,...args2)
}
}else{
fn(...args)
}
}
JSONP
function JSONP(url, data){
const callback = 'callback' + Math.random()
const src = url + '?callback=' + callback
const script = document.createElement('script')
script.setAttribute('type', 'text/javascript')
script.src = src
return new Promise((resolve, reject) => {
window[callback] = r => {
resolve(r)
headEle.removeChild(JSONP)
delete window[callback]
}
headEle.appendChild(JSONP)
})
}
JSONP().then(res => {
//res就是我们要拿的数据
console.log(res)
})
观察者模式
定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新
class Subject{
constructor(){
this.name = 'JavaScript'
this.observers = []
}
attach(obs){
this.observers.push(obs)
}
detach(obs){
this.observers.remove(obs)
}
notify(){
this.observers.forEach(o => o.update(this.name))
}
}
class Observer{
update(){
console.log('收到通知更新啦')
}
}
const sub = new Subject()
const obsmm = new Observer()
const obsnn = new Observer()
sub.attach(obsmm)
sub.attach(obsnn)
sub.notify()
EventEmitter 事件侦听器
class EventEmitter{
constructor(){
this.events = {}
}
on(event, cb){
const cbList = this.events[event] || []
cbList.push(cb)
this.events[event] = cbList
}
off(event, cb){
const cbList = this.events[event] || []
this.events[event] = cbList.filter(fn => fn !== cb)
return this
}
emit(event, ...args){
const cbList = this.events[event] || []
cbList.forEach(fn => fn(...args))
return this
}
this.once(event, cb){
const fn = function(...args){
cb(...args)
this.off(event, fn)
}
this.on(event, fn)
}
}
数组随机排序/生成随机数
let arr = [2,3,454,34,324,32]
arr.sort(randomSort)
function randomSort(a,b){
return Math.random() > 0.5? -1: 1
}
// --------------------------------------
function getRandom(max, min){
return Math.random() * (max - min) + min
}
sleep
sleep函数作用是让线程休眠,等到指定时间在重新唤起
function sleep(delay){
const start = new Date().getTime()
while(new Date().getTime() - start < delay){
continue
}
}
function test(){
console.log('start')
sleep(2000)
console.log('end')
}
test()
对象数组去重
// 将value转成字符串,利用set去重
const arr = [{a:1,b:2,c:3},{b:2,c:3,a:1},{d:2,c:2}]
objSort(obj){
let newObj = Object.create({})
Object.keys(obj).forEach(key => {
newObj[key] = obj[key]
})
return JSON.stringify(newObj)
}
function unique(arr){
let set = new Set()
for(let i = 0; i < arr.length; i++){
set.add(objSort(arr[i]))
}
returm [...set].map(item => JSON.parse(item))
}
Promise
let id = 0
const PENDING = 0
const FULFILLED = 1
const REJECTED = 2
class Promise{
constructor(excutor){
this.promiseId = ++id
this.state = undefined
this.result = undefined
this.subscribers = []
excutor(function resolvePromise(value){
this.resolve(value)
}, function rejectPromise(reason){
this.reject(reason)
})
}
resolve(value){
if(this.state !== PENDING) return
this.state = FULFILLED
this.result = value
//异步任务执行的resolve需要执行一下收集的onFulfilled/onRejected方法(then里面的回调)
if(this.subscribers.length){
this.publish
}
},
reject(reason){
if(this.state !== PENDING) return
this.state = REJECTED
this.result = reason
}
then(onFulfilled,onRejected){
const child = new Promise(function(){})
//如果是同步任务执行的resolve或者reject那么此时state是有值的
//那么需要执行then的回调,并给新的promise进行赋值
//如果是异步任务执行resolve或者reject,那么将then的回调收集起来
if(this.state){
this.invokeCallback(this.state,child,onFulfilled,this.result)
}else{
this.subscribe(child,onFulfilled,onRejected)
}
}
subscribe(promise, onFulfilled,onRejected){
const length = this.subsceibers.length
this.subscribers[length] = promise
this.subscribers[length + FULFILLED] = onFulfilled
this.subscribers[length + REJECTED] = onRejected
}
invokeCallback(state, promise, callback, result){
let value = result
if(getType(callback) === 'function'){
value = callback()
}
// 给新生成的promise进行赋值
promise.resolve(value)
}
publish(){
for(let i=0;i<this.subscribers.length;i++){
let child=this.subsctibers[i]
let cb = this.subscribers[i + this.state]
if(child){
this.invokeCallback(this.state,child,cb,this.result)
}else{
cb(this.result)
}
}
}
}
function getType(target){
return Object.prototype.toString.call(target).slice(8,-1).toLowercase()
}