一、new操作符
new操作符被用来创建一个构造函数的实例对象或者生成一个类的实例,其具体进行的操作如下:
- 创建一个空对象
- 更改this的指向,将创建的对象的原型指向构造函数的原型
- 调用构造函数
- 返回结果: 当构造函数的返回值是引用类型时返回该引用类型值,否则返回创建的对象
了解了操作以后,我们具体来实现一下:
/**
*
* @param fn:构造函数或者类
* @param args:构造函数的参数
* @returns {{}|void}:当原构造函数返回的是引用值时返回引用值,否则返回该构造函数或者类的实例
*/
function myNew(fn,...args) {
const obj = {}
obj.__proto__ = fn.prototype
// 更改this的指向,调用构造函数实例化该对象
const res = fn.myCall(obj,...args)
return typeof res !== 'Object' ? obj : res
}
function Person(name,age) {
this.name = name
this.age = age
}
const p1 = myNew(Person,'libai',18)
console.log(p1) //Person { name: 'libai', age: 18 }
二、更改this的指向(call,apply,bind)
手写call
call方法的作用主要是更改函数内部的this指向,接受两个参数,一个是要更改的this的指向,另一个是不定长的数组,那么我们实现以下这个函数:
- 首先我们明白,函数内部的this指向除箭头函数外,一般都是谁调用指向谁,另外call函数的第一个参数是要指向的this对象,是对象就可以添加属性,
- 然后呢,我们将调用call的函数赋值给要指向的this对象,
- 最后执行函数就可以了
/**
*
* @param thisArg:要改变的this指向参数
* @param args: 执行原函数需要的参数
*/
function myCall(thisArg,...args) {
const key = Symbol('key')
thisArg[key] = this
thisArg[key](...args)
delete thisArg[key]
}
Function.prototype.myCall = myCall
const name = 'window'
const obj = {
name:'aa',
num:2,
eat:function (){
console.log(this.name)
},
sum(num1){
console.log(this.num + 5)
}
}
const obj2 = {
name:'obj2',
num:10
}
console.log(obj.eat()) //‘aa’
console.log(obj.eat.myCall(obj2)) //‘obj2’
手写apply
实现apply的方法与call类似,只不过apply的第二个参数是数组,要求将要执行函数的参数都放进数组里,简单实现如下:
/**
*
* @param thisArg: 要传递的this参数
* @param args: 参数列表
*/
function myApply(thisArg,args = []) {
const key = Symbol('key')
thisArg[key] = this
thisArg[key](args)
delete thisArg[key]
}
Function.prototype.myApply = myApply
console.log(obj.sum(10)) // 7
console.log(obj.sum.myApply(obj2,[16]))// 15
手写Bind
bind 的返回值是一个更改this之后的函数,需要手动调用。实现思路类似,简单手写如下:
/**
*
* @param thisArg;要传递的this的指向
* @param args:参数列表
* @returns {function(...[*]): *}返回的新函数
*/
function myBind(thisArg,...args){
const key = Symbol('key')
thisArg[key] = this
return function (...newArgs) {
return thisArg[key](...args,...newArgs)
}
}
Function.prototype.myBind = myBind
console.log(obj.eat.myBind(obj2)()) // obj2
console.log(obj.sum.myBind(obj2,10)()) //15
手写debounce
防抖作为前端常见优化性能的手段,我们需要学习并理解。
防抖指的是在高频触发的事件中,多次触发但只有在最后一次触发并暂停一段时间后才会执行。
应用场景如下: input,keyup,scoll,resize等事件
现简单实现如下:
/**
*
* @param fn: 需要防抖优化的函数
* @param delay: 延迟的时间,单位是ms
* @returns {(function(...[*]): void)|*}
*/
function debounce(fn,delay) {
let timer = null
return function (...args) {
const _this = this
clearTimeout(timer)
timer = setTimeout(() => {
fn.apply(_this,args)
},delay)
}
}
先写到这里,欢迎多多指正~