2008-09-23 2 views
27

Я прохожу через превосходный Advanced javascript tutorial Джона Ресига, и я не совсем понимаю, в чем разница между следующими вызовами: (обратите внимание, что «аргументы» являются встроенным javascript-словом и не совсем массив, следовательно, взлом с Array.slice вместо того, чтобы просто вызывающее arguments.slice)Разница между Array.slice и Array(). Slice

>>> arguments 
[3, 1, 2, 3] 
>>> Array.slice.call(arguments) 
3,1,2,3 0=3 1=1 2=2 3=3 
>>> Array.slice.call(arguments, 1) 
[] 
>>> Array().slice.call(arguments) 
3,1,2,3 0=3 1=1 2=2 3=3 
>>> Array().slice.call(arguments, 1) 
1,2,3 0=1 1=2 2=3 

в основном мое недоразумение сводится к разнице между Array.slice и Array(). срезом. В чем же разница между этими двумя и почему Array.slice.call ведет себя так, как ожидалось? (который возвращает все, кроме первого элемента списка аргументов).

ответ

38

Не совсем.

Смотрите, что происходит, когда вы звоните String.substring.call ("Foo", 1) и String() substring.call ("Foo", 2):.

>>> String.substring.call("foo", 1) 
"1" 

>>> String().substring.call("foo", 1) 
"oo" 

Array.slice является ни должным образом ссылаются на функцию среза, прикрепленную к прототипу Array, и функцию среза, прикрепленную к любому экземпляру экземпляра Array (например, Array() или []).

Тот факт, что Array.slice даже не является нулевым, является неправильной реализацией самого объекта (/ function/constructor). Попробуйте запустить эквивалентный код в IE, и вы получите сообщение об ошибке, что Array.slice имеет значение.

Именно поэтому Array.slice не ведет себя корректно (и не String.substring).

Proof (следующее что-то никогда не следует ожидать на основании определения среза() ... так же, как подстроку() выше):

>>> Array.slice.call([1,2], [3,4]) 
3,4 

Теперь, если вы правильно называть кусочек() на либо экземпляр объекта или Массив прототип, вы получите то, что вы ожидаете:

>>> Array.prototype.slice.call([4,5], 1) 
[5] 
>>> Array().slice.call([4,5], 1) 
[5] 

Больше доказательство ...

>>> Array.prototype.slice == Array().slice 
true 
>>> Array.slice == Array().slice 
false 
+0

Я не знаю, как это было в браузерах '08, но с начала 2013 года `String.substring.call` выдает TypeError в Chrome (так как конструктор` String` не имеет свойства `substring`) , – bfavaretto 2013-01-21 18:42:40

6

Array - это просто функция, хотя и специальная (используется для инициализации массивов). Array.slice - это ссылка на функцию slice() в прототипе Array. Его можно вызвать только для объекта массива, а не для самого конструктора (т. Е. Массива). Массив, кажется, ведет себя особенно, хотя, поскольку Array() возвращает пустой массив. Это, похоже, не работает для нестроенных функций конструктора (там вам нужно использовать новые). Так

Array().slice.call 

такого же, как

[].slice.call 
-1

Ну,

Глядя на http://www.devguru.com/Technologies/ecmascript/quickref/slice.html

Array(). Ломтик функция (конструктор) в классе массива, наклоняет использоваться как элемент данных. Если вы не хотите использовать '(), вам нужно будет вызвать его в массиве. т.е. - arguments.slice (1)

-1

Я предполагаю, что Array является прототипом, в то время как Array() является фактическим объектом массива. В зависимости от интерпретации JavaScript может работать прямой вызов метода прототипа встроенного типа объекта, или он может не работать. Я не верю, что спецификация говорит, что она должна работать, только потому, что вызов ее на экземпляр объекта работает.

0

Я считаю Array является типом и Array() является функцией конструктора.

Мессинг вокруг в FireBug:

>>> Array === Array() 
false 

>>> Array.constructor 
Function() 

>>> Array().constructor 
Array() 
1

Как можно вызвать вызов slice.call() в примерах, предоставляемых с учетом того, что параметр контекста не предоставляется? Использует ли slice собственный метод вызова, тем самым переопределяя метод вызова JavaScript? Методы вызова и применения принимают в качестве первого параметра объект для указания контекстного (этого) объекта для применения к вызову.