Call the function
Add a simple method to the prototype chain of Function by changing the direction of this:
Function.prototype.myCall = function (content) {
content.fn = this
const result = eval(`content.fn()`)
return result
}
Copy the code
This implements the core part of the call function, which requires special handling of the argument part of the function because of the string form:
Function.prototype.myCall = function (content) {
content.fn = this
/** Handle arguments */
const args = []
for (let i = 1; i < arguments.length; i++) {
args.push(`arguments[${i}] `) // Direct push causes strong string translations :[]
}
/ * * * /
const result = eval(`content.fn(${args}) `)
return result
}
Copy the code
It is basically ok, but there are still problems, temporary attribute processing, final optimization result:
Function.prototype.myCall = function (content) {
const fn = `fn_The ${(Math.random()*999).toFixed()}` // Prevent attribute name conflicts in extreme cases
content[fn] = this
const args = []
for (let i = 1; i < arguments.length; i++) {
args.push(`arguments[${i}] `)}const result = eval(`content[fn](${args}) `)
delete content[fn] // Release after use
return result
}
Copy the code
Write an example to test:
const a = {
name: 'a'.say: function (t) { console.log(`${t}.The ${this.name}`)}}const b = { name: 'b' }
a.say.call(b, 'hi') // hi, b
a.say.myCall(b, 'hello') // hello, b
Copy the code
Image stabilization
Take the rolling event as an example, shaking prevention is triggered at a low frequency in the rolling process
window.onscroll = throttle(function () {
console.log('throttle'); // Continuous scrolling only rhythmically prints 1s apart
}, 1000)
Copy the code
Timer throttle implementation:
function throttle(fn, delay = 1000) {
let timer = null;
return function () {
if (timer) {
return
}
timer = setTimeout(() = > {
fn.apply(this.arguments);
timer = null; // Release the timer
}, delay)
}
}
Copy the code
Timestamp throttle implementation:
function throttle(fn, delayTime = 1000) {
let lastTime = 0
return function () {
const nowTime = new Date().getTime()
if (nowTime - lastTime > delayTime) {
fn.call(this. arguments) lastTime = nowTime// Also a closure that maintains a timestamp}}}Copy the code
The throttle
Again, using the rolling event as an example, throttling means that only one event is triggered during the rolling process
window.onscroll = debounce(function () {
console.log('debounce'); // The output is not executed until 1s after the scroll has completely stopped
}, 1000)
Copy the code
The timer debounce implementation is the same as the anti-shock implementation, the difference is that the throttle is not executed multiple times:
function debounce(fn, delay = 1000) {
let timer = null
return function () {
if (timer) {
clearTimeout(timer) // The main difference with anti-shake is that the previous task is cleared and only reserved for the last execution
}
timer = setTimeout(() = > {
fn.call(this. arguments) timer =null}, delay); }}Copy the code