Рукописный вызов, подача заявки, привязка реализации и подробное объяснение

JavaScript

Какая между ними разница? как пользоваться?

call получает несколько параметров, первый — это контекст функции, то есть this, а последние параметры — это параметры самой функции.

        let obj = {
            name: "一个"
        }

        function allName(firstName, lastName) {
            console.log(this)
            console.log(`我的全名是“${firstName}${this.name}${lastName}”`)
        }
        // 很明显此时allName函数是没有name属性的
        allName('我是', '前端') //我的全名是“我是前端”  this指向window
        allName.call(obj, '我是', '前端') //我的全名是“我是一个前端” this指向obj

image.png

apply

apply получает два параметра, первый параметр — это контекст функции this, а второй параметр — это параметр функции, который просто передается в виде массива.

allName.apply(obj, ['我是', '前端'])//我的全名是“我是一个前端” this指向obj

bind

bind получает несколько параметров, первым из которых является возвращаемое значение bindВозвращаемое значение является функциейthis контекста не будет выполнено немедленно.

        let obj = {
            name: "一个"
        }

        function allName(firstName, lastName, flag) {
            console.log(this)
            console.log(`我的全名是"${firstName}${this.name}${lastName}"我的座右铭是"${flag}"`)
        }
        allName.bind(obj) //不会执行
        let fn = allName.bind(obj)
        fn('我是', '前端', '好好学习天天向上')

        // 也可以这样用,参数可以分开传。bind后的函数参数默认排列在原函数参数后边
        fn = allName.bind(obj, "你是")
        fn('前端', '好好学习天天向上')

Далее потрите руки, чтобы осуществить вызов, применить и привязать

реализовать вызов

      let Person = {
            name: 'Tom',
            say() {
                console.log(this)
                console.log(`我叫${this.name}`)
            }
        }

        // 先看代码执行效果
        Person.say() //我叫Tom 
        Person1 = {
            name: 'Tom1'
        }

        // 我们尝试用原生方法call来实现this指向Person1
        Person.say.call(Person1) //我叫Tom1

В ходе первого выполнения печати и второго выполнения печати я обнаружил, что если у Person1 есть метод say, то Person1 напрямую выполняет Person1.say(). В результате я являюсь Tom1, и да, вызов реализован таким образом. посмотри на код

        Function.prototype.MyCall = function(context) {
            //context就是demo中的Person1
            // 必须此时调用MyCall的函数是say方法,那么我们只需要在context上扩展一个say方法指向调用MyCall的say方法这样this
            console.log(this)
            context.say = this //Mycall里边的this就是我们虚拟的say方法
            context.say()
        }
        // 测试
        Person.say.MyCall(Person1)//我叫Tom1

image.png
идеально! Взрывное удовлетворение! Однако думать об этом пальцами ног будет не так просто, продолжайте совершенствоваться мы придираемся 1. вызов поддерживает несколько параметров, возможно, ни один из них 2. При рассмотрении нескольких параметров параметры следует передавать в метод расширения. 3. Функция, определенная для контекста, должна быть уникальной и не может быть 4. После расширения нам нужно удалить пользовательскую функцию Далее решаем задачу поиска неисправностей по одной

        let Person = {
            name: 'Tom',
            say() {
                console.log(this)
                console.log(`我叫${this.name}`)
            }
        }
        Person1 = {
            name: 'Tom1'
        }
        //如果没有参数
        Person.say.call()

image.png

Это не указано, это указывает на окно

и мы тоже

        Function.prototype.MyCall = function(context) {
            // 如果没有参数我们参考call的处理方式
            context = context || window
                //context就是demo中的Person1
                // 必须此时调用MyCall的函数是say方法,那么我们只需要在context上扩展一个say方法指向调用MyCall的say方法这样this
            context.say = this //Mycall里边的this就是我们虚拟的say方法
            context.say()
        }

        Person.say.MyCall()

Без проблем! продолжать решать

// 找茬2:我们默认定义context.say = this  fn如果已经被占用 嘎嘎 sb了。 不怕 搞定它

        // say需要是一个唯一值 是不是突然想到es6的新类型 Symbol   fn = Symbol() 不过我们装逼不嫌事大 都说自己实现了

        function mySymbol(obj) {
            // 不要问我为什么这么写,我也不知道就感觉这样nb
            let unique = (Math.random() + new Date().getTime()).toString(32).slice(0, 8)
                // 牛逼也要严谨
            if (obj.hasOwnProperty(unique)) {
                return mySymbol(obj) //递归调用
            } else {
                return unique
            }
        }
//接下来我们一并把多参数和执行完删除自定义方法删除掉一块搞定
        Function.prototype.myCall1 = function(context) {
            // 如果没有传或传的值为空对象 context指向window
            context = context || window
            let fn = mySymbol(context)
            context[fn] = this //给context添加一个方法 指向this
            // 处理参数 去除第一个参数this 其它传入fn函数
            let arg = [...arguments].slice(1) //[...xxx]把类数组变成数组,arguments为啥不是数组自行搜索 slice返回一个新数组
            context[fn](...arg) //执行fn
            delete context[fn] //删除方法
        }
        
        let Person = {
            name: 'Tom',
            say(age) {
                console.log(this)
                console.log(`我叫${this.name}我今年${age}`)
            }
        }

        Person1 = {
            name: 'Tom1'
        }

        Person.say.call(Person1,18)//我叫Tom1我今年18

Результаты теста идеальны!

применить применить

Дальше применить намного проще, только когда параметров несколько, второй параметр является массивом, поэтому пошагово расписывать не буду.

        Function.prototype.myApply = function(context) {
            // 如果没有传或传的值为空对象 context指向window
            if (typeof context === "undefined" || context === null) {
                context = window
            }
            let fn = mySymbol(context)
            context[fn] = this //给context添加一个方法 指向this
                // 处理参数 去除第一个参数this 其它传入fn函数
            let arg = [...arguments].slice(1) //[...xxx]把类数组变成数组,arguments为啥不是数组自行搜索 slice返回一个新数组
            context[fn](arg) //执行fn
            delete context[fn] //删除方法

        }

реализовать привязку

Это очень отличается от вызова и подачи заявки, дайте мне выкурить сигарету и вернуться, чтобы убрать его Или старый способ сначала проанализировать, что умеет бинд и каковы характеристики 1. Вызов функции, измените это 2. Верните функцию, которая связывает это 3. Получить несколько параметров 4. Поддерживает передачу параметров в каррированной форме fn(1)(2)

       Function.prototype.bind = function(context) {
            //返回一个绑定this的函数,我们需要在此保存this
            let self = this
                // 可以支持柯里化传参,保存参数
            let arg = [...arguments].slice(1)
                // 返回一个函数
            return function() {
                //同样因为支持柯里化形式传参我们需要再次获取存储参数
                let newArg = [...arguments]
                console.log(newArg)
                    // 返回函数绑定this,传入两次保存的参数
                    //考虑返回函数有返回值做了return
                return self.apply(context, arg.concat(newArg))
            }
        }

        // 搞定测试
        let fn = Person.say.bind(Person1)
        fn()
        fn(18)

image.png

Да, отлично, реализует привязку this, возвращает функцию, не выполняется сразу и может передавать параметры в каррированном виде. Для получения дополнительной информации о каррировании перейдите по ссылке:сегмент fault.com/ah/119000001…

Реализация упрощенной версии завершена

Комментарии или лайки приветствуются!