Отличие и упрощенная реализация apply, call, bind

JavaScript
Отличие и упрощенная реализация apply, call, bind

apply()метод получает указанныйthisИ значениемассив с несколькими параметрамидля вызова функции.

call()метод получает указанныйthisценность исписок параметровдля вызова функции.

bind()Метод создает новую функцию,bind()При вызове новая функцияthisОбозначен какbind()Первый параметр и остальные параметры будут использоваться как параметры новой функции для использования при вызове

использоватьcallа такжеapplyПри использовании функции будьте осторожны, если вы передаете ееthisЗначение не является объектом, JavaScript попытается использовать внутреннийToObjectДействие превращает его в объект. Итак, если переданное значение является примитивным значением, например7или'foo', затем он преобразуется в объект с помощью соответствующего конструктора, поэтому исходное значение7будет преобразован в объект типаnew Number(7)Таким образом, пока строка'foo'Конвертировано вnew String('foo')Таким образом, например:

function bar() {
  console.log(Object.prototype.toString.call(this));
}

//原始值 7 被隐式转换为对象
bar.call(7); // [object Number]
bar.call('foo'); // [object String]

apply

func.apply(thisArg, [argsArray])

  • thisArgОбязательный. существуетfuncиспользуется при выполнении функцииthisстоимость. Если эта функция находится внестрогий режимниже он указан какnullилиundefinedавтоматически заменяется указателем на глобальный объект, а исходное значение упаковывается.
  • ArgsArray необязательный. Массив или подобный массиву объект, элементы массива которого будут переданы как отдельные аргументы вfuncфункция.
Function.prototype.Apply = function (thisArg, args = Symbol.for('args')) {
  //Apply 函数总是被我们想改变this的函数调用,因此本函数内this总是指代调用函数
  
  //生成一个Symbol类型的唯一符号,用于将调用apply的函数挂载到指定对象上
  const fn = Symbol('fn')      
  thisArg[fn] = this  

  //通过对象调用函数,并传参
  args === Symbol.for('args') ? thisArg[fn]() : thisArg[fn](...args)

  //删除挂载到指定对象上的方法
  delete thisArg[fn]           
}

// 声明全局变量
var position = 'global'
var name = 'window'

function func(name) {
  console.log(this.position)
  console.log(name) 
}

const obj = {
  name: 'object',
  position: 'obj',
}

func.Apply(obj,[obj.name,null]) // obj  object
// 其中,Apply内this指向func

func.Apply(obj,[name,null]) // obj  window
// func中 name 只受传参影响

Symbol.for(key)будет основан на заданном ключеkeyЧтобы найти соответствующий символ из реестра символов среды выполнения, если вы его нашли, верните его, в противном случае создайте новый символ, связанный с ключом, и поместите его в глобальный реестр символов.

call

Function.prototype.Call = function (thisArg, ...args) {
  //这里this为这个方法的调用者
  const fn = Symbol('fn')
  thisArg[fn] = this || globalThis

  //通过对象调用函数,并传参
  args.length ? thisArg[fn](...args) : thisArg[fn]() 

  //删除挂载到指定对象上的方法
  delete thisArg[fn]      
}

func.Call(obj)  // obj undefined
func.Call(obj, 'test') // obj test

здесь не используетсяargumentsОбъект получает входящие параметры.argumentsНе одинArray, без каких-либо параметров, кроме атрибута длины и индексированного элементаArrayАтрибуты.

Использовать оставшиеся параметры...argsкод можно упростить

bind

bind()функция создаст новыйфункция привязки,Он обертывает оригинальный объект функции. передачаФункция привязкиобычно приводит к выполнениюФункция обертки.

Простая версия

Function.prototype.Bind = function(thisArg, ...args){
  let self = this;
  let fBound = function(...args1){
    return self.apply(thisArg, [...args, ...args1]);
  }
  return fBound;
}

Использование замыкания сохраняет значение this первой привязки, делая недействительными последующие привязки.

Function.prototype.Bind = function(thisArg, ...args){
  let self = this;
  
  let fBound = function(...args1){
    //如果当前this为fBound的实例,表示是执行了new,指向this,否则指向bind对象
    return self.apply(this instanceof fBound ? this : thisArg, [...args, ...args1]);
  }
  //修改返回函数的 prototype 为绑定函数的 prototype,new出实例对象就可以继承绑定函数的原型中的成员
  fBound.prototype = this.prototype;
  return fBound;
}

Вот случай, когда связанная функция является конструктором

function foo(age, height) {
  console.log(this.name)       // obj
  console.log(age)             // 3
  console.log(height)          // 2
}
const obj = {
  name: 'obj',
  age: 3
}
foo.Bind(obj, obj.age)(2) // 绑定bind时同时传递一个参数

Статьи по Теме:
Путешествие по построению фундамента с нуля (отличное, постоянное обновление ~)
Объяснение этой функции указателя и стрелки, которое вы сможете понять после прочтения~

Если у вас появятся новые знания, пожалуйста, поставьте лайк автору~