Мы доверяем 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. 4. 5, а не 3, 3, 3.
Такая ошибка дает мне ощущение static
переменной в мире 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
Получаем true в консоли. Сложнее всего то, что мы создаем объект из функции-конструктора Name, но НЕ ИСПОЛЬЗУЕМ new
клавиши. Это сделает переменную a
и получит значение «Вуонг». Помните, что на самом деле это свойство window
глобального объекта (в браузере) или global
в nodejs.
Затем мы получаем a.length
~ 5 и window.a.length
~ 5, которые возвращают 0. !0 возвращает true.
Представьте себе, что произойдет, когда мы создадим экземпляр me
с new
ключевой функцией. Это интересный запрос!
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 массив typeof возвращает «объект», а не «массив». Это совершенно странно, если вы переходите с PHP.
То есть теперь у нас есть длина строкового object
, которая возвращает 6. zy() просто возвращает длину строки «freetut» (7).
Имейте в виду, что функция x() (в форме function express
или anonymous function
(если вы используете PHP) возвращает -1 при вызове, а при преобразовании в bool с помощью Boolean(-1)
возвращает true вместо false. Примечание. что 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 (выражение функции с немедленным вызовом). Обратите внимание, что параметр x
функции js
фактически передается со значением 3.
Возвращаемое значение функции — y(s())), что означает вызов трех других функций y()
, s()
и j()
поскольку функция s()
возвращает j()
.
j() возвращает 3^3 = 27, так что s() возвращает 27.
y(s()) означает y(27), который возвращает 27*3 = 81.
Обратите внимание, что мы можем вызвать 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 (выражение немедленно вызываемой функции). Это означает, что нам не нужно его вызывать, но он будет выполнен автоматически при объявлении. Последовательность действий такова: муж() возвращает жену()/2, а жена() возвращает чаевые*2.
Мы могли бы подумать, что Tip = 100, потому что это глобальная переменная при объявлении с ключевым словом var
. Однако на самом деле он undefined
, поскольку у нас также есть var tip = 10
ВНУТРИ функции. Поскольку переменная tip
поднимается со значением по умолчанию undefined
, окончательным результатом будет D. Мы знаем, что undefined
возвращает NaN, когда мы пытаемся разделить на 2 или умножить на 2.
Если мы не объявим повторно 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 ) ;
Эта задача пересматривает функцию ES6, касающуюся spread operator ...
Оператор расширения весьма полезен для получения параметра в функции, для unite
или combine
объекта и массива в JavaScript. PHP также имеет эту функцию.
В переменной edu
мы используем ...js
(оператор расширения здесь), чтобы объединить оба объекта в один. Аналогично это работает и с массивом.
Затем мы объявляем еще одну переменную с именем newbie
. ВАЖНОЕ примечание: при объявлении переменной таким образом обе переменные указывают на ОДНУ и ОДНУ ПОЗИЦИЮ в памяти. Возможно, в PHP мы знали что-то вроде $a = &$b
, что позволяло обеим переменным работать одинаково. В этом случае мы могли знать о pass by reference
.
Тогда у нас есть 2, поскольку edu.language
удален. Оба объекта теперь имеют только два элемента.
Теперь пришло время подумать о копировании объекта в 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. Во второй операции она возвращает только 1, поскольку она подвергается 5%2
.
В третьей и четвертой функциях 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
. В противном случае он называется lambda
, если мы не используем ключевое слово use
. Вы можете проверить результат фрагмента здесь https://3v4l.org/PSeMY. closure
PHP принимает значение переменной только ДО того, как замыкание будет определено, независимо от того, где оно вызывается. Таким образом, $var
равен 10, а не 15.
Напротив, JavaScript обрабатывает переменную немного иначе, когда она передается анонимной функции. Нам не нужно использовать здесь ключевое слово use
для передачи переменной в замыкание. Переменная x
во втором фрагменте обновляется перед вызовом замыкания, тогда мы получаем 26.
Обратите внимание, что в PHP 7.4 у нас есть стрелочная функция, и нам не нужно использовать ключевое слово use
для передачи переменной в функцию. Другой способ вызвать global
переменную внутри функции в PHP — использовать ключевое слово 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
is x
— два объекта, ссылающиеся на одну и ту же позицию памяти. В JavaScript массив и объект передаются по reference
. Таким образом, x
и z
возвращают true при сравнении.
console . log ( "hello" ) ;
setTimeout ( ( ) => console . log ( "world" ) , 0 ) ;
console . log ( "hi" ) ;
Учитывая, что функция setTimeout() будет храниться в task queue
перед возвратом в stack,
сначала будут напечатаны «привет» и «привет», затем A будет неправильным. То же самое относится и к ответам C и D.
Независимо от того, сколько секунд вы установите для функции setTimeout()
, она будет выполняться после синхронного кода. Таким образом, мы сначала получим «привет», поскольку оно первым помещается в стек вызовов. Хотя setTimeout()
затем помещается в стек вызовов, впоследствии он будет выгружен в веб-API (или Node API), а затем будет вызван, когда другие синхронные коды будут очищены. Это означает, что затем мы получаем «привет» и, наконец, «мир».
Итак, Б – правильный ответ.
Кредит: @kaitubg (voz) за ваше предложение относительно timeout throttled
, которым я решил немного изменить вопрос. Это гарантирует, что читатели не запутаются, поскольку предыдущий код может дать разные результаты при тестировании в других браузерах или средах. Основная суть вопроса заключается в несоответствии синхронного кода и асинхронного кода при использовании 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
используется только для удаления свойства объекта. Он не удаляет объект. Тогда мы получаем hello
, а не ReferenceError
.
Обратите внимание: если мы объявим объект без 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
, затем мы добавляем еще одно свойство hi
для x с помощью x.__proto__.hi
. Обратите внимание, что это эквивалентно Object.prototype.hi = 10
, и мы добавляем к father
объекту Object
свойство hi
. Это означает, что каждый объект унаследует это свойство. Имущество hi
становится общим. Скажем, теперь мы объявляем новый объект, например let y = {}
, y
теперь имеет свойство hi
унаследованное от father
Object
. Проще говоря, x.__proto__ === Object.prototype
возвращает true
.
Затем мы перезаписываем свойство hi
новым значением 11. Последнее значение 11 + 1 = 12. У x
есть одно свойство, а x.hi
возвращает 11.
Обновлено (27 июля 2021 г.). Если вы напишете Object.prototype.hi = 11;
вместо Object.prototype.hi = ++x.hi;
как написано в приведенном выше коде, тогда Object.keys(x)
вернет пустой массив, поскольку Object.keys(object)
возвращает только свойство самого объекта, а не унаследованные. Это означает, что конечный результат будет 11, а не 12. По какой-то причине код ``Object.prototype.hi = ++x.hi; will create a property for the object
x`, а затем `Object.keys(x)` предоставит нам массив `["hi"]`.
Тем не менее, если вы запустите console.log(x.hasOwnProperty("hi"))
он всё равно вернет false
. Кстати, если вы намеренно добавляете свойство для x, например x.test = "testing"
, 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 } ) ) ;
В этом вопросе рассматривается, как оператор delete
работает в JavaScript. Короче говоря, он ничего не делает, когда мы пишем delete someObject
или delete someArray
. Тем не менее, он полностью удаляет и удаляет свойство объекта при написании чего-то вроде delete someObject.someProperty
. В случае с массивом, когда мы пишем delete someArray[keyNumber]
, он удаляет только value
index
, сохраняет index
нетронутым, а новому value
теперь присваивается значение undefined
. По этой причине в первом фрагменте кода мы получаем (длину) 4 элемента, как и в исходном массиве, но в объекте, передаваемом при вызове функции object(), остается только 3 свойства, как во втором фрагменте.
Третий фрагмент дает нам 4, поскольку объявление свойства объекта как null
, так и undefined
не приводит к полному удалению свойства. Ключ цел. Таким образом, длина объекта неизменна.
Для тех, кто знаком с 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;
, работая аналогичным образом.
Третий дает нам подсказку о том, как скопировать массив в JavaScript с помощью метода slice()
. Теперь у нас есть f
, который является копией e
, но они указывают на разные ячейки памяти, поэтому у них разная «жизнь». Соответственно, мы получаем 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
, подтверждающее, существует свойство или нет.
У нас есть flag
true, потому что Object.values(languages)[0][4].name
возвращает feature
, который также является именем свойства.
Тогда у нас есть 4 << 4 в потоке if-else
, который возвращает побитовое значение, эквивалентное 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 .