Maison > interface Web > js tutoriel > 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

不言
Libérer: 2018-07-23 11:26:58
original
2135 Les gens l'ont consulté

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 女
Copier après la connexion

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
Copier après la connexion

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 男
Copier après la connexion

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 男
Copier après la connexion

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 男
Copier après la connexion

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 男
Copier après la connexion

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]
}
Copier après la connexion

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执行
  }
}
Copier après la connexion

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('男')
Copier après la connexion

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!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
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
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal