JavaScript Advanced Insight and outside: Mastering this direction

Alexzhang1030 2021-11-25 18:14:12
javascript advanced insight mastering direction

Introduction

Cet article est JavaScript Série avancéeTitre VI,Les détails JS Dans this Pointage

Texte

1. Pourquoi this

Dans les langages de programmation courants,Presque toujours.thisMots clés(Objective-C- Oui.self).Mais JS Dans this Et l'objet commun orienté this C'est différent.:

  • Dans les langages de programmation orientés objet courants:this Se produit généralement dans la méthode de la classe(En particulier dans la méthode de l'exemple),Renvoie à l'objet d'appel actuel
  • Mais JS Dans this Plus de flexibilité,Qu'il s'agisse de l'endroit où il apparaît ou de la signification qu'il représente
const foo = {
name: "foo",
greeting() {
// Dans le développement réel,Pour obtenir les propriétés de l'objet courant,Y a - t - il this Tout va bien.
// Mais si vous n'utilisez pas this ,Ce sera très gênant dans le développement
console.log(`Hello, My name is ${this.name}`)
console.log(`Hello, My name is ${foo.name}`)
}
}
Copier le Code

2. this Problème de pointage

2.1 Dans un environnement global

// Dans la plupart des cas,this Sont utilisés dans les classes,Mais le global est aussi accessible this
console.log(this)
Copier le Code
  • Dans l'environnement du navigateur ,GlobalthisPointage GlobalObject,C'est - à - direwindow
  • Node Environnement,GlobalthisPointer vers un objet vide{}

2.2 En fonction

En développement, En général, nous n'utilisons plus globalement this, Généralement utilisé dans une fonction .

  • Toutes les fonctions sont appelées , Crée un contexte d'exécution de fonction
  • La pile d'appels de la fonction est enregistrée dans ce contexte ,AOObjet, etc.
  • this Existe également dans ce contexte
function foo() {
console.log(this)
}
// 1. Appel global
foo() // window
const bar = {
name: `bar's name`,
foo,
}
// 2. Mettre dans l'objet pour utiliser 
bar.foo() // bar En soi
// 3. Adoption apply Appelez
foo.apply('abc') // abc
Copier le Code

Même fonction, La méthode d'appel est différente ,Alors this C'est différent..Description:this Le pointage n'a rien à voir avec la position de la fonction , Ça a quelque chose à voir avec la façon dont la fonction est appelée

  1. La fonction est appelée , JS Donne à la fonction un défaut this Valeur
  2. this La liaison de n'a rien à voir avec l'emplacement de la fonction
  3. this Est lié à la façon dont l'appel est appelé et à l'emplacement de l'appel
  4. this Oui.ExécutionLié

3. this Règles de liaison pour

3.1 Liaison par défaut

Quand une fonction est appelée indépendamment , La règle de liaison est la liaison par défaut , Fonction d'appel autonome , Et pointera vers le monde entier .

Fonction d'appel autonome nous pouvons comprendre que la fonction n'est pas appelée liée à un objet

function foo1() {
console.log(this)
}
function foo2() {
console.log(this)
foo1()
}
function foo3() {
console.log(this)
foo2()
}
foo3() // Fonction d'appel autonome ,3Fonction this Tout indique window
Copier le Code
// Cas 2
var obj = {
name: `obj's name`,
foo() {
console.log(this)
}
}
var bar = obj.foo
bar() // Appel indépendant,Toujours window
Copier le Code
// Cas III
function foo() {
return function() {
console.log(this)
}
}
var obj = {
name: `obj's name`,
foo
}
var bar = obj.foo()
bar() // Appel indépendant,this Ça doit être window
Copier le Code

3.2 Liaison implicite

Appelé par un objet qui déclenche une liaison implicite ,Liaison implicite,this Pointez vers l'objet lui - même qui appelle la fonction . C'est - à - dire dans sa position d'appel ,Est un appel de fonction lancé par un objet

// CAS
const obj = {
name: `obj's name`,
greeting() {
console.log(`my name is ${this.name}`)
}
}
obj.greeting() // Ici. this C'est obj En soi
Copier le Code
// Cas 2
const obj1 = {
name: `obj1's name`,
greeting() {
console.log(`my name is ${this.name}`)
}
}
const obj2 = {
name: `obj2's name`,
greeting: obj1.greeting
}
obj2.greeting() // Ici. this La liaison est obj2
Copier le Code

3.3 Liaison explicite

Il y a une condition préalable à la liaison implicite :

  • Il doit y avoir une référence à la fonction à l'intérieur de l'objet appelé ( Comme un attribut )obj.foo = function() { console.log(this) }
  • Sans une telle référence , Au moment de l'appel , Impossible de trouver la fonction dans cet objet , Ce code ne peut pas être exécuté
  • C'est à cause de cette citation , Indirectement this Lié à l'objet qui a appelé la fonction

Si nous ne voulons pas avoir une telle propriété sur cet objet , Mais j'espère que la fonction this L'objet pointé , Une liaison explicite est nécessaire à ce moment :

  • JS Toutes les fonctions dans peuvent être utilisées callapply
    • callEtapplyLa différence est que,call Les paramètres suivants sont séparés ,apply Le paramètre suivant est un tableau
  • Le premier argument de ces deux fonctions nécessite un objet passé , Cet objet modifie la fonction this Utilisé
  • call Et apply Lors de l'exécution d'une fonction, Peut être explicitement lié this, Cette règle de liaison s'appelle Liaison explicite
function foo() {
console.log(this)
}
foo() // Appel direct, Déclenche la liaison par défaut ,this => window
const obj = {
name: `obj's name`
}
// Utiliser call Méthodes, Le premier paramètre modifie le this Pointage
foo.call(obj) // { name: `obj's name` } Pointage obj En soi
Copier le Code

call Et apply La différence entre

function sum(num1, num2) {
console.log(num1 + num2, this)
}
sum(10, 20) // 30, window
const obj = {
name: `obj'name`,
}
// Sauf pour le premier paramètre , Les paramètres suivants sont les paramètres de la fonction entrante 
// La différence est que,call L'argument pour nécessite un 
sum.call(obj, 10, 20)
// Mais apply L'argument pour est un tableau
sum.apply(obj, [10, 20])
Copier le Code

bind

call Et apply Aucune valeur de retour

function foo() {
console.log(this)
}
// Plusieurs appels sont gênants 
foo.call('aaa')
foo.call('aaa')
foo.call('aaa')
Copier le Code

bind Renvoie une liaison this Nouvelle fonction pour

function foo() {
console.log(this)
}
// En ce moment newFoo C'est déjà this Modifier comme suit: "bar" Une nouvelle fonction pour 
const newFoo = foo.bind('bar')
newFoo() // "bar"
Copier le Code

3.4 new BIND

JS Les fonctions dans peuvent être utilisées comme constructeurs d'une classe ,Peut être utilisénewMots clés

Utiliser new Quand les mots clés, Il y a la procédure suivante :

  1. Créer un nouvel objet
  2. Ce nouvel objet sera exécuté prototype Connexion
  3. Ce nouvel objet sera lié à l'appel de fonction this Allez.(this La liaison est effectuée à cette étape )
  4. Si la fonction ne renvoie pas un autre objet,L'expression renvoie ce nouvel objet

new Lors de la liaison ,this = Nouveaux objets créés( C'est ce qu'on appelle l'objet instance )

4. Priorité de la règle de liaison

  • La règle par défaut a la priorité la plus basse
  • La liaison explicite a priorité sur la liaison implicite
  • new Priorité de liaison supérieure à la liaison implicite
  • new Priorité de liaison supérieure à bind
    • new Liaison et call、apply N'est pas autorisé à être utilisé en même temps, Il n'y a donc pas de problème de conflit
    • new La liaison peut être utilisée simultanément call,Mais new Supérieur à call

new > Liaison explicite > Liaison implicite > Liaison par défaut

5. De la fonction intégrée this Analyse

Minuterie

setTimeout/setInterval

setTimeout(function() {
console.log(this) // window
}, 1000)
Copier le Code

DOM Événements

const div = document.querySelector('.box')
div.addEventListener('click', function() {
console.log(this) // div Élément lui - même
})
Copier le Code

Fonctions intégrées au tableau

const names = ['Alex', 'John', 'Tom']
names.forEach(function(item) {
console.log(item, this) // window
})
// forEach Par défaut this - Oui. window
// Mais vous pouvez passer dans le deuxième paramètre , Le second paramètre modifie la valeur dans la fonction 
names.forEach(function(item) {
console.log(item, this) // "aaa"
}, 'aaa')
// map、filter Attendre les fonctions intégrées au tableau this Par défaut window, Peut passer dans le deuxième paramètre ,Modifier l'intérieur this Direction de
Copier le Code

6. this Une liaison spéciale pour

Avant 4 Les règles ont été adaptées au développement quotidien , Mais il y a toujours une syntaxe qui sort des règles

6.1 Ignorer la liaison explicite

function foo() {
console.log(this)
}
foo.apply("aaa") // aaa Pas de problème!
foo.apply(null) // window
foo.apply(undefined) // window
Copier le Code

Si elle est explicitement liée (apply、call、bind C'est tout.) Le point d'entrée est null/undefined,this Lier automatiquement comme objet global

6.2 Référence indirecte de la fonction

const obj1 = {
name: 'obj1',
foo() {
console.log(this)
},
}
const obj2 = {
name: 'obj2',
}
obj2.bar = obj1.foo
obj2.bar() // this Pointage obj2
// N'oubliez pas d'ajouter un point - virgule ici , Sinon, les parenthèses seront utilisées dans l'analyse lexicale et la déclaration ci - dessus obj2 Considérer comme un tout
;(obj2.bar = obj1.foo)() // Ceci est considéré comme un appel de fonction séparé ,this Pointage window
Copier le Code

Il est préférable de ne pas utiliser cette écriture dans un environnement de production

7. Dans les fonctions fléchées this Pointage

7.1 Qu'est - ce qu'une fonction fléchée

La fonction flèche est ES6 Une autre façon de déclarer une fonction

  • Les fonctions fléchées ne sont pas liées this 、arguments Propriétés
  • Les fonctions fléchées ne peuvent pas être utilisées comme constructeurs (Pas avec new À utiliser ensemble,Une erreur sera lancée)

Comment écrire une fonction fléchée :

  • () Paramètres, Si un seul paramètre peut être omis ()
  • => Les flèches
  • {} Corps fonctionnel, S'il n'y a qu'une seule ligne de code dans la fonction , Le résultat de cette ligne de code est considéré comme une valeur de retour , En même temps, dans ce cas, vous pouvez omettre {}
() => {}
num => { // do something... }
const sum = (num1, num2) => num1 + num2
console.log(sum(10, 20)) // 30
// Exemple d'utilisation des fonctions fléchées :Besoins: Mettez tous les nombres pair dans le tableau * 100 Ajouter après 
const nums = [2, 12, 24, 35, 48]
const res = nums
.filter(num => num % 2 === 0)
.map(num => num * 100)
.reduce((prev, curr) => prev + curr)
console.log(res)
Copier le Code

7.2 Abréviation de la fonction flèche

  • S'il n'y a qu'un seul paramètre,Peut être omis (), Aucun paramètre ne peut être omis ()
  • S'il n'y a qu'une seule ligne de code ,Peut être omis {}, En même temps, le résultat du calcul de cette ligne de code sera la valeur de retour
  • Si un objet est retourné , Je veux aussi omettre {} Et si, Doit être utilisé à l'extérieur () Le paquet
// Cette écriture,Le moteur ne sait pas {} Qu'il s'agisse d'un objet littéral ou d'un exécuteur de fonction 
const foo = () => { name: 'alex', age: 18 }
// C'est nécessaire
const foo = () => ({ name: 'alex', age: 18 })
Copier le Code

7.3 Dans les fonctions fléchées this Pointage

Les fonctions fléchées ne sont pas basées sur 4 Règles de liaison pour déterminer this Pointage, Mais en fonction de la portée extérieure this

const foo = function() {
console.log(this.message)
}
const obj = {
message: 'alex',
}
// Une fonction normale ,C'est basé sur 4 Règles de liaison pour déterminer this Pointé
foo.call(obj) // alex
Copier le Code
window['message'] = 'global message'
const bar = () => {
console.log(this.message)
}
const obj = {
message: `obj's message`,
}
// Mais la fonction fléchée suit la portée extérieure this C'est parti.
bar.call(obj) // global message
Copier le Code

Voir un cas

const obj = {
message: `obj's name`,
foo: function() {
return () => {
console.log(this.message)
}
},
}
const obj2 = {
message: `obj2' name`,
}
obj.foo().call(obj2) // Impression finale obj's name 
// Bien que call Modifié explicitement this Pointage, Mais à cause de la fonction flèche this Suivez le champ d'application externe ,Et foo Fonction this - Oui. obj, De la fonction flèche finale this En fait, c'est aussi obj,Au lieu de obj2
Copier le Code

Scénario d'application

const obj = {
data: [],
fetchData() {
// ES6 Une solution sans fonction fléchée avant 
// var _this = this . Ci - dessous _this Anaphora this,Accessible à partir de obj
setTimeout(function() {
// Il y a un problème avec ce code
// Parce que setTimeout De this Oui. window
// Il n'y a donc pas d'accès aux this C'est - à - dire obj 
console.log('fetched Data !!!')
this.data = [1, 2, 3]
this.getData()
}, 3000)
},
getData() {
console.log('data is', this.data)
},
}
obj.fetchData()
Copier le Code
// Modifier le Code en fonction de la flèche 
const obj = {
data: [],
fetchData() {
// En raison de la fonction flèche this Le point est un champ d'application externe this,Parce que c'est ici. fetchData De this Pointage obj, Ainsi, la fonction fléchée Timer Callback peut être accédée avec succès à obj 
setTimeout(() => {
console.log('fetched Data !!!')
this.data = [1, 2, 3]
this.getData()
}, 3000)
},
getData() {
console.log('data is', this.data)
},
}
obj.fetchData()
Copier le Code

8. Questions d'entrevue this Pointez vers le cas

8.1 Première question

var name = 'window'
var person = {
name: 'person',
sayName: function() {
console.log(this.name)
},
}
function sayName() {
var sss = person.sayName
sss() // window
person.sayName() // person
(person.sayName)() // person
;(b = person.sayName)() // window, Référence à la fonction indirecte décrite ci - dessus , C'est l'équivalent d'un seul appel de fonction 
}
sayName()
Copier le Code

La question est encore plus simple ,Base directe 4 Une sorte de règle de liaison pour juger , Liaison par défaut et liaison implicite , La seule difficulté est (person.sayName)(), Ça peut être considéré comme person.sayName(),Alors c'estperson

8.2 Deuxième question

var name = 'window'
var person1 = {
name: 'person1',
foo1: function() {
console.log(this.name)
},
foo2: () => console.log(this.name),
foo3: function() {
return function() {
console.log(this.name)
}
},
foo4: function() {
return () => {
console.log(this.name)
}
},
}
var person2 = { name: 'person2' }
person1.foo1() // person1,Liaison implicite
person1.foo1.call(person2) // person2 La priorité de liaison explicite est supérieure à la liaison implicite ,Alors c'est person2
person1.foo2() // window Les fonctions fléchées ne sont pas liées this,Donc, hériter person1 La portée supérieure de est la portée globale 
person1.foo2.call(person2) // window Bien que lié foo2 De this Voilà. person2, Mais il a quand même hérité person2 Portée supérieure ,C'est tout.
person1.foo3()() // window Liaison par défaut,Parce que person1.foo() Renvoie une fonction, Cette fonction est ensuite appelée séparément ,Alors c'est window
person1.foo3.call(person2)() // Toujours window, Celui - ci est le même que celui ci - dessus 
person1.foo3().call(person2) // person2, La fonction retournée est explicitement liée ici this Voilà. person2
person1.foo4()() // person1,Les fonctions fléchées ne sont pas liées this,Donc, hériter foo4 De this
person1.foo4.call(person2)() // person2,Tiens. foo4 De this Explicitement lié à person2,Donc C'est person2
person1.foo4().call(person2) // person1, Les mêmes fonctions fléchées ne sont pas liées this
Copier le Code

8.3 Question n° 3

Attention à cette question , Contrairement à la question précédente , Regardez bien l'analyse

var name = 'window'
function Person(name) {
this.name = name
this.foo1 = function() {
console.log(this.name)
}
this.foo2 = () => console.log(this.name)
this.foo3 = function() {
return function() {
console.log(this.name)
}
}
this.foo4 = function() {
return () => {
console.log(this.name)
}
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.foo1() // person1(Liaison implicite)
person1.foo1.call(person2) // person2( La liaison explicite est supérieure à la liaison implicite )
person1.foo2() // person1 Il faut que je te dise ,Bien que foo2 C'est une fonction fléchée, Mais ce qui est utilisé pour déclarer une fonction est this.xx Donc la portée supérieure a été trouvée this, C'est - à - dire l'objet instance person1
person1.foo2.call(person2) // person1 Les fonctions fléchées ne sont pas liées this,Hérité de this.foo2 La portée de,C'est - à - dire:this
person1.foo3()() // window,C'est toujours là. person1.foo3() Renvoie une fonction, Puis appelez cette fonction séparément , Pour les liaisons par défaut 
person1.foo3.call(person2)() // window, Comme la précédente. 
person1.foo3().call(person2) // person2, Voici la fonction qui sera retournée this Explicitement lié à person2
person1.foo4()() // person1,Les fonctions fléchées ne sont pas liées this, Hériter de l'étage supérieur ,C'est - à - dire this
person1.foo4.call(person2)() // person2,Voici le général. foo4 Le champ d'application est lié à person2
person1.foo4().call(person2) // person1,Les fonctions fléchées ne sont pas liées this, Bien que explicitement lié , Mais l'héritage est person1.foo4 Dethis
Copier le Code

8.4 Question n° 4

var name = 'window'
function Person(name) {
this.name = name
this.obj = {
name: 'obj',
foo1: function() {
return function() {
console.log(this.name)
}
},
foo2: function() {
return () => {
console.log(this.name)
}
},
}
}
var person1 = new Person('person1')
var person2 = new Person('person2')
person1.obj.foo1()() // window,foo1 La fonction renvoie une fonction, Cette fonction est appelée indépendamment immédiatement 
person1.obj.foo1.call(person2)() // window, Ou appeler cette fonction indépendamment 
person1.obj.foo1().call(person2) // person2, La fonction qui sera retournée ici est this Explicitement lié à person2
person1.obj.foo2()() // obj,Les fonctions fléchées ne sont pas liées this,Héritera foo2 De this C'est - à - dire obj
person1.obj.foo2.call(person2)() // person2,Ici. foo2 De this Explicitement lié à person2
person1.obj.foo2().call(person2) // obj, Non lié à la fonction flèche this,Héritera foo2 C'est - à - dire obj
Copier le Code

Résumé

Dans cet article, Tu as appris 5 Points de connaissance:

  • Pourquoi this:Améliorer l'efficacité du développement
  • this Problème de pointage:this Liaison dynamique au moment de l'exécution
  • this Règles de liaison pour:4 Règles de liaison des espèces, Mais les fonctions fléchées ne s'appliquent pas à ces quatre , Mais hérité de la portée extérieure this
  • Priorité de la règle de liaison :new BIND > Liaison explicite > Liaison implicite > Liaison par défaut
  • this Une liaison spéciale pour :Dans certains cas( Rarement utilisé dans le développement ),this C'est une liaison spéciale
版权声明
本文为[Alexzhang1030]所创,转载请带上原文链接,感谢
https://javamana.com/2021/11/20211125181405752I.html

  1. MySQL Learning - Logging System Redo log and Bin log
  2. Springboot Common comments | @ configuration
  3. Mécanisme d'expiration du cache redis et d'élimination de la mémoire
  4. Analyse concise du code source redis 01 - configuration de l'environnement
  5. Redis source Concise Analysis 02 - SDS String
  6. Spring cloud gateway practice 2: more routing configuration methods
  7. Principe de mise en œuvre ultime du mécanisme de concurrence Java sous - jacent
  8. [démarrer avec Java 100 exemples] 13. Modifier l’extension de fichier - remplacement de chaîne
  9. Java期末作业——王者荣耀的洛克王国版游戏
  10. Elasticsearch聚合学习之五:排序结果不准的问题分析,阿里巴巴java性能调优实战
  11. Java期末作業——王者榮耀的洛克王國版遊戲
  12. Java final work - King's Glory Rock Kingdom Game
  13. 【网络编程】TCP 网络应用程序开发
  14. 【网络编程入门】什么是 IP、端口、TCP、Socket?
  15. 【網絡編程入門】什麼是 IP、端口、TCP、Socket?
  16. [Introduction à la programmation réseau] qu'est - ce que IP, port, TCP et socket?
  17. [programmation réseau] développement d'applications réseau TCP
  18. [Java Basics] comprendre les génériques
  19. Dix outils open source que les architectes de logiciels Java devraient maîtriser!!
  20. Java经典面试题详解,突围金九银十面试季(附详细答案,mysql集群架构部署方案
  21. java架构之路(多线程)synchronized详解以及锁的膨胀升级过程,mysql数据库实用教程pdf
  22. java整理,java高级特性编程及实战第一章
  23. java教程——反射,mongodb下载教程
  24. Java岗大厂面试百日冲刺 - 日积月累,每日三题【Day12,zookeeper原理作用
  25. Java后端互联网500道中高级面试题(含答案),linux钩子技术
  26. java8 Stream API及常用方法,java初级程序员面试
  27. java-集合-Map(双列)——迪迦重制版,2021Java开发社招面试解答之性能优化
  28. Flink处理函数实战之二:ProcessFunction类,java线程面试题目
  29. flex 布局详解,【Java面试题
  30. Linux basic command learning
  31. Why did docker lose to kubernetes? Docker employee readme!
  32. MySQL安装
  33. Elastic Search Aggregate Learning five: Problem Analysis of Uncertainty of sequencing results, Alibaba Java Performance Tuning Practical
  34. Installing, configuring, starting and accessing rabbitmq under Linux
  35. Oracle SQL injection summary
  36. Installation MySQL
  37. L'exposition à la photo d'essai sur la route i7 du nouveau vaisseau amiral de BMW Pure Electric a également été comparée à celle de Xiaopeng p7.
  38. spring JTA 关于异常处理的时机问题
  39. Le problème du temps de traitement des exceptions dans la JTA printanière
  40. Flink Handling Function Real War II: processfunction class, Java thread interview subject
  41. Oracle SQL injection summary
  42. [Java data structure] you must master the classic example of linked list interview (with super detailed illustration and code)
  43. Do you really know MySQL order by
  44. Record a java reference passing problem
  45. spring JTA 關於异常處理的時機問題
  46. Java - Set - Map (double file) - dija Rewriting, 2021 Java Developer's Performance Optimization
  47. Android入门教程 | OkHttp + Retrofit 取消请求的方法
  48. Java 8 Stream API and common methods, Java Junior Program interview
  49. Github 疯传!史上最强!BAT 大佬,2021年最新Java大厂面试笔试题分享
  50. git(3)Git 分支,zookeeper下载教程
  51. Java Backend Internet 500 questions d'entrevue moyennes et avancées (y compris les réponses), technologie de crochet Linux
  52. Entretien d'entretien d'usine Java post sprint de 100 jours - accumulation de jours et de mois, trois questions par jour [jour 12, fonction de principe de Zookeeper
  53. Tutoriel Java - reflection, tutoriel de téléchargement mongodb
  54. How to analyze several common key and hot issues in redis from multiple dimensions
  55. GIT (3) GIT Branch, Zookeeper Download tutoriel
  56. Tutoriel de démarrage Android | okhttp + Retrofit comment annuler une demande
  57. Design pattern [3.3] - Interpretation of cglib dynamic agent source code
  58. Share the actual operation of private collection project nodejs backend + Vue + Mysql to build a management system
  59. Springboot has 44 application initiators
  60. GitHub上标星2,java项目开发实训教程