Cet article est JavaScript Série avancéeTitre VI
,Les détails JS Dans this Pointage
Dans les langages de programmation courants,Presque toujours.this
Mots clés(Objective-C- Oui.self
).Mais JS Dans this Et l'objet commun orienté this C'est différent.:
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
// 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
this
Pointage GlobalObject,C'est - à - direwindow
this
Pointer vers un objet vide{}
En développement, En général, nous n'utilisons plus globalement this, Généralement utilisé dans une fonction .
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
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
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
Il y a une condition préalable à la liaison implicite :
obj.foo = function() { console.log(this) }
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 :
call
、apply
call
Etapply
La différence est que,call Les paramètres suivants sont séparés ,apply Le paramètre suivant est un tableau 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
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
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
JS Les fonctions dans peuvent être utilisées comme constructeurs d'une classe ,Peut être utilisénew
Mots clés
Utiliser new Quand les mots clés, Il y a la procédure suivante :
new
Lors de la liaison ,this = Nouveaux objets créés( C'est ce qu'on appelle l'objet instance )
new > Liaison explicite > Liaison implicite > Liaison par défaut
setTimeout/setInterval
setTimeout(function() {
console.log(this) // window
}, 1000)
Copier le Code
const div = document.querySelector('.box')
div.addEventListener('click', function() {
console.log(this) // div Élément lui - même
})
Copier le Code
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
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
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
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
La fonction flèche est ES6 Une autre façon de déclarer une fonction
Comment écrire une fonction fléchée :
() => {}
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
// 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
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
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
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
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
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
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
Dans cet article, Tu as appris 5 Points de connaissance: