Можно ли узнать имена входящих аргументов функции?
Можно ли узнать, что в функцию
function(foo,bar){
...
}
переданы аргументы 'foo', 'bar'? |
PrototypeJs:
Function.prototype.argumentNames = function() {
var names = this.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
.replace(/\s+/g, '').split(',');
return names.length == 1 && !names[0] ? [] : names;
};
|
и что, действительно бывает нужно такое выяснять?
|
Цитата:
function valera(x, y, z) {
defaultArgs(arguments, {y: 5, z: 10});
...
}
C методом, который предложил Riim это достаточно просто. Еще раз спасибо. |
советую подумать, почему так никто не делает... и, если будем развивать тему, приведи какой-нибудь конкретный пример
|
Цитата:
по-моему,так проще!
function valera(x, y, z) {
y=y || 5, z = z || 10;
...
// или так
y = typeof y === 'undefined' ? 5 : y ;
z = typeof z === 'undefined' ? 10 : z ;
}
|
x-yuri, melky, так красивее.
Цитата:
|
FINoM,
Цитата:
Тем более что вам это даст, имена переменных? ну передали вы в функцию defaultArgs ряд arguments и хэш имя>значение, в этой функции вы будете изменять arguments, но имена-то зачем, ведь в arguments значения по Number индексу хранятся, можно как нибудь так defaultArgs(arguments, 5, 6, 7), внутри первый_аргумент[0] = arguments[1] и так до конца arguments, хотя все равно не понятно зачем это |
Цитата:
|
а почему вот так нельзя
function defaultArgs(/* arguments */){
var len = arguments.length - 1;
for(var i = 0; i < len; i ++){
arguments[0][i] = arguments[i + 1];
}
}
function valera(x, y, z){
defaultArgs(arguments, 5,6,7);
/* code */
}
Потому что не красиво? |
Чем бы программист не страдал главное что бы пальцы были прямые...
|
Цитата:
Цитата:
Цитата:
есть 2 способа указать значения по умолчанию: 1) arg || '...', 2) options = options || {'option-1': '...'} |
Цитата:
Цитата:
да и разницы нет,как писать и что вызывать все равно внутри....
defaultArgs(arguments, {y: 5, z: 10});
какой-нибудь цикл for-in, который на каждой итерации проверяет typeof со строкой. обычно это не так уж и долго... но время теряется. и в веб-приложениях, в которых даже деление на 1000 заменяют на умножение на 0.001,потому что так на 50 микросекунд быстрее ( в играх, например ).. .. оно просто растрачивается. ради красивости кода. ээ это какой-то холивар можно еще поговорить,как лучше в функцию передавать аргументы - через объект,
foo ( { bar : 'ololo', one : 'two' } );
или через перечисление foo ( 'ololo', 'two' ); |
Цитата:
Цитата:
Цитата:
(function(a, b, c, d){
alert([a,b,c,d] + '\n' + arguments.length);
arguments[0] = 10; arguments[1] = 13;
arguments[2] = 11; arguments[3] = 12;
arguments.length = 4;
alert([a,b,c,d] + '\n' + arguments.length);
})(5, 4)
Смотреть в опере.Да и устанвливать значения по-умолчанию внутри самой функции как-то не круто, на мой взгляд. Перед установкой значений по-умолчанию можно написать еще кучу кода и не заметить этого. Мне больше нравится такой подход (в качестве бонуса можно еще и контекст указать)
function lambda(fnc, context, defaults){ // другого имени не придумал
var defaultArgs = [], key, names;
if(defaults){
names = fnc.toString().match(/^[\s\(]*function[^(]*\(([^)]*)\)/)[1]
.replace(/\/\/.*?[\r\n]|\/\*(?:.|[\r\n])*?\*\//g, '')
.replace(/\s+/g, '').split(',');
names = names.length == 1 && !names[0] ? [] : names;
for(var i = 0, length = names.length; i < length; ++i){
key = names[i];
defaultArgs.push(defaults[key]);
}
}
return function(){
return fnc.apply(context, lambda.merge(arguments, defaultArgs));
}
}
lambda.merge = function(arr1, arr2){
var length = Math.max(arr1.length, arr2.length),
arr = [];
for(var i = 0; i < length; ++i){
arr.push(i < arr1.length ? arr1[i] : arr2[i]);
}
return arr;
};
alert(lambda(function(a, b){alert(this); return a + b}, 'Hello, world!', {a: 50, b: 77, c: 42})(10));
|
Это уже интереснее, но я все же склоняюсь к тому чтобы не разбирать по именам аргументы
function merge(arr1, arr2){
var length = Math.max(arr1.length, arr2.length),
arr = [];
for(var i = 0; i < length; ++i){
arr.push(i < arr1.length ? arr1[i] : arr2[i]);
}
return arr;
}
function withDefaults(fn, defaults, cnx){
if(!defaults){
defaults = [];
}
if(!cnx) {
cnx = this;
}
return function(/* args for fn*/){
return fn.apply(cnx, merge(arguments, defaults));
}
}
function mul(a, b){
alert(a + "*" + b + " = " + a*b);
}
withDefaults(mul, [3,5])(5,7);
withDefaults(mul, [3,5])();
withDefaults(mul, [3,5])(6);
|
poorking, тут уж, как говорится, на вкус и цвет. Хотите - передавайте массив, хотите - хеш. У меня, как не трудно заметить, хеш все равно на этапе препроцессинга перегоняется в массив.
Единственный случай, где я вижу разумным использование хеша вместо массива - указание значений по-умолчанию для произвольных переменных, а не только первых n штук. Но в таком случае есть 2 минуса: нам нужно ввести какое-то значение, которое будет сообщать, что данный аргумент не задан и, что гораздо существеннее, при вызове такой функции придется писать что-то вроде fncName(a, b, undefined, undefined, 'red');Это, все-таки, не очень хорошо и в статье, ссылку на которую я привел в предыдущем сообщении, предлагается в таких случаях использовать один аргумент для функции - объект с нужными полями.
fncName({
speed: a,
count: b,
codeName: 'red'
});
|
Статью конечно посмотрел, и я тоже считаю что это самый правильный вариант, я этим часто пользуюсь - и просто и красиво, да еще и удобно, и код читается легко и так далее..
Object.prototype.set = function(props){
for(var any in props) if(props.hasOwnProperty(any)){
if(typeof props[any] === "object" && !props[any] instanceof Array){
if(!this[any]){
this[any] = {};
}
this[any].set(props[any]);
}else{
this[any] = props[any];
}
}
//для удобства
return this;
}
var a = {}.set({codename: "red", value: 5, style: {color: "red", border: "1px solid red"}, fields: [1,2,3,4,5,6,7,8]});
//смотреть в FF
alert(a.toSource());
a.set({some: true});
alert(a.toSource());
Очень удобно, кто не любит расширять прототипы родных классов, в эту функцию можно передавать самого виновника А еще лучше так чтобы если массив передаем в качестве устанавливаемого значение, чтобы не ссылка его устанавливалась а копия, если например набор параметров един, но изменяется по ходу кода
Array.prototype.copy = function(){
var len = this.length, nuarr = [];
for(var i = 0; i < len; i ++){
if(i in this){
if(typeof this[i] === "object" && !this[i] instanceof Array){
nuarr[i] = {}.set(this[i]);
}else if(this[i] instanceof Array){
nuarr[i] = this[i].copy();
}else{
nuarr[i] = this[i];
}
}
}
return nuarr;
}
Object.prototype.set = function(props){
for(var any in props) if(props.hasOwnProperty(any)){
if(typeof props[any] === "object" && !props[any] instanceof Array){
if(!this[any]){
this[any] = {};
}
this[any].set(props[any]);
}else if(props[any] instanceof Array){
this[any] = props[any].copy();
}else{
this[any] = props[any];
}
}
//для удобства
return this;
}
Надеюсь не накосячил в коде почти не тестил |
Цитата:
Цитата:
Цитата:
и все эти ваши решения ни чем не лучше стандартного подхода, если не хуже. Кстати, как так получилось, что значения по умолчанию оказались вне функции? Цитата:
|
Цитата:
Но в целом, да, особой пользы от такого подхода нет. |
Цитата:
|
Цитата:
function arr_cycle ( arr, func ) {
// явл. ли массивом
if ( arr.constructor !== Array ) throw new Error( "'arr' must be Array" );
for ( var i = 0; i < arr.length; i++ )
i in arr && func.apply(window, [ arr[i], i, arr ] );
}
правда, очень жаль, что изза такой типизации в JS нельзя использовать оверлоадинг ( перегрузки ) приходится внутри всей функции проверять тип аргумента и только потом расфасовывать методы |
melky, и что это? Во-первых, где тут значения по-умолчанию, а во-вторых, что помешает Вам написать какой-нибудь код, оперирующий с arr, до проверки?
|
вот значения по-умолчанию. про это забыл
... if ( arr = arr || [] ).constructor ... но если ведь необходимо оперировать только с массивами, то как еще ? |
Это и есть стандартный подход.
|
Цитата:
function f(a, b){alert(this); return a + b}
function fWrapper(){
return lambda(f, 'Hello, world!', {a: 50, b: 77, c: 42});
}
к тому же lambda навязывает задание контекста, т.е. контекст для методов надо либо жестко прописывать в обертке (но тогда нельзя будет вызвать метод в другом контексте), либо указывать при каждом вызове Цитата:
Цитата:
Цитата:
|
Цитата:
Цитата:
Цитата:
|
Цитата:
но передавать объекты ,как один аргумент, будет удобнее Код:
|
Цитата:
Цитата:
B@rmaley.e><e, давай лучше на ты ;) melky, у тебя абстрактный пример, а я просил конкретный |
| Часовой пояс GMT +3, время: 22:13. |