Создание моей собственной функции bind () с использованием apply () в Javascript

#javascript #prototype #prototypal-inheritance

#javascript #прототип #прототипирование-наследование

Вопрос:

В качестве упражнения я пытаюсь создать свою собственную функцию bind () с помощью apply () и прототипного наследования, которые я только что изучил.

Это мой код:

 // Create your own bind() using call() and apply()
const lizard = {
    phrase: 'slither',
    say(phraseToSay) {
        if (!phraseToSay) phraseToSay = this.phrase
        console.log('sss'   phraseToSay)
    },
}

const dragon = {
    phrase: 'sizzle',
}

// My Answer
Function.prototype.mybind = function (object) {
    return () => this.apply(object, arguments)
}

// Solution
Function.prototype.solbind = function (object) {
    let self = this
    return function () {
        self.apply(object, arguments)
    }
}

dragon.say = lizard.say.mybind(dragon)

lizard.say()
dragon.say()
lizard.say('sexy')
dragon.say('sexy')  

Это результат:

 ssslither
sss[object Object]
ssssexy
sss[object Object]
  

Решение заключается в использовании self=this . Но в моих глазах это выглядит некрасиво…
Я пытаюсь сделать это только с помощью функций this и arrow. Но по какой-то причине apply() передает первый аргумент, который является самим объектом, в качестве фактического аргумента целевой функции. Я не понимаю, почему это так и как я могу достичь желаемого результата без сохранения this в другую переменную.

Комментарии:

1. Функции со стрелками не имеют неявного arguments параметра. Внутри функции со стрелкой, arguments ссылается arguments на охватывающую область, если она существует

2. return (...args) => this.apply(object, args) . Оба ключевых слова arguments и this внутри функции со стрелкой привязаны к родительской функции.

3. почему бы не использовать class ? Кажется, lizard продолжается от dragon .

4. На самом деле это решение также неверно, поскольку оно не учитывает дополнительные аргументы к bind , которые должны быть частично применены. Лучше: function(receiver, ...boundArgs) { return (...callArgs) => this.call(receiver, ...boundArgs, ...callArgs); }

Ответ №1:

Когда вы делаете:

 .... = function (object) { 
  return () => this.apply(object, arguments)
}
  

Вы имеете в виду arguments объект, ограниченный выражением внешней функции, а не вашу функцию arrow, поскольку функции arrow не имеют привязки к своим собственным аргументам. В этом случае этот объект arguments будет содержать dragon , поскольку вы используете:

 dragon.say = lizard.say.mybind(dragon)
  

Итак, ваш объект arguments будет содержать, dragon который будет передан в качестве аргумента вашему say методу при использовании .apply(object, arguments) .

В случае предоставленного решения они возвращают функциональное выражение, которое, в отличие от функции со стрелкой, имеет свою собственную arguments привязку, поэтому в этом случае arguments объект ссылается на аргументы, переданные в функцию, возвращаемую solbind() .

Вы можете исправить свой код, используя синтаксис параметра rest (...) ES6 вместо ссылки на объект arguments. Этот способ args будет ссылаться на аргументы, переданные в «связанную» функцию:

 // Create your own bind() using call() and apply()
const lizard = {
    phrase: 'slither',
    say(phraseToSay) {
        if (!phraseToSay) phraseToSay = this.phrase
        console.log('sss'   phraseToSay)
    },
}

const dragon = {
    phrase: 'sizzle',
}

// My Answer
Function.prototype.mybind = function (object) {
    return (...args) => this.apply(object, args)
}

// Solution
Function.prototype.solbind = function (object) {
    let self = this
    return function () {
        self.apply(object, arguments)
    }
}

dragon.say = lizard.say.mybind(dragon)

lizard.say()
dragon.say()
lizard.say('sexy')
dragon.say('sexy')