#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')