Maison  >  Article  >  interface Web  >  Comment implémenter l'appel, l'application et la liaison nativement dans js

Comment implémenter l'appel, l'application et la liaison nativement dans js

不言
不言original
2018-07-23 11:26:582059parcourir

Le contenu partagé avec vous dans cet article explique comment implémenter call, apply et bind nativement dans js. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Parce que cela est lié au problème souligné par ceci, l'utilisation de call, apply et bind peut être considérée comme un cliché. La fonction principale de cet article est d'utiliser les méthodes natives de js pour implémenter les trois méthodes, comprendre les principes et mieux comprendre les points de connaissances pertinents. Implémentation native de l'appel d'adresse github, apply et bind

call and apply

Une brève introduction : les méthodes call et apply appellent toutes deux une fonction en utilisant une valeur this spécifiée et les paramètres ou méthodes correspondants. La différence est que call transmet plusieurs paramètres, tandis que apply transmet un tableau.
Par exemple :

var obj = {
  name: 'linxin'
}

function func(age, sex) {
  console.log(this.name,age,sex);
}

func.call(obj,12,'女');         // linxin 12 女
func.apply(obj, [18, '女']);        //linxin 18 女

Implémentation de simulation

Idée : Le pointeur this en JavaScript mentionné : la fonction peut également être appelée comme méthode d'un objet, alors ceci fait référence à cet objet supérieur. C'est ce que nous disons habituellement, quiconque appelle, cela le signalera. La méthode d'implémentation consiste donc à ajouter une telle méthode à l'objet entrant, puis à exécuter cette méthode. Afin de garder l'objet persistant, l'objet est supprimé après l'exécution. N'est-ce pas très simple ^-^.
Première expérience :

Function.prototype.newCall = function(context) {
  context.fn = this;  // 通过this获取call的函数
  context.fn();
  delete context.fn;
}
let foo = {
  value: 1
}
function bar() {
  console.log(this.value);
}
bar.newCall (foo); // 1

Cela termine l'implémentation de la version de base, mais que se passe-t-il s'il y a des paramètres à passer ?
Nous pouvons donc l'optimiser, car le nombre de paramètres transmis est incertain, nous pouvons donc l'obtenir à partir de l'objet Arguments, ce qui est relativement simple. Le problème est que les paramètres sont incertains. Comment les transmettre à la fonction que nous voulons exécuter ? Nous avons deux options ici : l’une consiste à utiliser l’épissage eval et l’autre consiste à utiliser es6.
Mise à niveau de l'expérience (version d'évaluation) :

Function.prototype.newCall = function(context) {
  context.fn = this;
  var args = [];
  for(var i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']');
  }
  eval('context.fn(' + args +')');
  delete context.fn;
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

Mise à niveau de l'expérience (version ES6) :

Function.prototype.newCall = function(context) {
  context.fn = this;  
  context.fn(...Array.from(arguments).slice(1));
  delete context.fn;
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

Laissez ES6 Le La méthode peut également être utilisée pour réaliser la mise à niveau de la version
ES6 sans utiliser d'arguments :

Function.prototype.newCall = function(context, ...parameter) {
  context.fn = this;  
  context.fn(...parameter);
  delete context.fn;
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

De cette façon, nous réalisons essentiellement la fonction d'appel, mais il y a encore des choses cachées dangers et différences.
Lorsque l'objet lui-même a la méthode fn, il y a un gros problème.
Lorsque l'objet transmis par appel est nul ou d'un autre type, la fonction signalera une erreur.
Expérience ultime :

Function.prototype.newCall = function(context, ...parameter) {
  if (typeof context === 'object') {
    context = context || window
  } else {
    context = Object.create(null)
  }
  let fn = Symbol()
  context[fn] = this
  context[fn](...parameter);
  delete context[fn]
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
sayHi.newCall (person, 25, '男'); // Abiel 25 男

Après avoir mis en œuvre l'appel, apply a la même idée.
appliquer l'implémentation :

Function.prototype.newApply = function(context, parameter) {
  if (typeof context === 'object') {
    context = context || window
  } else {
    context = Object.create(null)
  }
  let fn = Symbol()
  context[fn] = this
  context[fn](parameter);
  delete context[fn]
}

bind

bind est également une méthode fonctionnelle. Sa fonction est de modifier l'exécution de ceci, et elle peut également passer. plusieurs paramètres. Différente de call et apply, la méthode bind ne sera pas exécutée immédiatement, mais renverra une fonction qui modifie le contexte vers lequel elle pointe. La fonction d'origine n'a pas été modifiée. Et si la fonction elle-même est une fonction liée à cet objet, alors l'application et l'appel ne s'exécuteront pas comme prévu.
Première expérience :

Function.prototype.bind = function (context) {
  var me = this
  return function () { // bind之后得到的函数
    return me.call(context)  // 执行是改变this执行
  }
}

Ajouter des paramètres :

Function.prototype.bind = function (context,...innerArgs) {
  var me = this
  return function (...finnalyArgs) {
    return me.call(context,...innerArgs,...finnalyArgs)
  }
}
let person = {
  name: 'Abiel'
}
function sayHi(age,sex) {
  console.log(this.name, age, sex);
}
let personSayHi = sayHi.bind(person, 25)
personSayHi('男')

Recommandations associées :

Analyse modulaire de js (espace de noms)

Introduction détaillée à l'héritage JS (chaîne de prototypes, constructeur, combinaison, prototype, parasite, combinaison parasite, extension de classe)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn