Во-первых, вам нужно иметь четкое представление о scope
и поведении ключевого слова this
в контексте scope
.
this
& amp; scope
:
there are two types of scope in javascript. They are :
1) Global Scope
2) Function Scope
вкратце, глобальная область относится к объекту window.Variables, объявленные в глобальной области, доступны из любого места. С другой стороны, область функций находится внутри функции .variable, объявленный внутри функции, не может быть доступен из внешнего мира в обычном режиме. this
ключевое слово в глобальной области относится к объекту window. Внутренняя функция this
также относится к объекту window.So this
всегда будет ссылаться на окно до тех пор, пока мы найдем способ манипулировать this
, чтобы указать контекст по собственному выбору.
--------------------------------------------------------------------------------
- -
- Global Scope -
- ( globally "this" refers to window object) -
- -
- function outer_function(callback){ -
- -
- // outer function scope -
- // inside outer function"this" keyword refers to window object - -
- callback() // "this" inside callback also refers window object -
- } -
- -
- function callback_function(){ -
- -
- // function to be passed as callback -
- -
- // here "THIS" refers to window object also -
- -
- } -
- -
- outer_function(callback_function) -
- // invoke with callback -
--------------------------------------------------------------------------------
Различные способы управления this
внутри функций обратного вызова:
Здесь У меня есть функция-конструктор, называемая Person. Он имеет свойство, называемое name
, и четыре метода, называемые sayNameVersion1
, sayNameVersion2
, sayNameVersion3
, sayNameVersion4
. Все четыре из них имеют одну конкретную задачу. Заберите обратный вызов и вызовите его. Обратный вызов имеет конкретную задачу, которая заключается в регистрации свойства имени экземпляра функции конструктора Person.
function Person(name){
this.name = name
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
this.sayNameVersion3 = function(callback){
callback.call(this)
}
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
}
function niceCallback(){
// function to be used as callback
var parentObject = this
console.log(parentObject)
}
Теперь давайте создадим экземпляр из конструктора person и вызывать разные версии sayNameVersionX
(X относится к 1,2,3,4) методу с niceCallback
, чтобы увидеть, как много способов управления this
внутри обратного вызова ссылаться на person
.
var p1 = new Person('zami') // create an instance of Person constructor
Что нужно сделать, это создать новую функцию с ключевым словом this
, установленным на предоставленное значение.
sayNameVersion1
и sayNameVersion2
используют bind для управления this
функции обратного вызова.
this.sayNameVersion1 = function(callback){
callback.bind(this)()
}
this.sayNameVersion2 = function(callback){
callback()
}
сначала связывают this
с обратным вызовом внутри самого метода. для второго обратного вызова передается связанный с ним объект.
p1.sayNameVersion1(niceCallback) // pass simply the callback and bind happens inside the sayNameVersion1 method
p1.sayNameVersion2(niceCallback.bind(p1)) // uses bind before passing callback
first argument
в call
используется как функция this
внутри функции, которая вызывается с call
, прикрепленной к ней.
sayNameVersion3
использует call
для управления this
], чтобы ссылаться на созданный нами объект person, а не на объект окна.
this.sayNameVersion3 = function(callback){
callback.call(this)
}
и он называется следующим:
p1.sayNameVersion3(niceCallback)
Как и в call
, первый аргумент apply
относится к объекту, который будет обозначен ключевым словом this
.
sayNameVersion4
использует apply
для манипулирования this
для обращения к объекту человека
this.sayNameVersion4 = function(callback){
callback.apply(this)
}
, и он называется следующим. Просто передается обратный вызов,
p1.sayNameVersion4(niceCallback)
Я немного изменил код, который я написал некоторое время назад:
@echo off
setlocal EnableDelayedExpansion
rem total number of random numbers:
set /A "RND_TOTAL=8"
rem range for random numbers (minimum, maximum):
set /A "RND_MIN=1, RND_MAX=10"
set /A "range=RND_MAX-RND_MIN+1"
rem Create an input list with all numbers in given range
set "input="
for /L %%i in (%RND_MIN%,1,%RND_MAX%) do (
set "input=!input! %%i"
)
set "input=%input% "
echo IN: [%input%]
rem Extract RND_TOTAL elements from input list in random order
set "output="
for /L %%i in (%RND_TOTAL%,-1,1) do (
set /A "randIndex=(!random!*range)/32768+1, range-=1"
call :MoveInputToOutput !randIndex!
)
echo OUT: [%output%]
goto :EOF
:MoveInputToOutput randIndex
for /F "tokens=%1" %%n in ("%input%") do (
set output=%output% %%n
set input=!input: %%n = !
)
exit /B
Пример вывода:
> test
IN: [ 1 2 3 4 5 6 7 8 9 10 ]
OUT: [ 8 7 9 3 1 4 5 2]
> test
IN: [ 1 2 3 4 5 6 7 8 9 10 ]
OUT: [ 9 2 10 6 4 8 5 1]
> test
IN: [ 1 2 3 4 5 6 7 8 9 10 ]
OUT: [ 1 2 4 3 8 5 7 9]
Извините, но я не понимаю, что %RND_INTER%
значение используется для ...
EDIT: новая версия, которая использует значение %RND_INTER%
и не имеет ограничения на количество генерируемых случайных чисел.
@echo off
setlocal EnableDelayedExpansion
rem total number of random numbers:
set /A "RND_TOTAL=8"
rem range for random numbers (minimum, maximum, interval):
set /A "RND_MIN=1, RND_MAX=10, RND_INTER=1"
rem Create an input vector with all numbers in given range
set "n=0"
for /L %%i in (%RND_MIN%,%RND_INTER%,%RND_MAX%) do (
set /A n+=1
set "in[!n!]=%%i"
)
echo Input:
set in[
echo/
rem Extract RND_TOTAL elements from input vector in random order
for /L %%i in (1,1,%RND_TOTAL%) do (
set /A "randIndex=(!random!*n)/32768+1"
set /A "out[%%i]=in[!randIndex!], in[!randIndex!]=in[!n!], n-=1"
)
echo Output:
set out[
Несмотря на то, что вы, ребята, выложили действительно отличные решения, у меня нет сердца, чтобы просто сдаться, и поэтому мне пришлось попробовать его самостоятельно, чтобы найти лучший код, который я разместил в вопросе; здесь мы идем ...
Основная идея состоит в том, чтобы создать таблицу, состоящую из двух столбцов, где первая содержит случайные числа с дубликатами, а вторая содержит индексы, которые составляют все возможные случайные числа. Следующим шагом будет сортировка этой таблицы по первому столбцу. Наконец, вам нужно выбрать значения из второго столбца из числа строк, в которых вам нужны случайные числа (в моем подходе я использую последние строки). Все полученные номера уникальны, так как второй столбец не содержит дубликатов. Вот пример, если нам нужны 8
случайные числа из 1,2,3,4,5,6,7,8,9,10
:
blockquote>generated sorted returned table table numbers -------------------------------- 1,1 1,1 - 9,2 1,6 - 8,3 10,8 8 3,4 3,4 4 9,5 4,7 7 1,6 5,9 9 4,7 8,10 10 10,8 8,3 3 5,9 9,2 2 8,10 9,5 5
Как вы можете видеть, нет дублирующихся чисел. Большим преимуществом этого метода является то, что вычисление случайных чисел не нужно повторять, если тот же уже был использован. Недостатком является то, что полная таблица должна быть создана даже в том случае, если из огромного пула возможных чисел требуется только несколько уникальных случайных чисел.
Я должен признать, что этот метод не является моей идеей, но, к сожалению, я не знаю, кому это зачисляется ...
Вот мой код, содержащий некоторые пояснительные замечания:
@echo off setlocal EnableExtensions EnableDelayedExpansion rem total number of random numbers, duplicate flag (`0` means no duplicates): set /A "RND_TOTAL=8, FLAG_DUP=0" rem range for random numbers (minimum, maximum, interval): set /A "RND_MIN=1, RND_MAX=10, RND_INTER=1" rem write table-like data to temporary file: > "%~n0.tmp" ( rem loop through all possible random numbers: for /L %%I in (%RND_MIN%,%RND_INTER%,%RND_MAX%) do ( rem compute a random number: set /A "RND_NUM=!RANDOM!%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN" if %FLAG_DUP% EQU 0 ( rem duplicates denied, so build row with random number as first column: echo !RND_NUM!,%%I ) else ( rem duplicates allowed, so build row with loop counter as first column: echo %%I,!RND_NUM! ) ) ) rem determine how many items of the table need to be skipped to get total number: set /A "SKIP=(RND_MAX-RND_MIN)/RND_INTER+1, SKIP-=RND_TOTAL" if %SKIP% GTR 0 ( set "SKIP=skip=%SKIP% " ) else ( set "SKIP=" ) rem read table-like data from temporary file: set /A "RND_COUNT=0" < "%~n0.tmp" ( rem sort rows (lines) of table-like data alphabetically, enumerate them: for /F "%SKIP%tokens=2 delims=," %%N in ('sort') do ( set /A "RND_COUNT+=1" rem store and return random number: set /A "RND_NUM[!RND_COUNT!]=%%N" echo %%N ) ) rem clean up temporary file: del /Q "%~n0.tmp" endlocal exit /B
В этом скрипте вышеописанные табличные данные хранятся во временном файле, который затем передается команде
sort
, которая выполняет сортировку по алфавиту.Полученная случайная последовательность выводится на консоль и сохраняется в array-like variables
RND_NUM[1:8]
(который доступен только до тех пор, пока командаendlocal
не будет выполнена).
Обновление:
Исходя из того, что
set
также может сортироваться и что описанная выше таблица также может быть отражена в именах переменных окружения в стиле, подобном двумерному массиву (здесь я использовалRND_NUM[_,_]
), следующий скрипт больше не использует временную файл. случайная последовательность снова выводится на консоль и также сохраняется в 1D-массивеRND_NUM[1:8]
).Но прежде чем мы перейдем к скрипту, я хочу показать вам 2D-массив, который представляет упомянутый таблицу с теми же данными образца, что и выше (обратите внимание, что значения переменных совершенно неактуальны):
blockquote>generated sorted returned 2D-array 2D-array numbers ------------------------------------------------ RND_NUM[1,1] RND_NUM[1,1] - RND_NUM[9,2] RND_NUM[1,6] - RND_NUM[8,3] RND_NUM[10,8] 8 RND_NUM[3,4] RND_NUM[3,4] 4 RND_NUM[9,5] RND_NUM[4,7] 7 RND_NUM[1,6] RND_NUM[5,9] 9 RND_NUM[4,7] RND_NUM[8,10] 10 RND_NUM[10,8] RND_NUM[8,3] 3 RND_NUM[5,9] RND_NUM[9,2] 2 RND_NUM[8,10] RND_NUM[9,5] 5
Вот код (включая некоторые пояснительные замечания):
@echo off setlocal EnableExtensions EnableDelayedExpansion rem total number of random numbers, duplicate flag (`0` means no duplicates): set /A "RND_TOTAL=8, FLAG_DUP=0" rem range for random numbers (minimum, maximum, interval): set /A "RND_MIN=1, RND_MAX=10, RND_INTER=1" rem clean up all variables named `RND_NUM*` (optionally): call :CLEANUP1 rem loop through all possible random numbers: for /L %%I in (%RND_MIN%,%RND_INTER%,%RND_MAX%) do ( rem compute a random number: set /A "RND_INDEX=!RANDOM!%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN" if %FLAG_DUP% EQU 0 ( rem duplicates denied, so build 2D-array with random number as first index: set "RND_NUM[!RND_INDEX!,%%I]=#" ) else ( rem duplicates allowed, so build 2D-array with loop counter as first index: set "RND_NUM[%%I,!RND_INDEX!]=#" ) ) rem determine how many items of the 2D-array need to be skipped to get total number: set /A "SKIP=(RND_MAX-RND_MIN)/RND_INTER+1-RND_TOTAL" if %SKIP% GTR 0 ( set "SKIP=skip=%SKIP% " ) else ( set "SKIP=" ) rem let `set` output all `RND_NUM*` variables sorted alphabetically, enumerate them: set /A "RND_COUNT=0" for /F "%SKIP%tokens=3 delims=[,]" %%I in ('set "RND_NUM"') do ( set /A "RND_COUNT+=1" rem store and return random number: set "RND_NUM[!RND_COUNT!]=%%I" echo %%I ) rem clean up all 2D-array variables named `RND_NUM*,*` (optionally): call :CLEANUP2 endlocal exit /B :CLEANUP1 for /F "tokens=1 delims==" %%I in ('2^> nul set "RND_NUM"') do ( set "%%I=" ) exit /B :CLEANUP2 for /F "tokens=1,2,3 delims=,=" %%I in ('set "RND_NUM"') do ( if not "%%K"=="" ( set "%%I,%%J=" ) ) exit /B
Процедуры очистки
:CLEANUP1
и:CLEANUP2
считаются необязательными и просто удаляют любые переменные, имена которых начинаются сRND_NUM
(см.:CLEANUP1
) в начале и имена которых содержат,
(что верно для 2D-массива, но не для 1D-массива, см.:CLEANUP2
) в конце.
Исходное решение Aacini эффективно, однако оно может поддерживать максимум 31 возможное значение, потому что FOR / F не может читать более 31 токенов. EDIT - его второе решение устранило ограничение.
Ниже приведено аналогичное понятие, которое использует постоянную ширину для чисел в списке. Это позволяет мне легко использовать операции подстроки для извлечения случайно выбранных значений и для удаления каждого значения из списка.
Как написано, это решение поддерживает значения от 0 до 9999 с максимальным количеством возможных значения & lt; = 1354.
Я использовал очень похожую стратегию для управления случайным размещением продуктов в моей игре SNAKE.BAT . Мне нужно было отслеживать все пустые места в игровом поле и случайным образом выбирать новое расположение продуктов из этого списка.
@echo off
setlocal enableDelayedExpansion
:: This script has the following limitations:
:: RND_MIN >= 0
:: RND_MAX <= 9999
:: ((RND_MAX - RND_MIN + 1) / RND_INTER) <= 1354
::
set "RND_MIN=1"
set "RND_MAX=10"
set "RND_INTER=1"
set "RND_TOTAL=8"
set /a cnt=(RND_MAX - RND_MIN + 1) / RND_INTER
:: Define a string containing a space delimited list of all possible values,
:: with each value having 10000 added
set "pool="
set /a "beg=RND_MIN+10000, end=RND_MAX+10000, cnt=(RND_MAX-RND_MIN+1)/RND_INTER"
for /l %%N in (%beg% %RND_INTER% %end%) do set "pool=!pool!%%N "
:: Build the randomly sequenced array of numbers
for /l %%N in (1 1 %RND_TOTAL%) do (
%= Randomly select a value from the pool of all possible values =%
%= and compute the index within the string, as well as the index =%
%= of the next value =%
set /a "loc=(!random!%%cnt)*6, next=loc+6"
%= Transfer the index values to FOR variables =%
for %%A in (!loc!) do for %%B in (!next!) do (
%= Assign the selected value to the output array =%
set /a "RND_NUM[%%N]=!pool:~%%A,5!-10000"
%= Remove the value from the pool =%
set "pool=!pool:~0,%%A!!pool:~%%B!"
set /a cnt-=1
)
)
:: Display the results
for /l %%N in (1 1 %RND_TOTAL%) do echo !RND_NUM[%%N]!
замените
for /L %%I in (1,1,%RND_TOTAL%) do (
rem compute a random number:
set /A "RND_NUM[%%I]=!RANDOM!%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN"
echo !RND_NUM[%%I]!
)
на
for /L %%I in (%rnd_min%,1,%RND_max%) do set "rnd_num{%%I}="
set /a rnd_count=rnd_total
:rnd_loop
rem compute a random number:
set /A "RND_selection=%RANDOM%%%((RND_MAX-RND_MIN)/RND_INTER+1)*RND_INTER+RND_MIN"
if not defined rnd_num{%rnd_selection%} (
SET "rnd_num{%rnd_selection%}=Y"
set /a rnd_num[%count%]=rnd_selection
echo %rnd_selection%
set /a rnd_count-=1
)
if %rnd_count% neq 0 goto rnd_loop
Каждый раз, когда выбор сделан, rnd_num{selectionmade}
установлен на Y
, поэтому, если он выбран снова, это и запись / выход / счет-1-меньше пропускается.
RND_INTER
определяет интервал, т. е. размер шага в данном диапазоне; например,RND_MIN=0
,RND_MAX=15
,RND_INTER=3
, тогда случайная последовательность может содержать0 3 6 9 12 15
... – aschipfl 22 December 2015 в 10:04RND_INTER
– Aacini 22 December 2015 в 19:56SET /A
командах ... – Aacini 22 December 2015 в 20:01