En JS, nous avons confiance - La meilleure façon d'apprendre est de construire/coder et d'enseigner. Je crée des défis pour aider mes amis à apprendre JavaScript et en retour, cela m'aide à assimiler le langage à un niveau beaucoup plus profond. N'hésitez pas à cloner, bifurquer et tirer.
function a ( x ) {
x ++ ;
return function ( ) {
console . log ( ++ x ) ;
} ;
}
a ( 1 ) ( ) ;
a ( 1 ) ( ) ;
a ( 1 ) ( ) ;
let x = a ( 1 ) ;
x ( ) ;
x ( ) ;
x ( ) ;
1, 2, 3
et 1, 2, 3
3, 3, 3
et 3, 4, 5
3, 3, 3
et 1, 2, 3
1, 2, 3
et 3, 3, 3
Cette question revisite la fermeture, l'un des concepts les plus déroutants de JavaScript. La fermeture nous permet de créer une stateful function
et une telle fonction peut accéder à la variable en dehors de sa portée. En un mot, une fermeture peut avoir accès à la variable global
(portée), à la portée father function
et its
propre portée.
Nous avons ici, la seule bonne réponse, 3, 3, 3 et 3, 4, 5 car d'abord nous appelons simplement la fonction a()
. Cela fonctionne comme une fonction normale et nous n’avons encore rien vu de soi-disant stateful
. Dans le code suivant, nous déclarons une variable x
et elle stocke la valeur de la fonction a(1)
, c'est pourquoi nous obtenons 3. 4. 5 plutôt que 3, 3, 3.
Ce genre de piège me donne le sentiment d'une variable static
dans le monde PHP.
function Name ( a , b ) {
this . a = a ;
this . b = b ;
}
const me = Name ( "Vuong" , "Nguyen" ) ;
console . log ( ! ( a . length - window . a . length ) ) ;
undefined
NaN
true
false
Nous obtenons vrai dans la console. La partie délicate est lorsque nous créons un objet à partir du nom de la fonction constructeur mais que nous N'UTILISONS PAS new
clavier. Cela rend la variable a
et obtient la valeur "Vuong". N'oubliez pas qu'il s'agit en fait d'une propriété de la window
de l'objet global (dans le navigateur) ou global
dans le nodejs.
On obtient alors a.length
~ 5 et window.a.length
~ 5 qui renvoient 0. !0 renvoie true.
Imaginez ce qui se passerait lorsque nous créerions l' me
avec le new
clétage. C'est une enquête intéressante !
const x = function ( ... x ) {
let k = ( typeof x ) . length ;
let y = ( ) => "freetut" . length ;
let z = { y : y } ;
return k - z . y ( ) ;
} ;
console . log ( Boolean ( x ( ) ) ) ;
true
false
L'opérateur spread ...x
pourrait nous aider à obtenir le paramètre dans la fonction sous forme de tableau. Pourtant, en Javascript, le type de tableau renvoie « objet » plutôt que « tableau ». C'est totalement étrange si vous venez de PHP.
Cela dit, nous avons maintenant la longueur de l' object
chaîne qui renvoie 6. zy() renvoie simplement la longueur de la chaîne 'freetut' (7).
Sachez que la fonction x() (sous forme de function express
ou anonymous function
(si vous venez de PHP) renvoie -1 lorsqu'elle est appelée et lorsqu'elle est convertie en bool avec Boolean(-1)
renvoie vrai au lieu de faux. Noté que Boolean(0)
renvoie false.
( function js ( x ) {
const y = ( j ) => j * x ;
console . log ( y ( s ( ) ) ) ;
function s ( ) {
return j ( ) ;
}
function j ( ) {
return x ** x ;
}
} ) ( 3 ) ;
undefined
La fonction js()
peut être exécutée automatiquement sans l'appeler et connue sous le nom d'IIFE (Immediately Invoked Function Expression). A noter que le paramètre x
de la fonction js
est effectivement passé avec la valeur 3.
La valeur renvoyée par la fonction est y(s())), ce qui signifie appeler trois autres fonctions y()
, s()
et j()
car la fonction s()
renvoie j()
.
j() renvoie 3^3 = 27 donc s() renvoie 27.
y(s()) signifie y(27) qui renvoie 27*3 = 81.
Notez que nous pouvons appeler declare function
AVANT que la fonction ne soit réellement déclarée, mais pas avec expression function
.
var tip = 100 ;
( function ( ) {
console . log ( "I have $" + husband ( ) ) ;
function wife ( ) {
return tip * 2 ;
}
function husband ( ) {
return wife ( ) / 2 ;
}
var tip = 10 ;
} ) ( ) ;
Nous avons ici une IIFE (Immediately Invoked Function Expression). Cela signifie que nous n'avons pas besoin de l'appeler mais qu'il sera exécuté automatiquement une fois déclaré. Le flux est le suivant : mari() renvoie femme()/2 et femme() renvoie pourboire*2.
Nous pourrions penser que tip = 100 car il s'agit d'une variable globale lors de la déclaration avec le mot-clé var
. Cependant, il n'est en fait undefined
car nous avons également var tip = 10
À L'INTÉRIEUR de la fonction. Comme la variable tip
est levée avec la valeur par défaut undefined
, le résultat final serait D. Nous savons que undefined
renvoie NaN lorsque nous essayons de diviser par 2 ou de multiplier par 2.
Si nous ne déclarons pas à nouveau var tip = 10;
à la fin de la fonction, nous obtiendrons définitivement B.
JS est amusant, non ?
const js = { language : "loosely type" , label : "difficult" } ;
const edu = { ... js , level : "PhD" } ;
const newbie = edu ;
delete edu . language ;
console . log ( Object . keys ( newbie ) . length ) ;
Ce défi révise la fonctionnalité de l'ES6 concernant spread operator ...
L'opérateur spread est très utile pour récupérer des paramètres en fonction, pour unite
ou combine
un objet et un tableau en JavaScript. PHP possède également cette fonctionnalité.
Dans la variable edu
, nous utilisons ...js
(opérateur spread ici) pour combiner les deux objets en un seul. Cela fonctionne de la même manière avec array.
Ensuite, nous déclarons une autre variable nommée newbie
. Remarque IMPORTANTE : En déclarant la variable ainsi, les deux variables pointent vers la MÊME POSITION dans la mémoire. Nous connaissons peut-être quelque chose comme $a = &$b
en PHP, qui permet aux deux variables de fonctionner de la même manière. Nous aurions pu connaître pass by reference
dans cette affaire.
Ensuite, nous en avons 2 car edu.language
est supprimé. Les deux objets ne comportent désormais plus que deux éléments.
Il est maintenant temps de penser à gérer un objet dans JS, qu'il soit superficiel ou profond.
var candidate = {
name : "Vuong" ,
age : 30 ,
} ;
var job = {
frontend : "Vuejs or Reactjs" ,
backend : "PHP and Laravel" ,
city : "Auckland" ,
} ;
class Combine {
static get ( ) {
return Object . assign ( candidate , job ) ;
}
static count ( ) {
return Object . keys ( this . get ( ) ) . length ;
}
}
console . log ( Combine . count ( ) ) ;
La méthode intégrée Object.assign(candidate, job)
fusionne les deux objets candidate
et job
en un seul objet. Ensuite, la méthode Object.keys
compte le nombre de key
dans l'objet.
Notez que deux méthodes get()
et count()
sont définies comme static
, elles doivent donc être appelées de manière statique en utilisant la syntaxe Class.staticmethod()
. Ensuite, l'objet final reçoit 5 éléments.
var x = 1 ;
( ( ) => {
x += 1 ;
++ x ;
} ) ( ) ;
( ( y ) => {
x += y ;
x = x % y ;
} ) ( 2 ) ;
( ( ) => ( x += x ) ) ( ) ;
( ( ) => ( x *= x ) ) ( ) ;
console . log ( x ) ;
Initialement x
est déclaré avec la valeur 1. Dans la première fonction IIFE, il y a deux opérations. x
devient d’abord 2 puis 3.
Dans la deuxième fonction IIFE, x = x + y
alors la valeur actuelle est 5. Dans la deuxième opération, elle ne renvoie que 1 car elle subit 5%2
.
Dans les troisième et quatrième fonctions IIFE, nous obtenons 2 x = x + x
puis 4 x = x * x
. C'est plus que simple.
$ var = 10 ;
$ f = function ( $ let ) use ( $ var ) {
return ++ $ let + $ var ;
};
$ var = 15 ;
echo $ f ( 10 );
var x = 10 ;
const f = ( l ) => ++ l + x ;
x = 15 ;
console . log ( f ( 10 ) ) ;
Cette question illustre les différences entre PHP et JavaScript lors de la gestion de la fermeture. Dans le premier extrait, nous déclarons une fermeture avec le mot-clé use
. La fermeture en PHP est simplement une fonction anonyme et les données sont transmises à la fonction à l'aide du mot-clé use
. Sinon, il est appelé lambda
lorsque nous n'utilisons pas le mot-clé use
. Vous pouvez vérifier le résultat de l'extrait ici https://3v4l.org/PSeMY. closure
PHP n'accepte que la valeur de la variable AVANT que la fermeture ne soit définie, peu importe où elle est appelée. En tant que tel, $var
vaut 10 au lieu de 15.
Au contraire, JavaScript traite la variable un peu différemment lorsqu'elle est transmise à une fonction anonyme. Nous n'avons pas besoin d'utiliser le mot-clé use
ici pour transmettre la variable à la fermeture. La variable x
dans le deuxième extrait est mise à jour avant l'appel de la fermeture, nous obtenons alors 26.
Notez que dans PHP 7.4, nous avons la fonction flèche et nous n'avons alors pas besoin d'utiliser le mot-clé use
pour passer la variable à la fonction. Une autre façon d'appeler une ariable global
dans une fonction en PHP consiste à utiliser le mot-clé global
ou à utiliser la variable GLOBAL intégrée $GLOBALS.
let x = { } ;
let y = { } ;
let z = x ;
console . log ( x == y ) ;
console . log ( x === y ) ;
console . log ( x == z ) ;
console . log ( x === z ) ;
Techniquement, x
et y
ont la même valeur. Les deux sont des objets vides. Cependant, nous n'utilisons pas la valeur pour comparer des objets.
z
et x
sont deux objets faisant référence à la même position mémoire. En JavaScript, le tableau et l'objet sont passés par reference
. x
et z
renvoient donc vrai lors de la comparaison.
console . log ( "hello" ) ;
setTimeout ( ( ) => console . log ( "world" ) , 0 ) ;
console . log ( "hi" ) ;
Étant donné que la fonction setTimeout() sera conservée dans la task queue
avant de revenir à stack,
"hello" et "hi" seront imprimés en premier, puis A est incorrect. C'est également le cas des réponses C et D.
Quel que soit le nombre de secondes que vous définissez pour la fonction setTimeout()
, elle s'exécutera après le code synchrone. Nous obtiendrons donc "bonjour" en premier car il sera placé en premier dans la pile d'appels. Bien que setTimeout()
soit ensuite placé dans la pile d'appels, il sera ensuite déchargé vers l'API Web (ou l'API Node), puis appelé lorsque d'autres codes synchrones seront effacés. Cela signifie que nous obtenons ensuite « salut » et enfin « monde ».
Donc B est la bonne réponse.
Crédit : @kaitoubg (voz) pour votre suggestion concernant le timeout throttled
par lequel j'ai décidé de modifier légèrement la question. Cela garantira que les lecteurs ne seront pas confus car le code précédent pourrait donner des résultats différents lorsqu'il sera testé sur d'autres navigateurs ou environnements. Le point principal de la question concerne la différence entre le code synchrone et le code asynchrone lors de l'utilisation setTimeout.
.
String . prototype . lengthy = ( ) => {
console . log ( "hello" ) ;
} ;
let x = { name : "Vuong" } ;
delete x ;
x . name . lengthy ( ) ;
String.prototype.someThing = function () {}
est le moyen courant de définir une nouvelle méthode intégrée pour String
. Nous pouvons faire la même chose avec Array
, Object
ou FunctionName
où FunctionName est la fonction conçue par nous-mêmes.
Il n'est pas difficile de réaliser que "string".lengthy()
renvoie toujours hello
. Pourtant, la partie délicate réside dans l' delete object
où l'on pourrait penser que cette expression supprimera entièrement l'objet. Ce n'est pas le cas car delete
est utilisé pour supprimer uniquement la propriété de l'objet. Cela ne supprime pas l'objet. Ensuite, nous obtenons hello
plutôt que ReferenceError
.
Notez que si nous déclarons un objet sans let, const
ou var
, nous avons alors un objet global. delete objectName
puis retournez true
. Sinon, il renvoie toujours false
.
let x = { } ;
x . __proto__ . hi = 10 ;
Object . prototype . hi = ++ x . hi ;
console . log ( x . hi + Object . keys ( x ) . length ) ;
Nous avons d’abord un objet vide x
, puis nous ajoutons une autre propriété hi
pour x avec x.__proto__.hi
. Notez que cela équivaut à Object.prototype.hi = 10
et nous ajoutons à l'objet father
Object
la propriété hi
. Cela signifie que chaque objet héritera de cette propriété. La propriété hi
devient partagée. Disons maintenant que nous déclarons un nouvel objet tel que let y = {}
, y
a maintenant une propriété hi
héritée du father
Object
. En termes simples, x.__proto__ === Object.prototype
renvoie true
.
Ensuite, nous écrasons la propriété hi
par une nouvelle valeur 11. Enfin, nous avons 11 + 1 = 12. x
a une propriété et x.hi
renvoie 11.
Mis à jour (27 juillet 2021). Si vous écrivez Object.prototype.hi = 11;
au lieu de Object.prototype.hi = ++x.hi;
comme écrit dans le code ci-dessus, alors Object.keys(x)
renverra un tableau vide car Object.keys(object)
ne renvoie que la propriété de l'objet lui-même, pas celles héritées. Cela signifie que le résultat final sera 11 au lieu de 12. Pour une raison quelconque, le code ``Object.prototype.hi = ++x.hi; will create a property for the object
x` lui-même, puis `Object.keys(x)` nous donnera le tableau `["hi"]`.
Pourtant, si vous exécutez console.log(x.hasOwnProperty("hi"))
il renvoie toujours false
. À propos, lorsque vous ajoutez délibérément une propriété pour x telle que x.test = "testing"
, alors console.log(x.hasOwnProperty("test"))
renvoie true
.
const array = ( a ) => {
let length = a . length ;
delete a [ length - 1 ] ;
return a . length ;
} ;
console . log ( array ( [ 1 , 2 , 3 , 4 ] ) ) ;
const object = ( obj ) => {
let key = Object . keys ( obj ) ;
let length = key . length ;
delete obj [ key [ length - 1 ] ] ;
return Object . keys ( obj ) . length ;
} ;
console . log ( object ( { 1 : 2 , 2 : 3 , 3 : 4 , 4 : 5 } ) ) ;
const setPropNull = ( obj ) => {
let key = Object . keys ( obj ) ;
let length = key . length ;
obj [ key [ length - 1 ] ] = null ;
return Object . keys ( obj ) . length ;
} ;
console . log ( setPropNull ( { 1 : 2 , 2 : 3 , 3 : 4 , 4 : 5 } ) ) ;
Cette question examine le fonctionnement de l'opérateur delete
en JavaScript. En bref, cela ne fait rien lorsque nous écrivons delete someObject
ou delete someArray
. Il supprime néanmoins complètement et supprime une propriété d'un objet lors de l'écriture de quelque chose comme delete someObject.someProperty
. Dans le cas d'un tableau, lorsque nous écrivons delete someArray[keyNumber]
, cela supprime uniquement la value
de l' index
, conserve l' index
intact et la nouvelle value
est maintenant définie sur undefined
. Pour cette raison, dans le premier extrait de code, nous obtenons (la longueur) 4 éléments comme dans le tableau d'origine mais il ne reste que 3 propriétés dans l'objet passé lorsque la fonction object() est appelée, comme dans le deuxième extrait.
Le troisième extrait nous donne 4 car déclarer la propriété d'un objet comme null
ou undefined
ne supprime pas complètement la propriété. La clé est intacte. La longueur de l'objet est donc immuable.
Pour ceux qui connaissent PHP, nous avons unset($someArray[index])
qui supprime l'élément du tableau, à la fois la clé et la valeur. Lorsque print_r
le tableau, nous pourrions ne pas voir la clé et la valeur qui n'ont pas été définies. Cependant, lorsque nous poussons (en utilisant array_push($someArray, $someValue)
) un nouvel élément dans ce tableau, nous pouvons voir que la clé précédente est toujours conservée, mais aucune valeur et n'est pas affichée. C'est quelque chose dont vous devez être conscient. Jetez un œil à https://3v4l.org/7C3Nf
var a = [ 1 , 2 , 3 ] ;
var b = [ 1 , 2 , 3 ] ;
var c = [ 1 , 2 , 3 ] ;
var d = c ;
var e = [ 1 , 2 , 3 ] ;
var f = e . slice ( ) ;
console . log ( a === b ) ;
console . log ( c === d ) ;
console . log ( e === f ) ;
a
et b
renvoient false car ils pointent vers un emplacement mémoire différent même si les valeurs sont les mêmes. Si vous venez du monde PHP, cela retournera évidemment vrai lorsque nous comparerons la valeur ou la valeur + le type. Découvrez-le : https://3v4l.org/IjaOs.
En JavaScript, la valeur est passée par référence dans le cas d' array
et object
. Ainsi, dans le deuxième cas, d
est la copie de c
mais ils pointent tous deux vers la même position mémoire. Tout ce qui change dans c
entraînera le changement dans d
. En PHP, nous pourrions avoir $a = &$b;
, travaillant de la même manière.
Le troisième nous donne une astuce pour copier un tableau en JavaScript en utilisant la méthode slice()
. Maintenant, nous avons f
, qui est la copie de e
mais ils pointent vers des emplacements mémoire différents, ils ont donc une "vie" différente. Nous obtenons donc false
lorsqu'ils sont comparés.
var languages = {
name : [ "elixir" , "golang" , "js" , "php" , { name : "feature" } ] ,
feature : "awesome" ,
} ;
let flag = languages . hasOwnProperty ( Object . values ( languages ) [ 0 ] [ 4 ] . name ) ;
( ( ) => {
if ( flag !== false ) {
console . log (
Object . getOwnPropertyNames ( languages ) [ 0 ] . length <<
Object . keys ( languages ) [ 0 ] . length
) ;
} else {
console . log (
Object . getOwnPropertyNames ( languages ) [ 1 ] . length <<
Object . keys ( languages ) [ 1 ] . length
) ;
}
} ) ( ) ;
L'extrait de code est assez délicat car il comporte plusieurs méthodes intégrées différentes pour gérer les objets en JavaScript
. Par exemple, Object.keys
et Object.getOwnPropertyNames
sont utilisés même s'ils sont assez similaires, sauf que ces derniers peuvent renvoyer des propriétés non énumérables. Vous voudrez peut-être jeter un œil à cette référence soigneusement écrite https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames
Object.values
et Object.keys
renvoient respectivement la valeur de propriété et le nom de propriété de l'objet. Cela n’a rien de nouveau. object.hasOwnProperty('propertyName')
renvoie un boolean
confirmant si une propriété existe ou non.
Nous avons flag
true car Object.values(languages)[0][4].name
renvoie feature
, qui est également le nom de la propriété.
Ensuite, nous avons 4 << 4 dans le flux if-else
qui renvoie la valeur au niveau du bit, équivalente à 4*2^4
~ 4*16
~ 64.
var player = {
name : "Ronaldo" ,
age : 34 ,
getAge : function ( ) {
return ++ this . age - this . name . length ;
} ,
} ;
function score ( greeting , year ) {
console . log (
greeting + " " + this . name + `! You were born in ${ year - this . getAge ( ) } `
) ;
}
window . window . window . score . call ( window .