一日不读书,胸臆无佳想。一月不读书,耳目失精爽。 ——《读书有所见作》
new关键字的实现
// 1. 写一个函数,支持接收N多参数,第一个参数是构造函数
// 2. 新创建一个对象,把这个对象的原型,指向构造函数的原型
// 3. 改变this指向,指向新创建的对象
// 4. 返回这个对象
function myNew(fn, ...args) {
const instance = {}
instance.__proto__ = fn.prototype
const result = fn.call(instance, ...args)
return typeof result === 'object' ? result : instance
}
function Student(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.play = function() {
console.log('hhhhhhh')
}
}
const student1 = myNew(Student, '小明', 18, '男')
console.log(student1) // {name: "小明", age: 18, sex: "男", play: ƒ}
call的实现
// 1. 函数原型上定义myCall,接收N多参数,第一个参数为要改变this指向的函数
// 2. 根据this指向特性,谁掉用就指向谁,把this挂载到目标对象上
// 3. 执行挂载的函数,this就指向了目标对象
// 4. 删除挂载
Function.prototype.myCall = function(target, ...args) {
const fn = this
target[fn] = fn
target[fn](...args)
delete target.fn
}
function say(name) {
console.log(name + this.age + '岁了')
}
const obj = { age: 23 }
say.call(obj, '小明') // 小明23岁了
apply的实现
与call的实现原理相同,就是传参的方式略微不同。传的是一个数组。
Function.prototype.myCall = function(target, args = []) {
const fn = this
target[fn] = fn
target[fn](...args)
delete target.fn
}
bind的实现
首先熟知bind的特性,支持改变this指向,接收N多参数,返回一个函数,这个函数需要调用才会执行
// 1. 先保存原函数
// 2. 再保存目标函数
// 3. 处理入参为数组(方便下面处理),除第一个参数外
// 4. 返回一个新函数,同样接受N多参数
// 5. 改变this,指向目标函数,再把上一步剩余参数,和返回的新函数的参数合并
Function.prototype.myBind = function() {
const self = this
const target = Array.prototype.shif.call(arguments)
const args = Array.prototype.slice.call(arguments)
return function() {
self.apply(target, Array.prototype.concat.call(args, Array.prototype.slice.call(arguments)))
}
}
function a(m, n, o) {
console.log(this.name + ' ' + m + ' ' + n + ' ' + o);
}
const b = {
name: 'kong'
}
a.myBind(b, 7, 8)(9); // kong 7 8 9