实现new 操作符功能
实现的要点:
- 返回一个对象
- 该对象的__proto__ 指向 函数的prototype
- 如果有参数, 参数也需要对应到返回的对象中
function myNew(fn) {
let obj = {}
if (fn.prototype !== null) {
obj.__proto__ = fn.prototype
}
const objWithParams = fn.apply(obj, Array.prototype.slice.call(arguments, 1))
if (( typeof objWithParams === 'object' || typeof objWithParams === 'function') && objWithParams !== null) {
return objWithParams
}
return obj
}
test
function test(name, company) {
this.name = name
this.company = company
}
const obj1 = myNew(test, 'test', 'test')
const obj2 = new test('test', 'test')
console.log(obj1, obj2)
result
debounce
触发事件后,在 n 秒内函数只能执行一次,如果触发事件后在 n 秒内又触发了事件,则会重新计算函数延执行时间
实现要点
- 一段时间只执行一次
- 一段时间内的后一次触发, 会覆盖上一次触发
- 返回事件函数
function debounce(fn, delay = 500, immediate) {
let timer = undefined
return function(){
if (immediate) {
fn.apply(this, arguments)
}
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
}, delay)
}
}
test
const testFn = debounce(
() => {
console.log('debounce', 1)
}, 1000, false
)
const normalFn = () => {
console.log('normal', 2)
}
const interval = setInterval(() => {
testFn()
normalFn()
}, 500)
setTimeout(() => {
clearInterval(interval)
}, 2000)
result
throttle
一个连续操作中的处理,按照阀值时间间隔进行触发,从而实现节流
function throttle(fn, wait) {
let timer = undefined
return function() {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, arguments)
timer = undefined
}, wait)
}
}
}
test
const testFn = throttle(() => {
console.log('throttle', 1)
}, 500)
const interval = setInterval(() => {
testFn()
}, 10)
setTimeout(() => {
clearInterval(interval)
}, 2000)
result
debounce 和throttle的区别
debounce 会覆盖上一次的触发,结果表现为一段时间内, 如果多次在delay时间间隔内触发, 只触发最后一次响应
throttle,不会覆盖上一次触发, 结果表现为一段时间内, 如果在wait时间间隔内触发, 则无响应, 超过wait时间则再次触发
深拷贝
拷贝的原因:js中对象存储在堆内存中,如果直接采用赋值的方式,只是简单的将对象的堆内存地址赋值给新变量, 这时两者的引用都指向同一个内存地址,修改任意一个,另一个都会随着改变。达不到拷贝效果。 同时,深拷贝又不同于浅拷贝, 目的是将存在多层结构对象拷贝为一个新对象, 拷贝后两者就不存在关系。 而浅拷贝只会拷贝第一层。
// 对于简单对象(非函数,正则, Date,Set, Map等)而言, 可采用json来实现.
JSON.parse(JSON.stringify(obj))
// 递归实现
function deepClone(obj) {
let result = null
if (typeof obj === 'object') {
result = Array.isArray(obj) ? [] : {}
for (let i in obj) {
result[i] = typeof obj[i] === 'object' ? deepClone(obj[i]) : obj[i]
}
} else {
result = obj
}
return result
}
test
const obj1 = {
test: { innertest: '1'},
test2: 'test2'
}
const obj3 = deepClone(obj1)
result
promise
参考原文: juejin.cn/post/694531…
// 三种状态, pending, fulfilled, rejected
// 状态只能由 pending -> fulfilled 或者 pending -> rejected
// Promise 对象为一个构造函数,返回一个promise实例
// Promise对象接受一个函数(executor)作为参数, 函数包含两个对象, resolve 和 reject
// resolve 函数将 promise 状态由pending 变为 fulfilled, reject 将状态由pending 变成 rejected
// promise 实例生成后, 可调用then方法。 then 接受两个回调函数作为参数, 分别指定fulfilled 和 rejected状态, 两个参数皆为可选的
// 支持异步操作, 通过一个队列来存储resolve 和reject 结果
// then 方法要链式调用那么就需要返回一个 Promise 对象
// then 方法里面 return 一个返回值作为下一个 then 方法的参数,如果是 return 一个 Promise 对象,那么就需要判断它的状态
// then 返回 promise 对象时需要判断是否为自身, 否则会造成嵌套
// 捕获错误
const PENDING = "PENDING"
const REJECTED = "REJECTED"
const FULFILLED = "FULFILLED"
function resolvePromise(promise2, value, resolve, reject) {
if (value === promise2) {
reject(new TypeError("Chaining cycle detected for promise #<Promise>"))
} else if (value instanceof MyPromise) {
value.then(resolve, reject)
} else {
resolve(value)
}
}
class MyPromise {
constructor(executor) {
try {
executor(this.resolve, this.reject)
} catch (err) {
this.reject(err)
}
}
status = PENDING
value = null
reason = null
resolveCallbacks = []
rejectCallbacks = []
resolve = (value) => {
if (this.status === PENDING) {
this.status = FULFILLED
this.value = value
while (this.resolveCallbacks.length) {
this.resolveCallbacks.shift()(value)
}
}
}
reject = (reason) => {
if (this.status === PENDING) {
this.status = REJECTED
this.reason = reason
while (this.rejectCallbacks.length) {
this.rejectCallbacks.shift()(reason)
}
}
}
static resolve = (parameter) => {
if (parameter instanceof MyPromise) {
return parameter
}
return new MyPromise((resolve, reject) => {
resolve(parameter)
})
}
static reject = (parameter) => {
return new MyPromise((resolve, reject) => {
reject(parameter)
})
}
then = (onFulfilled, onRejected) => {
const realOnFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value
const realOnRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason
}
const promise2 = new MyPromise((resolve, reject) => {
const queueMicrotaskWithResolve = () => {
queueMicrotask(() => {
try {
const resolveValue = realOnFulfilled(this.value)
resolvePromise(promise2, resolveValue, resolve, reject)
} catch (e) {
reject(e)
}
})
}
const queueMicrotaskWithReject = () => {
try {
queueMicrotask(() => {
const rejectValue = realOnRejected(this.reason)
resolvePromise(promise2, rejectValue, resolve, reject)
})
} catch (e) {
reject(e)
}
}
if (this.status === FULFILLED) {
queueMicrotaskWithResolve()
} else if (this.status === REJECTED) {
queueMicrotaskWithReject()
} else if (this.status === PENDING) {
this.resolveCallbacks.push(queueMicrotaskWithResolve)
this.rejectCallbacks.push(queueMicrotaskWithReject)
}
})
return promise2
}
}
setTimeout
参考原文: github.com/sisterAn/Ja…
// 不可取方法, 会造成js死锁, 无法执行其他任务
// function mySetTimeout(fn, delay) {
// let flag = true
// const now = new Date;
// while (flag) {
// const end = new Date
// if ( end - now > delay ) {
// flag = false
// }
// }
// return fn()
// }
const mySetTimeout = (fn, delay, ...args) => {
const start = Date.now()
let timer
let now
const loop = () => {
timer = window.requestAnimationFrame(loop)
now = Date.now()
if (now - start >= delay) {
fn.apply(this, args)
window.cancelAnimationFrame(timer)
}
}
window.requestAnimationFrame(loop)
}
function showName() {
console.log("Hello")
}
mySetTimeout(showName, 1000)
instanceOf
通过原型链来判断一个对象的原型
function myInstanceOf(instance, Fn) {
let obj = instance['__proto__']
const prototype = Fn.prototype
while(true) {
if (obj === null || obj === undefined) {
return false
}
if (obj === prototype) {
return true
}
obj = obj['__proto__']
}
}
test
myInstanceOf({name: 'test'}, Object)
result
持续更新。。。