우리는 JS를 신뢰합니다. 학습하는 가장 좋은 방법은 구축/코딩 및 교육입니다. 나는 친구들이 JavaScript를 배울 수 있도록 도전 과제를 만들고 그 대가로 언어를 훨씬 더 깊은 수준으로 받아들이는 데 도움이 됩니다. 자유롭게 복제하고, 포크하고, 끌어오세요.
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
및 1, 2, 3
3, 3, 3
및 3, 4, 5
3, 3, 3
및 1, 2, 3
1, 2, 3
및 3, 3, 3
이 질문은 JavaScript에서 가장 혼란스러운 개념 중 하나인 클로저에 대해 다시 살펴봅니다. 클로저를 사용하면 stateful function
생성할 수 있으며 이러한 함수는 해당 범위 외부의 변수에 액세스할 수 있습니다. 간단히 말해서, 클로저는 global
변수(범위), father function
범위 및 its
범위에 접근할 수 있습니다.
여기에는 단 하나의 정답인 3, 3, 3과 3, 4, 5가 있습니다. 먼저 단순히 함수 a()
를 호출하기 때문입니다. 이는 일반 함수처럼 작동하며 소위 stateful
이라는 기능은 아직 본 적이 없습니다. 다음 코드에서는 변수 x
선언하고 함수 a(1)
의 값을 저장하므로 3, 3, 3이 아닌 3. 4. 5를 얻습니다.
이런 종류의 문제는 PHP 세계에서 static
변수라는 느낌을 줍니다.
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
우리는 콘솔에서 사실을 얻습니다. 까다로운 부분은 생성자 함수 Name에서 객체를 생성하지만 new
키워크를 사용하지 않는 경우입니다. 그러면 변수가 전역 a
가 되고 "Vuong" 값을 얻습니다. 이는 실제로 전역 객체 window
(브라우저에서)의 속성이거나 nodejs에서 global
이라는 것을 기억하세요.
그런 다음 0을 반환하는 a.length
~ 5 및 window.a.length
~ 5를 얻습니다. !0은 true를 반환합니다.
new
키워크로 인스턴스 me
생성하면 어떤 일이 일어날지 상상해 보세요. 흥미로운 질문이네요!
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
확산 연산자 ...x
함수의 매개변수를 배열 형식으로 얻는 데 도움이 될 수 있습니다. 그러나 Javascript에서 배열 유형은 "배열"이 아닌 "객체"를 반환합니다. PHP에서 왔다면 완전히 이상합니다.
즉, 이제 6을 반환하는 문자열 object
의 길이를 갖게 되었습니다. zy()는 단순히 문자열 'freetut'(7)의 길이를 반환합니다.
x() 함수( function express
또는 anonymous function
(PHP에서 오는 경우) 형식)는 호출 시 -1을 반환하고 Boolean(-1)
을 사용하여 bool로 변환하면 false 대신 true를 반환한다는 점에 유의하세요. Boolean(0)
은 false를 반환합니다.
( function js ( x ) {
const y = ( j ) => j * x ;
console . log ( y ( s ( ) ) ) ;
function s ( ) {
return j ( ) ;
}
function j ( ) {
return x ** x ;
}
} ) ( 3 ) ;
undefined
js()
함수는 호출하지 않고 자동으로 실행될 수 있으며 IIFE(Immediately Invoked Function Expression)로 알려져 있습니다. js
함수의 매개변수 x
실제로 값 3으로 전달됩니다.
함수의 반환 값은 y(s()))입니다. 이는 함수 s()
j()
반환하기 때문에 세 가지 다른 함수 y()
, s()
및 j()
를 호출한다는 의미입니다.
j()는 3^3 = 27을 반환하므로 s()는 27을 반환합니다.
y(s())는 27*3 = 81을 반환하는 y(27)을 의미합니다.
함수가 실제로 선언되기 전에 declare function
호출할 수 있지만 expression function
사용해서는 호출할 수 없습니다.
var tip = 100 ;
( function ( ) {
console . log ( "I have $" + husband ( ) ) ;
function wife ( ) {
return tip * 2 ;
}
function husband ( ) {
return wife ( ) / 2 ;
}
var tip = 10 ;
} ) ( ) ;
여기에는 IIFE(즉시 호출 함수 표현)가 있습니다. 이는 호출할 필요는 없지만 선언되면 자동으로 실행된다는 의미입니다. 흐름은 다음과 같습니다. husband()는 wife()/2를 반환하고 wife()는tip*2를 반환합니다.
var
키워드로 선언하면 전역 변수이기 때문에 팁 = 100이라고 생각할 수도 있습니다. 그러나 함수 내부에 var tip = 10
도 있으므로 실제로는 undefined
. 변수 tip
기본값 undefined
으로 끌어올려지기 때문에 최종 결과는 D가 됩니다. 우리는 2로 나누거나 2의 배수로 나누려고 할 때 undefined
NaN을 반환한다는 것을 알고 있습니다.
var tip = 10;
함수가 끝나면 우리는 확실히 B를 얻게 될 것입니다.
JS는 재미있죠?
const js = { language : "loosely type" , label : "difficult" } ;
const edu = { ... js , level : "PhD" } ;
const newbie = edu ;
delete edu . language ;
console . log ( Object . keys ( newbie ) . length ) ;
이 과제는 spread operator ...
스프레드 연산자는 함수에서 매개변수를 검색하고 JavaScript에서 객체와 배열을 unite
하거나 combine
데 매우 유용합니다. PHP에도 이 기능이 있습니다.
edu
변수에서 ...js
(여기서는 스프레드 연산자)를 사용하여 두 객체를 하나로 결합합니다. 배열과 동일한 방식으로 작동합니다.
그런 다음 newbie
라는 또 다른 변수를 선언합니다. 중요 참고 사항: 이와 같이 변수를 선언하면 두 변수 모두 메모리에서 동일한 위치를 가리킵니다. 우리는 PHP에서 두 변수가 동일한 방식으로 작동하도록 하는 $a = &$b
와 같은 것을 알고 있을 것입니다. 이 경우 pass by reference
에 대해 알고 있었을 수도 있습니다.
그러면 edu.language
삭제되어 2개가 됩니다. 이제 두 개체 모두 두 개의 요소만 갖습니다.
이제 JS에서 얕은 객체나 깊은 객체를 처리하는 방법에 대해 생각해 볼 때입니다.
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 ( ) ) ;
내장 메소드인 Object.assign(candidate, job)
은 candidate
와 job
두 객체를 하나의 객체로 병합합니다. 그런 다음 Object.keys
메소드는 객체의 key
수를 계산합니다.
get()
및 count()
두 메서드는 static
으로 정의되므로 Class.staticmethod()
구문을 사용하여 정적으로 호출해야 합니다. 그런 다음 최종 개체는 5개의 요소를 얻습니다.
var x = 1 ;
( ( ) => {
x += 1 ;
++ x ;
} ) ( ) ;
( ( y ) => {
x += y ;
x = x % y ;
} ) ( 2 ) ;
( ( ) => ( x += x ) ) ( ) ;
( ( ) => ( x *= x ) ) ( ) ;
console . log ( x ) ;
처음에 x
값 1로 선언되었습니다. 첫 번째 IIFE 함수에는 두 가지 작업이 있습니다. 처음에는 x
2가 되고 다음에는 3이 됩니다.
두 번째 IIFE 함수에서 x = x + y
이면 현재 값은 5입니다. 두 번째 연산에서는 5%2
겪으므로 1만 반환합니다.
세 번째와 네 번째 IIFE 함수에서는 2 x = x + x
와 4 x = x * x
얻습니다. 그것은 단순한 것 이상입니다.
$ 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 ) ) ;
이 질문은 클로저를 처리할 때 PHP와 JavaScript의 차이점을 보여줍니다. 첫 번째 스니펫에서는 use
키워드를 사용하여 클로저를 선언합니다. PHP의 클로저는 단순히 익명 함수이며 데이터는 use
키워드를 사용하여 함수에 전달됩니다. 그렇지 않고 use
키워드를 사용하지 않으면 lambda
라고 합니다. 여기(https://3v4l.org/PSeMY)에서 스니펫 결과를 확인할 수 있습니다. PHP closure
호출 위치에 상관없이 클로저가 정의되기 전에만 변수 값을 허용합니다. 따라서 $var
15가 아니라 10입니다.
반대로 JavaScript는 변수가 익명 함수에 전달될 때 약간 다르게 처리합니다. 클로저에 변수를 전달하기 위해 여기서 키워드 use
사용할 필요는 없습니다. 두 번째 스니펫의 변수 x
클로저가 호출되기 전에 업데이트되어 26을 얻습니다.
PHP 7.4에는 화살표 함수가 있으므로 함수에 변수를 전달하기 위해 키워드 use
사용할 필요가 없습니다. PHP 함수 내에서 global
변수를 호출하는 또 다른 방법은 global
키워드를 사용하거나 내장된 GLOBAL 변수 $GLOBALS를 사용하는 것입니다.
let x = { } ;
let y = { } ;
let z = x ;
console . log ( x == y ) ;
console . log ( x === y ) ;
console . log ( x == z ) ;
console . log ( x === z ) ;
기술적으로 x
와 y
동일한 값을 갖습니다. 둘 다 빈 개체입니다. 그러나 우리는 객체를 비교하기 위해 값을 사용하지 않습니다.
z
는 x
이며 동일한 메모리 위치를 참조하는 두 객체입니다. JavaScript에서는 배열과 객체가 reference
로 전달됩니다. 따라서 x
와 z
비교할 때 true를 반환합니다.
console . log ( "hello" ) ;
setTimeout ( ( ) => console . log ( "world" ) , 0 ) ;
console . log ( "hi" ) ;
setTimeout() 함수가 stack,
으로 다시 이동하기 전에 task queue
에 유지된다는 점을 고려하면 "hello" 및 "hi"가 먼저 인쇄되고 A는 올바르지 않습니다. C와 D의 답변도 마찬가지입니다.
setTimeout()
함수에 몇 초를 설정하더라도 동기 코드 이후에 실행됩니다. 따라서 "hello"는 호출 스택에 먼저 들어가므로 먼저 받게 됩니다. setTimeout()
호출 스택에 배치되지만 이후에는 웹 API(또는 Node API)로 오프로드되고 다른 동기 코드가 지워지면 호출됩니다. 이는 "hi"를 얻고 마지막으로 "world"를 얻는다는 의미입니다.
따라서 B가 정답입니다.
질문을 약간 변경하기로 결정한 timeout throttled
에 관한 귀하의 제안에 대한 크레딧: @kaitoubg(voz). 다른 브라우저나 환경에서 테스트할 때 이전 코드가 다른 결과를 가져올 수 있으므로 독자가 혼동하지 않도록 보장합니다. 질문의 주요 요점은 setTimeout.
.
String . prototype . lengthy = ( ) => {
console . log ( "hello" ) ;
} ;
let x = { name : "Vuong" } ;
delete x ;
x . name . lengthy ( ) ;
String.prototype.someThing = function () {}
String
에 대한 새로운 내장 메서드를 정의하는 일반적인 방법입니다. Array
, Object
또는 FunctionName
사용하여 동일한 작업을 수행할 수 있습니다. 여기서 FunctionName은 자체 설계한 함수입니다.
"string".lengthy()
항상 hello
반환한다는 사실을 깨닫는 것은 어렵지 않습니다. 그러나 까다로운 부분은 이 표현식이 객체를 완전히 삭제할 것이라고 생각할 수 있는 delete object
에 있습니다. delete
객체의 속성만 삭제하는 데 사용되므로 그렇지 않습니다. 객체를 삭제하지는 않습니다. 그러면 ReferenceError
대신 hello
표시됩니다.
let, const
, var
없이 객체를 선언하면 전역 객체가 됩니다. delete objectName
다음 true
반환합니다. 그렇지 않으면 항상 false
반환합니다.
let x = { } ;
x . __proto__ . hi = 10 ;
Object . prototype . hi = ++ x . hi ;
console . log ( x . hi + Object . keys ( x ) . length ) ;
먼저 빈 객체 x
가 있고 x.__proto__.hi
사용하여 x에 대한 또 다른 속성 hi
추가합니다. 이는 Object.prototype.hi = 10
과 동일하며 father
객체 Object
에 hi
속성을 추가합니다. 이는 모든 단일 개체가 이 속성을 상속한다는 의미입니다. hi
속성은 공유 속성이 됩니다. 이제 let y = {}
와 같은 새 객체를 선언한다고 가정해 보겠습니다. 이제 y
father
Object
에서 상속받은 속성 hi
갖습니다. 간단히 말해서 x.__proto__ === Object.prototype
true
반환합니다.
그런 다음 hi
속성을 새 값 11로 덮어씁니다. 마지막으로 11 + 1 = 12입니다. x
에는 하나의 속성이 있고 x.hi
11을 반환합니다.
업데이트됨(2021년 7월 27일). Object.prototype.hi = 11;
Object.prototype.hi = ++x.hi;
대신 위 코드에 작성된 대로 Object.keys(x)
빈 배열을 반환합니다. Object.keys(object)
상속된 속성이 아닌 객체 자체의 속성만 반환하기 때문입니다. 이는 최종 결과가 12가 아닌 11이 된다는 것을 의미합니다. 어떤 이유로 ``Object.prototype.hi = ++x.hi; will create a property for the object
다음 `Object.keys(x)`는 `["hi"]` 배열을 제공합니다.
그러나 console.log(x.hasOwnProperty("hi"))
실행하면 여전히 false
반환됩니다. 그런데 의도적으로 x.test = "testing"
과 같은 x 속성을 추가하면 console.log(x.hasOwnProperty("test"))
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 } ) ) ;
이 질문은 JavaScript에서 delete
연산자가 어떻게 작동하는지 조사합니다. 간단히 말해서, delete someObject
또는 delete someArray
작성할 때 아무 작업도 수행하지 않습니다. 그럼에도 불구하고 delete someObject.someProperty
와 같은 것을 작성할 때 객체의 속성을 완전히 삭제하고 제거합니다. 배열의 경우 delete someArray[keyNumber]
작성하면 index
value
제거되고 index
그대로 유지되며 이제 새 value
undefined
으로 설정됩니다. 이러한 이유로 첫 번째 코드 조각에서는 원래 배열에서와 같이 (길이) 4개의 요소를 얻지만 두 번째 조각에서와 같이 object() 함수가 호출될 때 전달된 객체에는 3개의 속성만 남습니다.
세 번째 스니펫은 객체의 속성을 null
또는 undefined
으로 선언해도 속성이 완전히 제거되지 않으므로 4를 제공합니다. 열쇠는 온전합니다. 따라서 객체의 길이는 변경할 수 없습니다.
PHP에 익숙한 사람들을 위해 키와 값 모두 배열 요소를 제거하는 unset($someArray[index])
있습니다. 배열을 print_r
할 때 설정되지 않은 키와 값이 표시되지 않을 수 있습니다. 그러나 해당 배열의 새 요소를 푸시( array_push($someArray, $someValue)
사용)하면 이전 키가 여전히 유지되지만 값이 없고 표시되지 않는 것을 볼 수 있습니다. 그것은 당신이 알아야 할 것입니다. 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
와 b
값이 동일하더라도 다른 메모리 위치를 가리키기 때문에 false를 반환합니다. PHP 세계에서 온 경우 값 또는 값 + 유형을 비교할 때 분명히 true를 반환합니다. 확인해보세요: https://3v4l.org/IjaOs.
JavaScript에서는 array
및 object
의 경우 값이 참조로 전달됩니다. 따라서 두 번째 경우에서 d
c
의 복사본이지만 둘 다 동일한 메모리 위치를 가리킵니다. c
의 모든 변경 사항은 d
의 변경으로 이어집니다. PHP에서는 $a = &$b;
, 비슷한 방식으로 작업합니다.
세 번째는 slice()
메서드를 사용하여 JavaScript에서 배열을 복사하는 힌트를 제공합니다. 이제 e
의 복사본인 f
있지만 서로 다른 메모리 위치를 가리키므로 서로 다른 "수명"을 갖습니다. 우리는 그것들을 비교할 때 그에 따라 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
) ;
}
} ) ( ) ;
코드 조각에는 JavaScript
에서 객체를 처리하는 몇 가지 서로 다른 내장 메서드가 있기 때문에 매우 까다롭습니다. 예를 들어, Object.keys
와 Object.getOwnPropertyNames
는 모두 열거할 수 없는 속성을 반환할 수 있다는 점을 제외하면 매우 유사하다고 생각되어도 사용됩니다. 철저하게 작성된 이 참조 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/getOwnPropertyNames를 살펴보는 것이 좋습니다.
Object.values
및 Object.keys
각각 객체의 속성 값과 속성 이름을 반환합니다. 그것은 새로운 것이 아닙니다. object.hasOwnProperty('propertyName')
속성이 존재하는지 여부를 확인하는 boolean
반환합니다.
Object.values(languages)[0][4].name
속성의 이름이기도 한 feature
반환하기 때문에 true flag
있습니다.
그런 다음 4*2^4
~ 4*16
~ 64에 해당하는 비트 단위 값을 반환하는 if-else
흐름에 4 << 4가 있습니다.
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 .