Wir vertrauen auf JS – Der beste Weg zum Lernen ist das Erstellen/Codieren und Lehren. Ich erstelle die Herausforderungen, um meinen Freunden beim Erlernen von JavaScript zu helfen, und im Gegenzug hilft es mir, die Sprache auf einer viel tieferen Ebene zu erlernen. Fühlen Sie sich frei zu klonen, zu forken und zu ziehen.
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
und 1, 2, 3
3, 3, 3
und 3, 4, 5
3, 3, 3
und 1, 2, 3
1, 2, 3
und 3, 3, 3
Bei dieser Frage geht es um den Abschluss – eines der verwirrendsten Konzepte in JavaScript. Durch den Abschluss können wir eine stateful function
erstellen, und eine solche Funktion kann auf die Variable außerhalb ihres Gültigkeitsbereichs zugreifen. Kurz gesagt, ein Abschluss kann Zugriff auf die global
Variable (Bereich), den Bereich father function
und its
eigenen Bereich haben.
Wir haben hier die einzig richtige Antwort: 3, 3, 3 und 3, 4, 5, weil wir zunächst einfach die Funktion a()
aufrufen. Es funktioniert wie eine normale Funktion und wir haben noch nichts sogenanntes stateful
gesehen. Im folgenden Code deklarieren wir eine Variable x
und sie speichert den Wert der Funktion a(1)
, deshalb erhalten wir 3. 4. 5 statt 3, 3, 3.
Diese Art von Fallstrick gibt mir das Gefühl einer static
Variablen in der PHP-Welt.
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
Wir werden in der Konsole wahr. Der schwierige Teil besteht darin, dass wir ein Objekt aus dem Konstruktorfunktionsnamen erstellen, aber KEINE new
Schlüsselarbeit verwenden. Dadurch wird die Variable a
und erhält den Wert „Vuong“. Denken Sie daran, dass es sich tatsächlich um eine Eigenschaft des globalen window
(im Browser) oder global
in den Nodejs handelt.
Wir erhalten dann a.length
~ 5 und window.a.length
~ 5, die 0 zurückgeben. !0 gibt true zurück.
Stellen Sie sich vor, was passieren würde, wenn wir die me
mit dem new
Schlüsselwerk erstellen. Das ist eine interessante Anfrage!
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
Der Spread-Operator ...x
könnte uns helfen, den Parameter in der Funktion in Form eines Arrays zu erhalten. In Javascript gibt der Array-Typ jedoch „Objekt“ und nicht „Array“ zurück. Es ist völlig seltsam, wenn Sie von PHP kommen.
Das heißt, wir haben jetzt die Länge des String- object
, das 6 zurückgibt. zy() gibt einfach die Länge des Strings „freetut“ (7) zurück.
Beachten Sie, dass die Funktion x() (in Form einer function express
oder anonymous function
(wenn Sie von PHP kommen) beim Aufruf -1 zurückgibt und bei der Konvertierung in bool mit Boolean(-1)
true statt false zurückgibt. Zur Kenntnis genommen dass Boolean(0)
false zurückgibt.
( function js ( x ) {
const y = ( j ) => j * x ;
console . log ( y ( s ( ) ) ) ;
function s ( ) {
return j ( ) ;
}
function j ( ) {
return x ** x ;
}
} ) ( 3 ) ;
undefined
Die Funktion js()
kann ohne Aufruf automatisch ausgeführt werden und ist als IIFE (Immediately Invoked Function Expression) bekannt. Beachten Sie, dass der Parameter x
der Funktion js
tatsächlich mit dem Wert 3 übergeben wird.
Der Rückgabewert der Funktion ist y(s())), was bedeutet, dass drei weitere Funktionen y()
, s()
und j()
aufgerufen werden, da die Funktion s()
j()
zurückgibt.
j() gibt 3^3 = 27 zurück, sodass s() 27 zurückgibt.
y(s()) bedeutet y(27), was 27*3 = 81 zurückgibt.
Beachten Sie, dass wir declare function
aufrufen können, BEVOR die Funktion tatsächlich deklariert wird, jedoch nicht mit expression function
.
var tip = 100 ;
( function ( ) {
console . log ( "I have $" + husband ( ) ) ;
function wife ( ) {
return tip * 2 ;
}
function husband ( ) {
return wife ( ) / 2 ;
}
var tip = 10 ;
} ) ( ) ;
Wir haben hier einen IIFE (Immediately Invoked Function Expression). Das bedeutet, dass wir es nicht aufrufen müssen, sondern es automatisch ausgeführt wird, wenn es deklariert wird. Der Ablauf ist wie folgt: Ehemann() gibt Ehefrau()/2 zurück und Ehefrau() gibt Tipp*2 zurück.
Wir denken vielleicht, dass tip = 100 ist, weil es sich bei der Deklaration mit dem Schlüsselwort var
um eine globale Variable handelt. Tatsächlich ist es jedoch undefined
, da wir auch var tip = 10
INNERHALB der Funktion haben. Da die Variable tip
mit dem Standardwert undefined
angehoben wird, wäre das Endergebnis D. Wir wissen, dass undefined
NaN zurückgibt, wenn wir versuchen, durch 2 zu dividieren oder mit 2 zu multiplizieren.
Wenn wir var tip = 10;
Am Ende der Funktion erhalten wir definitiv B.
JS macht Spaß, oder?
const js = { language : "loosely type" , label : "difficult" } ;
const edu = { ... js , level : "PhD" } ;
const newbie = edu ;
delete edu . language ;
console . log ( Object . keys ( newbie ) . length ) ;
Diese Herausforderung überarbeitet die ES6-Funktion in Bezug auf spread operator ...
Der Spread-Operator ist sehr nützlich zum Abrufen von Parametern in einer Funktion, um Objekt und Array in JavaScript zu unite
oder combine
. Auch PHP verfügt über diese Funktion.
In der Variablen edu
verwenden wir ...js
(hier Spread-Operator), um beide Objekte zu einem zu kombinieren. Mit Arrays funktioniert es genauso.
Dann deklarieren wir eine weitere Variable namens newbie
. WICHTIGER Hinweis: Durch die Deklaration der Variablen verweisen beide Variablen auf die GLEICHE POSITION im Speicher. Möglicherweise haben wir in PHP so etwas wie $a = &$b
gekannt, wodurch beide Variablen auf die gleiche Weise funktionieren. Möglicherweise wussten wir in diesem Fall von pass by reference
.
Dann haben wir 2, da edu.language
gelöscht wird. Beide Objekte haben jetzt nur noch zwei Elemente.
Jetzt ist es an der Zeit, darüber nachzudenken, ein Objekt in JS entweder flach oder tief zu bewältigen.
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 ( ) ) ;
Die eingebaute Methode Object.assign(candidate, job)
führt die beiden Objekte candidate
und job
zu einem Objekt zusammen. Dann zählt die Methode Object.keys
die Anzahl der key
im Objekt.
Beachten Sie, dass zwei Methoden get()
und count()
als static
definiert sind und daher statisch mithilfe Class.staticmethod()
-Syntax aufgerufen werden müssen. Dann erhält das endgültige Objekt 5 Elemente.
var x = 1 ;
( ( ) => {
x += 1 ;
++ x ;
} ) ( ) ;
( ( y ) => {
x += y ;
x = x % y ;
} ) ( 2 ) ;
( ( ) => ( x += x ) ) ( ) ;
( ( ) => ( x *= x ) ) ( ) ;
console . log ( x ) ;
Zunächst wird x
mit dem Wert 1 deklariert. In der ersten IIFE-Funktion gibt es zwei Operationen. Zuerst wird x
zu 2 und dann zu 3.
In der zweiten IIFE-Funktion x = x + y
ist der aktuelle Wert 5. In der zweiten Operation wird nur 1 zurückgegeben, da 5%2
ausgeführt wird.
In der dritten und vierten IIFE-Funktion erhalten wir 2 x = x + x
und dann 4 x = x * x
. Es ist mehr als einfach.
$ 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 ) ) ;
Diese Frage veranschaulicht die Unterschiede zwischen PHP und JavaScript bei der Verarbeitung von Schließungen. Im ersten Snippet deklarieren wir einen Abschluss mit dem Schlüsselwort use
. Der Abschluss in PHP ist einfach eine anonyme Funktion und die Daten werden mit dem Schlüsselwort use
an die Funktion übergeben. Andernfalls wird es als lambda
bezeichnet, wenn wir das Schlüsselwort use
nicht verwenden. Sie können das Ergebnis des Snippets hier überprüfen: https://3v4l.org/PSeMY. Der PHP- closure
akzeptiert nur den Wert der Variablen, BEVOR der Abschluss definiert wird, unabhängig davon, wo er aufgerufen wird. Daher ist $var
10 statt 15.
Im Gegenteil, JavaScript behandelt die Variable etwas anders, wenn sie an eine anonyme Funktion übergeben wird. Wir müssen hier nicht das Schlüsselwort use
verwenden, um die Variable an den Abschluss zu übergeben. Die Variable x
im zweiten Snippet wird aktualisiert, bevor der Abschluss aufgerufen wird, dann erhalten wir 26.
Beachten Sie, dass wir in PHP 7.4 eine Pfeilfunktion haben und dann nicht das Schlüsselwort use
verwenden müssen, um die Variable an die Funktion zu übergeben. Eine andere Möglichkeit, eine global
Variable innerhalb einer Funktion in PHP aufzurufen, besteht darin, das Schlüsselwort global
zu verwenden oder die integrierte GLOBAL-Variable $GLOBALS zu verwenden.
let x = { } ;
let y = { } ;
let z = x ;
console . log ( x == y ) ;
console . log ( x === y ) ;
console . log ( x == z ) ;
console . log ( x === z ) ;
Technisch gesehen haben x
und y
den gleichen Wert. Beides sind leere Objekte. Wir verwenden den Wert jedoch nicht zum Vergleichen von Objekten.
z
ist x
sind zwei Objekte, die auf dieselbe Speicherposition verweisen. In JavaScript werden Array und Objekt als reference
übergeben. x
und z
geben daher beim Vergleich „true“ zurück.
console . log ( "hello" ) ;
setTimeout ( ( ) => console . log ( "world" ) , 0 ) ;
console . log ( "hi" ) ;
Da die Funktion setTimeout() in der task queue
verbleibt, bevor sie zum stack,
werden zuerst „Hallo“ und „Hi“ ausgegeben, dann ist A falsch. Dies gilt auch für die Antworten C und D.
Unabhängig davon, wie viele Sekunden Sie für die Funktion setTimeout()
festlegen, wird sie nach dem synchronen Code ausgeführt. Wir erhalten also zuerst „Hallo“, da es zuerst in den Aufrufstapel eingefügt wird. Obwohl setTimeout()
dann in den Aufrufstapel eingefügt wird, wird es anschließend auf die Web-API (oder Node-API) verlagert und dann aufgerufen, wenn andere synchrone Codes gelöscht werden. Das heißt, wir bekommen dann „Hallo“ und schließlich „Welt“.
Also ist B die richtige Antwort.
Credit: @kaitoubg (voz) für Ihren Vorschlag bezüglich des timeout throttled
, durch den ich beschlossen habe, die Frage leicht zu ändern. Dadurch wird sichergestellt, dass die Leser nicht verwirrt werden, da der vorherige Code beim Testen in anderen Browsern oder Umgebungen möglicherweise andere Ergebnisse liefert. Der Hauptpunkt der Frage betrifft die Diskrepanz zwischen synchronem Code und asynchronem Code bei Verwendung von setTimeout.
.
String . prototype . lengthy = ( ) => {
console . log ( "hello" ) ;
} ;
let x = { name : "Vuong" } ;
delete x ;
x . name . lengthy ( ) ;
String.prototype.someThing = function () {}
ist die gängige Methode zum Definieren einer neuen integrierten Methode für String
. Dasselbe können wir mit Array
, Object
oder FunctionName
machen, wobei FunctionName die von uns selbst entworfene Funktion ist.
Es ist nicht schwer zu erkennen, dass "string".lengthy()
immer hello
zurückgibt. Der knifflige Teil liegt jedoch im delete object
, wo wir annehmen könnten, dass dieser Ausdruck das Objekt vollständig löscht. Dies ist nicht der Fall, da delete
nur zum Löschen der Eigenschaft des Objekts verwendet wird. Das Objekt wird nicht gelöscht. Dann bekommen wir hello
statt ReferenceError
.
Beachten Sie, dass wir ein globales Objekt haben, wenn wir ein Objekt ohne let, const
oder var
deklarieren. delete objectName
und dann true
zurückgeben. Andernfalls wird immer false
zurückgegeben.
let x = { } ;
x . __proto__ . hi = 10 ;
Object . prototype . hi = ++ x . hi ;
console . log ( x . hi + Object . keys ( x ) . length ) ;
Zuerst haben wir ein leeres Objekt x
, dann fügen wir mit x.__proto__.hi
eine weitere Eigenschaft hi
für x hinzu. Beachten Sie, dass dies äquivalent zu Object.prototype.hi = 10
ist und wir dem father
Object
die Eigenschaft hi
hinzufügen. Das bedeutet, dass jedes einzelne Objekt diese Eigenschaft erbt. Das hi
wird gemeinschaftlich genutzt. Angenommen, wir deklarieren jetzt ein neues Objekt wie let y = {}
, y
hat nun eine Eigenschaft hi
Object
vom father
geerbt wurde. Einfach ausgedrückt: x.__proto__ === Object.prototype
gibt true
zurück.
Dann überschreiben wir die Eigenschaft hi
mit einem neuen Wert 11. Zuletzt haben wir 11 + 1 = 12. x
hat eine Eigenschaft und x.hi
gibt 11 zurück.
Aktualisiert (27. Juli 2021). Wenn Sie Object.prototype.hi = 11;
statt Object.prototype.hi = ++x.hi;
Wie im obigen Code geschrieben, gibt Object.keys(x)
dann ein leeres Array zurück, da Object.keys(object)
nur die Eigenschaft des Objekts selbst zurückgibt, nicht die geerbten. Das bedeutet, dass das Endergebnis 11 statt 12 sein wird. Aus irgendeinem Grund ist der Code „Object.prototype.hi = ++x.hi;“ will create a property for the object
x` selbst und dann gibt uns `Object.keys(x)` das Array `["hi"]`.
Wenn Sie jedoch console.log(x.hasOwnProperty("hi"))
ausführen, wird immer noch false
zurückgegeben. Übrigens, wenn Sie absichtlich eine Eigenschaft für x hinzufügen, beispielsweise x.test = "testing"
, dann gibt console.log(x.hasOwnProperty("test"))
true
zurück.
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 } ) ) ;
Diese Frage untersucht, wie der delete
in JavaScript funktioniert. Kurz gesagt, es passiert nichts, wenn wir delete someObject
oder delete someArray
schreiben. Dennoch wird eine Eigenschaft eines Objekts vollständig gelöscht und entfernt, wenn etwas wie delete someObject.someProperty
geschrieben wird. Wenn wir im Fall eines Arrays delete someArray[keyNumber]
schreiben, wird nur der value
des index
entfernt, der index
bleibt erhalten und der neue value
wird jetzt auf undefined
gesetzt. Aus diesem Grund erhalten wir im ersten Codeausschnitt (die Länge) 4 Elemente wie im ursprünglichen Array, aber nur noch 3 Eigenschaften im übergebenen Objekt, wenn die Funktion object() aufgerufen wird, wie im zweiten Codeausschnitt.
Das dritte Snippet gibt uns 4, da das Deklarieren der Eigenschaft eines Objekts entweder auf null
oder undefined
die Eigenschaft nicht vollständig entfernt. Der Schlüssel ist intakt. Die Länge des Objekts ist also unveränderlich.
Für diejenigen, die mit PHP vertraut sind: Wir haben unset($someArray[index])
das das Array-Element, sowohl den Schlüssel als auch den Wert, entfernt. Wenn Sie das Array print_r
, sehen wir möglicherweise nicht den Schlüssel und den Wert, die nicht gesetzt wurden. Wenn wir jedoch (mithilfe von array_push($someArray, $someValue)
) ein neues Element in diesem Array verschieben, stellen wir möglicherweise fest, dass der vorherige Schlüssel weiterhin erhalten bleibt, aber kein Wert vorhanden ist und nicht angezeigt wird. Darüber sollten Sie sich im Klaren sein. Schauen Sie sich https://3v4l.org/7C3Nf an
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
und b
geben „false“ zurück, da sie auf unterschiedliche Speicherorte verweisen, obwohl die Werte gleich sind. Wenn Sie aus der PHP-Welt kommen, wird es offensichtlich „true“ zurückgeben, wenn wir entweder Wert oder Wert + Typ vergleichen. Schauen Sie es sich an: https://3v4l.org/IjaOs.
In JavaScript wird der Wert im Fall von array
und object
als Referenz übergeben. Daher ist d
im zweiten Fall die Kopie von c
, aber beide zeigen auf dieselbe Speicherposition. Alles, was sich in c
ändert, führt zu einer Änderung in d
. In PHP könnten wir $a = &$b;
, funktioniert auf ähnliche Weise.
Der dritte gibt uns einen Hinweis, ein Array in JavaScript mit der Methode slice()
zu kopieren. Jetzt haben wir f
, die Kopie von e
aber sie zeigen auf unterschiedliche Speicherorte und haben daher ein unterschiedliches „Leben“. Beim Vergleich erhalten wir dementsprechend false
.
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
) ;
}
} ) ( ) ;
Das Code-Snippet ist ziemlich knifflig, da es über mehrere verschiedene integrierte Methoden verfügt, mit denen Objekte in JavaScript
behandelt werden. Beispielsweise werden sowohl Object.keys
als auch Object.getOwnPropertyNames
verwendet, obwohl sie recht ähnlich sind, mit der Ausnahme, dass letzteres nicht aufzählbare Eigenschaften zurückgeben kann. Vielleicht möchten Sie einen Blick auf diese ausführlich geschriebene Referenz https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames werfen
Object.values
und Object.keys
geben den Eigenschaftswert bzw. den Eigenschaftsnamen des Objekts zurück. Das ist nichts Neues. object.hasOwnProperty('propertyName')
gibt einen boolean
zurück, der bestätigt, ob eine Eigenschaft vorhanden ist oder nicht.
Wir haben flag
true, weil Object.values(languages)[0][4].name
feature
zurückgibt, was auch der Name der Eigenschaft ist.
Dann haben wir 4 << 4 im if-else
-Fluss, der den bitweisen Wert zurückgibt, entsprechend 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 .