Comments 37
полезная вещь, буду пользоваться. спасибо!
-1
Array.prototype.slice.call
можно вызывать и без 0:Array.prototype.slice.call(arguments);
+3
Вот этот код дефолтных значений аргументов:
Можно написать гораздо проще (:
function (foo, bar) {
if (typeof foo === 'undefined') foo = 30;
if (typeof bar === 'undefined') bar = 'test';
console.log(foo, bar);
}
Можно написать гораздо проще (:
function (foo, bar) {
foo = foo || 30;
bar = bar || 'test';
console.log(foo, bar);
}
+6
К сожалению, из-за бага в трёх популярных браузерах(IE, Fx, Opera) я не смог добиться желаемого эффекта
О каком баге идет речь? По-моему, наоборот упомянутые браузеры более строго соответствуют спецификациям ECMA.
function test(a, b) {
arguments[0] = 100;
arguments[1] = 101;
console.log(a,b);
}
test(1,2); // => 100, 101
test(1); // => 100, undefined
Потому как динамическая связь устанавливается только для реально переданных аругментов:
(...) named data properties of an arguments object whose numeric name values are less than the number of formal parameters of the corresponding function object initially share their values with the corresponding argument bindings in the function’s execution context. This means that changing the property changes the corresponding value of the argument binding and vice-versa. (...)
До этой фразы идет подробное описание как строить этот объект «arguments» — формальные аргументы не переданные фактически в «arguments» не попадают.
+2
Да, увидел в посте ссылку на баг в файерфоксе. Во-первых, он давно уже пофиксан, а во-вторых, он совершенно не имеет отношения к вашему коду.
0
Я рад, что затеяли это обсуждение, очень хотел бы определится, кто таки неправ из браузеров.
На самом деле я спецификацию читал и, признаюсь, немного в ней запутался, но позвольте проясню.
Если вы не против, будем обсуждать перевод.
У функции есть аргументы формальные и актуальные. Если создавать функцию через конструктор:
То формальные аргументы — это «a» и «b». (и они не зависят от того, как функцию вызывали):
Я сходу не нашел такое же определение для создания функции не-через-конструктор, но, можно логически предположить, что оно не отличается. Значит, формальные аргументы — это аргументы, объявлены в загоовку функции. Теперь идем дальше:
Попробую написать псевдокод:
То есть, согласно спецификации, количество переданных аргументов не должно учитываться при линковании формальных параметров и свойств arguments.
Так я понял этот момент. Поправьте меня, если где-то ошибся.
Ссылку на баг дал не просто так. На mdc написано:
Согласен, баг другой, раньше, я так понял не менялось даже значение arguments[i], но в 4 часа ночи они показались очень похожими)
На самом деле я спецификацию читал и, признаюсь, немного в ней запутался, но позвольте проясню.
Если вы не против, будем обсуждать перевод.
У функции есть аргументы формальные и актуальные. Если создавать функцию через конструктор:
new Function('a', 'b', 'return a+b');
То формальные аргументы — это «a» и «b». (и они не зависят от того, как функцию вызывали):
Если более чем один параметр передаётся конструктору Function, все параметры кроме последнего преобразовываются в строки и конкатенируются вместе с использованием запятых в качестве разделителя. Результирующая строка интерпретируется как СписокФормальныхАргументов для ТелаФункции, определённого последним параметром.
Я сходу не нашел такое же определение для создания функции не-через-конструктор, но, можно логически предположить, что оно не отличается. Значит, формальные аргументы — это аргументы, объявлены в загоовку функции. Теперь идем дальше:
Для каждого неотрицательного числа arg, меньшего значения свойства length создаётся свойство с именем ToString(arg) и атрибутом { DontEnum }. Начальным значением этого свойства является реальное значение соответствующего аргумента, переданное при вызове. Первое реальное значение аргумента соответствует arg = 0, второе — arg = 1 и так далее. В том случае, когда arg меньше количества формальных параметров объекта Function, значение свойства является общим с соответствующим свойством объекта активации. Это означает, что изменение данного свойства изменяет соответствующее значение свойства у объекта активации и наоборот.
Попробую написать псевдокод:
for (arg = 0; arg < func.length; arg++) {
link(arguments[i], formalParameters[i]);
}
То есть, согласно спецификации, количество переданных аргументов не должно учитываться при линковании формальных параметров и свойств arguments.
Так я понял этот момент. Поправьте меня, если где-то ошибся.
Ссылку на баг дал не просто так. На mdc написано:
Note: The SpiderMonkey JavaScript engine has a bug in which arguments[n] cannot be set if n is greater than the number of formal or actual parameters. This has been fixed in the engine for JavaScript 1.6.
Согласен, баг другой, раньше, я так понял не менялось даже значение arguments[i], но в 4 часа ночи они показались очень похожими)
0
Согласен. Вроде, согласно ES5 оно должно считаться от аргументов.
Просто любопытно, как считаете, согласно ES3 — я все правильно понял?
Просто любопытно, как считаете, согласно ES3 — я все правильно понял?
0
Понял, в чем ваше заблуждение:
Здесь имеется ввиду свойство length созданное на предыдущем шаге. Т.е. не свойство функции, а свойство только что созданного оьъекта arguments. В ES3 описание просто немного более расплывчатое, но, по-моему, все равно вполне однозначное.
Для каждого неотрицательного числа arg, меньшего значения свойства length создаётся свойство с именем (...)
Здесь имеется ввиду свойство length созданное на предыдущем шаге. Т.е. не свойство функции, а свойство только что созданного оьъекта arguments. В ES3 описание просто немного более расплывчатое, но, по-моему, все равно вполне однозначное.
0
Точно, вы правы:
Создаётся свойство с именем length и атрибутами { DontEnum }. Начальным значением этого свойства является число реальных значений аргументов, переданное при вызове.
0
Описание семантики объекта
В Хроме помимо упоминавшегося бага, был еще баг с удалением индексов
Так же, учтите, что в strict-ES5 аксессор для индексов
И, касательно Harmony (aka ES6 или ES.next)
arguments
в ES5/non-strict ES5 JS кодом: gist.github.com/539974В Хроме помимо упоминавшегося бага, был еще баг с удалением индексов
arguments
.Так же, учтите, что в strict-ES5 аксессор для индексов
arguments
больше не создается (т.е. обычные статические копии формальных параметров).И, касательно Harmony (aka ES6 или ES.next)
arguments
вообще будет удален и заменен на rest
— полноценный массив. +3
Да, вы правы — баг именно в Chrome :)
0
По-моему, этот фукнционал уместнее расположить в прототипе фукнции.
Чтобы типа
Чтобы типа
var myFunc = function(foor, bar){ console.log(arguments); }.types(Foo, Bar).cast(Foo, Bar).allRequired();
+1
А
Проблема этого подхода в том, что при относительно больших функциях не видно, что происходит с аргументами. Если изучать верх функции, можно пропустить, скажем, кастинг или дефолтные значения.
allRequired
как сделать, тем более ему передастся функция, которая требует 0 аргументов?)Проблема этого подхода в том, что при относительно больших функциях не видно, что происходит с аргументами. Если изучать верх функции, можно пропустить, скажем, кастинг или дефолтные значения.
0
Function.prototype.allRequired = function(){
var f = this, validLength = f.length;
return function(){
if (arguments.length >= validLength)
return f.call(this, arguments);
else
throw new Error('oh Shit..');
}
};
Или я вопрос не правильно понял?
0
только там не .call, а .apply.
0
(function () {
// code
}.cast(Number).allRequired());
Function.prototype.cast = function (types) {
var fn = this;
return function () { // cast inner function
// casting arguments
return fn.call(this, arguments);
};
};
Function.prototype.allRequired = function () {
var fn = this; // оно ссылается не на нужную функцию, а на cast inner function
return function () {
}
};
0
Хотя, возможно, можно делать как-то так:
Function.prototype.cast = function (types) {
var fn = this;
var result = function () { // cast inner function
// casting arguments
return fn.call(this, arguments);
};
result.length = fn.length;
return result;
};
0
Неа, так не работает.
Если только делать
в каждой обертке.
Если только делать
result._length = fn._length || fn.length;
в каждой обертке.
0
Вот еще придумался вариант с сохранением нативного length: gist.github.com/934203
Я его не проверял, но вроде должен быть рабочий.
Я его не проверял, но вроде должен быть рабочий.
0
лучше враппер использовать — тогда можно в зависимости от типов и числа параметров разные функции вызывать, а также проверять результат исполнения функции
var find= Types
( HTMLElement
, [ String ]
, fucntion( id ){ return document.getElementById( id ) }
)
var check= Types
( HTMLElement
, [ HTMLElement ]
, fucntion( elem ){ elem }
)
var $= Poly( find, check )
var find= Types
( HTMLElement
, [ String ]
, fucntion( id ){ return document.getElementById( id ) }
)
var check= Types
( HTMLElement
, [ HTMLElement ]
, fucntion( elem ){ elem }
)
var $= Poly( find, check )
0
Часто, когда необходимы значения по умолчанию — в функцию передается объект.
Для такого случая тоже можно написать аналог вашей функции, устанавливающей значение по умолчанию — и у такого подхода есть свои очевидные преимущества.
function test(options)
{
if(options.foo===default)options.foo=30;
if(options.bar===default)options.bar='test';
console.log(options.foo,options.bar);
}
Для такого случая тоже можно написать аналог вашей функции, устанавливающей значение по умолчанию — и у такого подхода есть свои очевидные преимущества.
+1
В strict mode такое работать уже не будет, т.к. объект arguments не будет иметь связи с формальными параметрами, соответственно даже переданный аргумент нельзя изменить.
+6
Чтобы использовать обертку надо привыкнуть к ней, внедрить, научить других — все как правило очень долго. Мне обычный подход милее и он не менее нагляднее, да и если ещё снабдить код хорошим JSdoc'ом с описанными дефалтными значениями, который понимает любой современный IDE, то будет совсем хорошо (улучшу немного код omfg):
Ну и не забываем, что грядет
/**
* Pewpew
*
* @param {Object} [foo]
* @param {Mixed} [foo.smth]
* @param {Boolean} [bar=true]
* @param {String} [baz='pewpew']
* @param {Boolean} [bar=false]
*
* @returns {Mixed}
*/
function pewpew(foo, bar, baz, qqq) {
foo = foo || {}; // default empty object
bar = bar || bar == null; // default true (можно не использовать typeof bar)
baz = baz || 'pewpew'; // default some string
qqq = qqq || false; // default false
if (foo.smth) {
do();
}
}
Ну и не забываем, что грядет
"strict mode"
+2
Добрый день, подскажите где можно прочитать про strict mode на русском и что это вообще?
+2
Здесь немного есть. На русском действительно немного информации.
На английском статья на developer.mozilla.org
На английском статья на developer.mozilla.org
+1
По ссылке можно увидеть в каких случаях произойдет ошибка, на русском не встречал описания про strict mode, лучше всего заглянуть в раздел C спецификации ECMAScript5
0
«strict mode» — это да.
подход такой — не совсем правильный, что делать, если я хочу в качестве строки
Хотя, конечно, можно писать так:
А в таком коде уже было бы красиво:
Хотя, в целом, с аргументами согласен.
подход такой — не совсем правильный, что делать, если я хочу в качестве строки
baz
передать пустую строку?Хотя, конечно, можно писать так:
/**
* Pewpew
*
* @param {Object} [foo]
* @param {Mixed} [foo.smth]
* @param {Boolean} [bar=true]
* @param {String} [baz='pewpew']
* @param {Boolean} [bar=false]
*
* @returns {Mixed}
*/
function pewpew(foo, bar, baz, qqq) {
foo = foo != null ? foo : {}; // default empty object
bar = bar != null ? bar : true; // default true
baz = baz != null ? baz : 'pewpew'; // default some string
qqq = qqq != null ? qqq : false; // default false
if (foo.smth) {
do();
}
}
А в таком коде уже было бы красиво:
/**
* Pewpew
*
* @param {Object} [foo]
* @param {Mixed} [foo.smth]
* @param {Boolean} [bar=true]
* @param {String} [baz='pewpew']
* @param {Boolean} [bar=false]
*
* @returns {Mixed}
*/
function pewpew(foo, bar, baz, qqq) {
Args(arguments).defaults({}, true, 'pewpew', false)
if (foo.smth) {
do();
}
}
Хотя, в целом, с аргументами согласен.
+1
Only those users with full accounts are able to leave comments. Log in, please.
Магия JavaScript: arguments