Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Строка вызова функции (https://javascript.ru/forum/misc/11109-stroka-vyzova-funkcii.html)

DMH 07.08.2010 08:33

Строка вызова функции
 
Можно ли внутри функции определить строку, её вызвавшую?
Например -
$=function(x) {
     var a = [];
     a.css = function(b) { перебираем массив элементов this[i] }
     // тут через push наполняем a
     return a;
}

Внутри $ нужно определить, если в строке вызова присутствует "css", значит из $ возвращаем массив, иначе возвращаем элемент, т.е. $('x').css('y') - из $ возвращаем массив элементов, так как css() присутствует в строке вызова, а тут - $('x').style из $ возвращаем сам единственный элемент, так как css() в строке вызова нет.

Пока делаю так - для моих методов $('x').css('y'), для стандартных $('x')[0].style, но некрасиво как-то, хотелось бы без [0] и долнительного маркера в параметрах.

p.s. код к jquery никакого отношения не имеет.

Kolyaj 07.08.2010 09:05

Бред какой-то, честно говоря.

DMH 07.08.2010 09:23

Аргументы? Предлагайте варианты решения. Видимо в самой функции нельзя определить кто её вызвал, arguments.caller в ie возвращает Object object, в остальных undefined. Тогда только остаётся по маркеру-параметру определять что возвращать.

DMH 07.08.2010 10:19

Если непонятно, приведу пример с jquery, в котором не работает то, что я хочу сделать.

<!DOCTYPE HTML PUBLIC  "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<title></title>
<style>
p {
	border:2px solid red;
	width:100px;
	height:100px;
	margin:20px;
}
</style>

<script type="text/javascript" src="jquery-1.3.2.min.js"></script>

</head>
<body>

<p id="x"></p>

<input onclick="$('#x').css({'background':'blue'})" type="button" value="test 1"> // работает

<input onclick="$('#x').style.background='blue'" type="button" value="test 2"> // получим ошибку - неизвестный style, так как вернулся массив, а не элемент

<input onclick="$('#x')[0].style.background='blue'" type="button" value="test 3"> // прекрасно отработает, так как выдёргиваем первый элемент из массива 

</body>
</html>


Я хочу сделать, чтобы это происходило прозрачно, т.е. чтобы внутри самой $() определялось что вернуть, элемент или массив, тогда непонадобится подставлять [0] или вводить дополнительный параметр-индикатор.

Kolyaj 07.08.2010 11:13

Цитата:

Сообщение от DMH
Тогда только остаётся по маркеру-параметру определять что возвращать.

Разумеется возвращаемое значение функции не должно зависеть от того, где и как она вызвана.

Цитата:

Сообщение от DMH
arguments.caller в ie возвращает Object object, в остальных undefined.

arguments.callee.caller

DMH 07.08.2010 12:06

Спасибо за arguments.callee.caller, ошибся в написании. Прогнал по браузерам, при таком вызове -
window.onload=function() {
	$('x').css({background:'#00f'});
	$('x').style.width='10px';
}

возвращается -
function() {
	$('x').css({background:'#00f'});
	$('x').style.width='10px';
}

Можно было бы регуляркой выдрать css и style, но как проверить какая из двух строк вызвала $ не знаю + вызывающая строка должна быть внутри функции, иначе null.

Ладно, видимо придётся к входящему параметру дописывать флаг.

PeaceCoder 07.08.2010 22:35

Смысл понял, но не понял зачем это все ? Разве css не станавливает свойство style.* для каждого элемента? Если так, то зачем ломать голову?

Простое решение - перегонять ссылку .style первого элемента в массиве как свойство массива. Хотя так не пробовал но должно сработать.

<div style='width:10px; height: 10px; background: #0f0;'></div>
<div style='width:20px; height: 20px;'></div>

<script type='text/javascript'>
function $(tag){
  var arr = [], els = document.getElementsByTagName(tag),i=els.length;
  while (i--) arr[i] = els[i];
  arr.style = (arr[0]||{style:{}}).style;
  return arr;
  }
setTimeout(function(){
alert($('div').style.background='#000')
},2000);</script>


Как и ожидал, работает. Но не тестил в др браузерах

DMH 08.08.2010 06:12

style - это просто пример, частный случай. На самом деле внутри $ будет несколько моих функций. Основное предназначение $() - вернуть конкретный элемент для дальнейшего его использования со стандартным js (setAttribute, id и т.д.) либо вернуть массив элементов (пусть даже из одного элемента, но массив) для использования его в моих функциях внутри $(). Но так как функции $() неизвестна полная строка вызова, она не знает что возвратить, элемент или массив, поэтому пока додумался до маркера во входящем параметре либо выдёргивании первого элемента из массива для стандартного js - $()[0]. Думаю также разделить $() на две функции, первая будет всегда возвращать сам элемент для работы со стандартным js - $$$().setAttribute(), а вторая всегда массив для работы с $().моя_функция().

Если мы напишем document.getElementById('x').css(), мы ведь получим ошибку о неизвестном css(), а если напишем $('x').style, то получим ошибку о неизвестном style, так как внутри $ есть css(), но нету style.
Хотел сделать чтобы было прозрачно и определялось автоматически, т.е. внутри $() определялось что вернуть и тогда бы работали оба варианта - $().css() и $().getAttribute(), даже если внутри $() нету этого getAttribute().

p.s. элемент всмысле document.getElementById('x');

PeaceCoder 08.08.2010 18:04

увы. в JS нет магических функций типа __call и т.п. а жаль. это бы и спасло.

Gvozd 09.08.2010 13:41

возвращайте всегда массив.
а в нем определите методы, аналогичные методам DOM для одного объхекта

DMH 09.08.2010 17:51

Перечисление всего js-dom - много кода. Пока в раздумьях.
Разбил на три группы - события, стили и методы. С первыми двумя проблем нет, с третим (mtd) пока разбираю варианты.

Примерно так -
onmouseover=function() {};
innerHTML='text';
эти похожи, их в первую группу.

style.background='red';
у этого добавился style, его во вторую группу.

С третей группой неопределённость.
setAttribute();
getAttribute();
width+10px;
В этой группе значения как считываются, так и присваиваются.
В итоге для этой группы код получается вроде такого -

z('.be').mtd(offsetWidth+'px');


Основной код -
z=function(x) {

	if (!x) return;

	var a = [];
	var r;

	a.chd = function(x) {for (var i = 0; i < this.length; i++) {return z(x, this[i]);}}
	
	a.stl = function(x) {for (var i = 0; i < this.length; i++) {for (var j in x) this[i].style[j] = x[j];}}

	a.evt = function(x) {for (var i = 0; i < this.length; i++) {for (var j in x) this[i][j] = x[j];}}

	a.mtd = function(x) {for (var i = 0; i < this.length; i++) {return this[i].x;}}



	a.opc = function(b,f,sp) {

		for (var i = 0; i < this.length; i++) {
			var t=this[i];
			if (ie) t.style.filter='alpha(opacity='+(b*100)+')';
			else t.style.opacity=b;

			if ((b==0) && (f>0)) t.style.display='block';
			if ((b==0) && (f==0)) {

				if (t.className=='bu') t.style.top='-1000px';
				else t.style.display='none';
			}

			if (b!=f) {
			
				if (b>f) { b=(b*10-1)/10; setTimeout(function() { z(t).opc(b,f,sp); },sp); }
				else { b=(b*10+1)/10; setTimeout(function() { z(t).opc(b,f,sp); },sp); }
			}

		}
	}


	var e=z.arguments[1];

	if (typeof(x) == 'string') {
		
		x=x.toLowerCase();
		
		if (x.substr(0,1)=='#') {
			var d=document.getElementById(x.slice(1));
			if (d) a.push(d);
			return a;
		}

	if (x.substr(0,1)=='.') r = new RegExp('\\b' + x.slice(1) + '\\b');
	}
	else {

	a.push(x)
	return a;
	}

	e = (e ? e : document).getElementsByTagName("*");

	for (var i = 0; i < e.length; i++) {

	if (r) {if (r.test(e[i].className.toLowerCase())) a.push(e[i]);}
	else {if (e[i].tagName.toLowerCase()==x) a.push(e[i]);}
	}

	return a;
}

chd - дочерние элементы, stl - стили, evt - события и всё что подходит по синтаксису, mtd - всё остальное, opc - одна из моих функций. # - id, .-класс, пустота - сам тег.

Вызов выгдядит так -
z('.t').chd('.bk').stl({background:'url('+btn[l]+') no-repeat'});
// дочерним элементам с классом bk элемента с классом t назначаем фон. 
z('.t').chd('.bk').evt({
onmouseover:function {
alert('over');
},
onmouseout=function() {alert('out')}
});
//тоже самое, только обработчики событий.

Если третий mtd удастся пристроить, тогда всё ок.

DMH 10.08.2010 09:06

Короче с методом (mtd) фигня получается.
z('.t').mtd('setAttribute("class","v")');
элементам ".t" назначить класс "v" ещё как-то вписывается, а вот простая и понятная запись -
function $(x) {return document.getElementById(x);}

$('x').removeChild($('y'));

превращается в
z('#x').mtd(removeChild(z('#y')[0]));

Появился [0], без него я не верну один элемент. Вернулся снова туда с чего начал, либо маркер, либо [0].
Решил оставить [0], пускай с ним будет.
В jquery $() тоже возвращает массив, а не сам элемент, но там переписан весь стандартный js, взаимодействующий с DOM, мне же этого не требуется.

p.s.
z('.b9').chd('span')[0].onclick=function(){daut();}
z('.b9').chd('span').evt({onclick:function(){daut();}});

Внутри ".b9" у меня только один span, поэтому результат обоих функций идентичен.
Тоже самое и тут -
z('#a')[0].innerHTML='Добро пожаловать,';
z('#a').evt({innerHTML:'Добро пожаловать,'});

есть выбор, как с [0], так и без него. А куда этот прицепить - z('x').removeChild(z('y')); и ему подобные. В любом случае без [0], z('y') мне вернёт массив и removeChild выдаст ошибку. Может строгое разбиение, групповые операции - отдельно, единичные - отдельно и создать две разные функции, z() и $().


Часовой пояс GMT +3, время: 11:06.