手写new,call,apply,bind

116 阅读2分钟

一日不读书,胸臆无佳想。一月不读书,耳目失精爽。 ——《读书有所见作》

src=http___5b0988e595225.cdn.sohucs.com_images_20181217_343f5107cb2f4366aa9fa7d4f4a680a0.jpeg&refer=http___5b0988e595225.cdn.sohucs.webp

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