Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Цепочки вызовов (https://javascript.ru/forum/misc/4403-cepochki-vyzovov.html)

Vladimir[gs] 19.07.2009 14:57

Цепочки вызовов
 
Подскажите, как создаются такие штуковины? Хочу понять принцип.
F(10).plus(5).minus(3); // => 12

Riim 19.07.2009 15:02

Каждый метод должен возвращать объект с другими методами.

var MyObj = {
	myMethod1: function() {
		alert('1');
		return this;
	},
	myMethod2: function() {
		alert('2');
		return MyObj;
	}
};

MyObj.myMethod1().myMethod2().myMethod1().myMethod2();

Vladimir[gs] 19.07.2009 15:22

Спасибо за ответ. Как в этом случае передать данные первому объекту?

Riim 19.07.2009 16:02

Цитата:

Сообщение от Vladimir[gs
]Как в этом случае передать данные первому объекту?

Может не объекту, а функции?

Vladimir[gs] 19.07.2009 16:33

Да, наверное. Взгляните на пример из первого поста. Пока понятно только с методами (.plus(5).minus(3)).

Riim 19.07.2009 16:50

Цитата:

Сообщение от Vladimir
Взгляните на пример из первого поста.

Простейший вариант будет примерно таким:
var F = function(x) {
	return {
		plus: function(y) {
			x += y;
			return this;
		},
		minus: function(y) {
			x -= y;
			return this;
		},
		getResult: function() {
			return x;
		}
	};
};

alert(
F(10).plus(5).minus(3).getResult()
);


Он плох тем, что при каждом вызове F создается новый объект, тем самым забивается память браузера.

Вариант получше:
var F = function(x) {
	return new F._f(x);
};

F._f = function(x) {
	this.x = x;
};
F._f.prototype.plus = function(y) {
	this.x += y;
	return this;
};
F._f.prototype.minus = function(y) {
	this.x -= y;
	return this;
};
F._f.prototype.getResult = function(y) {
	return this.x;
};


alert(
F(10).plus(5).minus(3).getResult()
);

Vladimir[gs] 19.07.2009 17:35

Спасибо, понятно. Однако в цепочке появился метод getResult. Существует ли способы вернуть результат автоматически, без появления отдельных методов в цепочке?

Riim 19.07.2009 17:47

Цитата:

Сообщение от Vladimir[gs
]Существует ли способы вернуть результат автоматически, без появления отдельных методов в цепочке?

Можно добавлять методы в prototype числа (только F здесь уже не нужен):
Number.prototype.plus = function(num) {
	return this + num;
};
Number.prototype.minus = function(num) {
	return this - num;
};

alert(
(10).plus(5).minus(3)
);


Для удобного наполнения объектов свойствами/методами обычно используют функцию Object.extend . Простейший вариант:
Object.extend = function(self, obj) {
	for (var key in obj) self[key] = obj[key];
	return self;
};


И наполняем:
Object.extend(Number.prototype, {
	plus: function(num) {
		return this + num;
	},
	minus: function(num) {
		return this - num;
	}
});


upd: не очень удачно получилось, здесь методов мало, при большом количестве методов с Object.extend все же удобней.

Octane 19.07.2009 18:08

Есть еще такой вариант:

function F(x) {
	x = new Number(x);
	x.plus = function(y) {
		return F(x + y);
	};
	x.minus = function(y) {
		return F(x - y)
	};
	return x;
}

alert(F(10).plus(5).minus(3));

Vladimir[gs] 19.07.2009 18:31

Спасибо, все ясно. Ушел экспериментировать.

Riim 19.07.2009 18:34

Цитата:

Сообщение от Octane
Есть еще такой вариант:

Функции будут создаваться при каждом вызове F.

Octane 19.07.2009 18:57

Цитата:

Сообщение от Riim
Функции будут создаваться при каждом вызове F.

Ну и что, вариант то имеет право на жизнь. Да и использование конструктора тоже затратный процесс, еще не известно, что быстрее выполнится в данном случае. Тем более сама рассматриваемая цепочка:
F(10).plus(5).minus(3)

носит чисто ознакомительный характер и врятли кто-то будет применять её в коде JavaScript-приложения.

Riim 19.07.2009 19:02

Цитата:

Сообщение от Riim
Функции будут создаваться при каждом вызове F

На самом деле это легко исправить ;) .

Цитата:

Сообщение от Octane
вариант то имеет право на жизнь

Более того, в некоторых случаях это единственный вариант.

x-yuri 19.07.2009 19:19

Цитата:

Сообщение от Riim
var F = function(x) {
return {
plus: function(y) {
x += y;
return this;
},
minus: function(y) {
...
Он плох тем, что при каждом вызове F создается новый объект, тем самым забивается память браузера.

я бы сказал, объект создается в любом случае, а в этом варианте для каждого объекта создается отдельный "экземпляр" каждого метода

Riim 19.07.2009 19:24

Цитата:

Сообщение от x-yuri
я бы сказал, объект создается в любом случае, а в этом варианте для каждого объекта создается отдельный "экземпляр" каждого метода

Все верно, я там указал этот минус и ниже привел более правильный с этой точки зрения вариант.

leprosus 10.08.2009 17:33

Вы не могли бы написать корректный код, который можно и нужно применять.
И желательно не на таком простом примере...

Давайте разберём вот такой пример:

dom("some_id").append("u").text("some text");

пускай код найдёт объект добавит тэг U и добавит текст.

Octane 10.08.2009 18:35

Да тут все просто :)
function F(node) {
   this.node = node;
}

F.prototype = {
   append: function(arg) { 
      return new F(this.node.appendChild(typeof arg == "string" ? document.createElement(arg) : arg));
   },
   text: function(str) {
      if(typeof str == "undefined") return this.node.innerText || this.node.textContent;
      this.node.innerHTML = "";
      this.node.appendChild(document.createTextNode(str));
      return this;
   }
};

function dom(arg) {
   return new F(typeof arg == "string" ? document.getElementById(arg) : arg);
}


Не могу не прорекламировать в этой теме :D Цепочки вызовов в JavaScript-фреймворке js-core

leprosus 11.08.2009 02:44

Цитата:

Сообщение от Octane (Сообщение 26379)
Не могу не прорекламировать в этой теме :D Цепочки вызовов в JavaScript-фреймворке js-core

Тогда встречный вопрос:
Как всё это сделать в рамках одной функции, как в js-core, не разделяя на function F() и function dom() ?

Octane 11.08.2009 03:39

В js-core, вместо второй функции, рекурсия добавлена, пример будет выглядеть следующим образом:

function dom(arg) {
   if(this.dom) return new dom(typeof arg == "string" ? document.getElementById(arg) : arg);
   this.node = arg;
}
 
dom.prototype = {
   append: function(arg) { 
      return new dom(this.node.appendChild(typeof arg == "string" ? document.createElement(arg) : arg));
   },
   text: function(str) {
      if(typeof str == "undefined") return this.node.innerText || this.node.textContent;
      this.node.innerHTML = "";
      this.node.appendChild(document.createTextNode(str));
      return this;
   }
};

dom(document.body).append("h1").text("It works!");


Используется тот факт, что одна и таже функция может вызываться явным образом и в конструкторе. При вызове явным образом this указывает на window, так определяем, что нужно рекурсивно вызвать эту же фунции в конструкторе с тем же аргументом.

YISHIMITSY 13.03.2010 20:51

Octane,
2-й пример почему-то не работает...

Octane 13.03.2010 21:28

Цитата:

Сообщение от YISHIMITSY
почему-то не работает...

а в консоль ошибок заглянуть?
ReferenceError: arg is not defined {  message="arg is not defined",  more...}

YISHIMITSY 14.03.2010 11:51

понял) а что проверяется этим: if(this.dom) во 2-й строке?

Octane 14.03.2010 11:59

Цитата:

Сообщение от YISHIMITSY
а что проверяется этим: if(this.dom) во 2-й строке?

Цитата:

Сообщение от Octane
Используется тот факт, что одна и таже функция может вызываться явным образом и в конструкторе. При вызове явным образом this указывает на window, так определяем, что нужно рекурсивно вызвать эту же фунции в конструкторе с тем же аргументом.

Но лучше на 2 конструктора расписать:
http://javascript.ru/forum/misc/7106...html#post40714

YISHIMITSY 14.03.2010 22:43

Octane, а если мне надо чтобы dom() и все методы от неё возвращали объект переданый dom, как так сделать? с методами я вроде понял: return this.node; там) а dom() можно?

Octane 14.03.2010 22:51

А смысл? Методы только в прототипе dom могут быть (кросс-браузерно), если DOM-элемент вернуть, никаких кастомных методов мы не получим.

YISHIMITSY 14.03.2010 23:11

ну мне нужно) например чтоб можно было написать и так: dom().style.color'=red'; независимо от методов. Так возможно сделать? (ток при этом чтоб методы тож имели туда доступ, как щас)

Octane 14.03.2010 23:14

никак

Еще по теме http://javascript.ru/forum/misc/6107...prototype.html

YISHIMITSY 14.03.2010 23:26

чё-то я ваще запутался с этим js... ( Но есть же вообще в природе какие-то способы сделать так: dom(arg).text('text') - это добавляет текст и возвращает arg и просто dom(arg) возвращает arg?
У вас в js-core если я правильно понял так и есть:

"В js-core функции core(…) и $(…) эквивалентны, и возвращают новую копию объекта core, содержащую ссылку на указанный узел.
function $(arg) {
return typeof arg == "string" ? document.getElementById(arg) : arg;
}"

Ток чё с методами тогда.. как совместить то эти вещи?

Octane 14.03.2010 23:44

function dom(arg) {

	var element = typeof arg == "string" ? document.getElementById(arg) : arg;
	if (!element) return null;

	var method, methods = dom.customMethods;
	for (method in methods) {
		if (methods.hasOwnProperty(method)) {
			element[method] = methods[method];
		}
	}

	return element;
}

dom.customMethods = {
	text1: function (str) {
		if (!arguments.length) return this.innerText || this.textContent;
		this.innerHTML = "";
		this.appendChild(document.createTextNode(str));
		return this;
	}
};

dom(document.body).text1("Тарам пам пам").style.backgroundColor = "#fee";


Цитата:

Сообщение от YISHIMITSY
В js-core функции core(…) и $(…) эквивалентны, и возвращают новую копию объекта core

тоже самое, что и
function dom(…) {…}
var $ = dom;

YISHIMITSY 14.03.2010 23:58

Большое спасибо, то что нужно) последний вопрос, а по скорости это хуже или лучше чем использование prototype?

Octane 15.03.2010 00:03

Хуже

YISHIMITSY 17.03.2010 09:23

Octane, я недавно смотрел исходник вашего js-core, не могли бы вы если не трудно конечно, пояснить что означает конструкция
( код... и закрытая далеко в конце ")"
вобщем расставленые так скобки?

Octane 17.03.2010 12:29

Оператор группировки?


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