Dans la console, j'ai créé une fonction de construction 'Car' comme ci-dessous, et new-ed un objet nommé 'mycar', et il s'est passé comme ceci:
> var Car = function() { ... this.make = "Ford"; ... } undefined > var mycar = new Car() undefined > mycar.make // when I visit mycar.make, it worked 'Ford' > Car.make // when I visit Car.make, it didn't work undefined
Je voudrais donc demander:
Comment visiter le 'Car.make' comme si je vis le 'mycar.make'?
Clarifier: visiter le nom via
Car
mais pas viamycar
- Formulaire HTML avec Sendemail
- Comment puis-je appeler une fonction à partir d'un fichier javascript externe dans un autre fichier javascript externe?
- Détection de collision dans un jeu javascript?
- Inclure le fichier dans HTML par JavaScript ou jquery dynamiquement
- Comment modifier (modifier) une vidéo dans le navigateur?
Où est-ce que le champ this.make="Ford"
allé?
J'ai également essayé d'étendre son __proto__
dans la console Chrome dev, mais je ne l'ai pas trouvé.
Merci!
this
Examinons attentivement le code suivant:
Car = function (brand) { this.brand = brand; } Car.prototype.getBrand = function () { return this.brand; }; ford = new Car("Ford"); fiat = new Car("Fiat"); ford.getBrand(); // "Ford" fiat.getBrand(); // "Fiat"
À première vue, vous pouvez penser que getBrand
est la propriété de ford
et fiat
, mais c'est faux. Lorsque vous souhaitez savoir comment les choses sont organisées en mémoire, vous ne devez pas compter uniquement sur le code, cela peut être trompeur. Voici un instantané approprié:
/ ├── Car │ └── prototype │ └── getBrand ├── ford │ ├── brand │ └── __proto__ -> /Car/prototype └── fiat ├── brand └── __proto__ -> /Car/prototype
Pensez-y comme une structure de dossier où les répertoires sont des objets, les fichiers sont des attributs ou des méthodes, et les liens sont des références à d'autres objets. Comme je l'ai dit, /ford/getBrand
n'existe pas. Vérifiez par vous-même, ford.hasOwnProperty("getBrand")
donne false
. Alors, vous pouvez demander pourquoi ford.getBrand()
ne se bloque pas? C'est là que cette chose étrange appelée __proto__
entre.
__proto__
est une propriété que vous pouvez trouver dans chaque objet. Dans notre code, /ford/__proto__
pourrait être considéré comme un lien vers /Car/prototype
. Cela pourrait également être considéré comme un fichier caché car vous ne le verrez pas si vous écrivez console.log(ford)
. Le fait est que vous n'êtes pas censé jouer avec lui, "L'utilisation de __proto__
est controversée et a été découragée". (En savoir plus sur MDN ).
Mais au-delà de la controverse __proto__
, ford.getBrand()
fonctionne car JavaScript implémente ce qu'on appelle un mécanisme de recherche. Lorsqu'il ne parvient pas à trouver quelque chose dans un objet, il continuera à chercher dans le prototype de cet objet. Comme il se produit, puisque /ford/getBrand
n'existe pas, JavaScript examinera /ford/__proto__
.
Ce que je veux vous montrer, c'est qu'il y a beaucoup de choses qui se passent derrière la scène, mais il n'y a rien de magique. La langue effectue quelques astuces que vous devez trouver et démystifier 🙂
this
this
s'agit d'un mot-clé contextuel, en d'autres termes, sa valeur dépend d'un contexte. Un contexte (= une portée) est un ensemble de valeurs. Par exemple, le contexte global ( /
) contient Car
, ford
et fiat
, mais il contient également this
qui fait référence à … le contexte global lui-même! Plus intéressant, JavaScript vous permet de créer de nouveaux contextes. Pour autant que je sache, appeler une fonction est le seul moyen de le faire:
function f (v) { // context birth // ... // context death } f(); // new local context f(); // new local context
Dans un contexte local comme celui ci-dessus, this
réfère au contexte global par défaut. Vous voudrez peut-être remplacer le comportement par défaut, malheureusement, vous ne pouvez pas écrire this = anything
. Nevermind, vous pouvez toujours prendre le contrôle de this
utilisant le new
mot-clé, un appel contextuel ou … la force brute!
Par défaut :
Car("Ford"); console.log(brand); // prints "Ford" :-\ told you, // in the context of `Car` // `this` refers to the global // context by default
Avec le new
mot-clé:
audi = new Car("Audi"); // in the context of `Car` // `this` refers to `audi`
Avec un appel contextuel:
ford.getBrand(); // "Ford" // in the context of `getBrand` // `this` refers to `ford`
Utilisation de la "force brute":
ford.getBrand.call(fiat); // "Fiat" // in the context of `getBrand` // `this` refers to `fiat` !
Cependant, comme vous pouvez le voir, this
ne fait jamais référence à la Car
, c'est pourquoi /Car/brand
manque. L'ajout de propriétés à partir de l'intérieur du constructeur modifie l'instance ( ford
, fiat
ou audi
), et non la classe ( Car
).
this
Trace of ford = new Car("Ford")
:
1. /Car exists ? yes 2. create a new object 3. call Car with this = the new object 3.1. add __proto__ to this 3.2. set this.__proto__ to /Car/prototype 3.1. add brand to this 3.2. set this.brand to "Ford" 3.3. return this (the new object) 4. set ford to the new object
Trace of ford.getBrand.call(fiat)
:
1. /ford exists ? yes 2. /ford/getBrand exists ? no 3. /ford/__proto__/getBrand exists ? yes 4. call /ford/__proto__/getBrand with this = fiat 4.1. /fiat exists ? yes 4.2. /fiat/brand exists ? yes 4.3. return /fiat/brand
Une petite démo:
Car = function (brand) { console.log("this === Car =", this === Car); this.brand = brand; } Car.prototype.getBrand = function () { console.log("this === ford =", this === ford); return this.brand; }; ford = new Car("Ford"); ford.getBrand(); console.log("ford.hasOwnProperty(\"getBrand\") =", ford.hasOwnProperty("getBrand")); console.log("Car.prototype === ford.__proto__ =", Car.prototype === ford.__proto__); console.log("Car =", Car); console.log("ford =", ford); console.log("Car.prototype =", Car.prototype); console.log("ford.__proto__ =", ford.__proto__);
Ce mot this
clé dans la fonction se réfère à l'objet créé par le new
mot-clé.
Si vous souhaitez créer une propriété "statique", vous devriez la configurer directement sur le nom de la fonction comme ceci:
function Car() { } Car.make = "Ford";
Fondamentalement, vous ne pouvez pas avoir "les deux". La propriété est statique (sur la fonction elle-même) ou instance (sur l'objet créé par new
)