Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 1.0/2.0 (http://www.flasher.ru/forum/forumdisplay.php?f=93)
-   -   Почему все свойства объекта получают тип "object" ? (http://www.flasher.ru/forum/showthread.php?t=90328)

Annihilator 08.01.2007 21:09

Почему все свойства объекта получают тип "object" ?
 
Есть очень полезный и удобный метод, который на основании XML-а делает объект со свойствами
Код:

XML.prototype.toObject = function () {
var xparse = function (n) {
        var o = new String (n.firstChild.nodeValue), s, i, t;
        for (s = (o == "null") ? n.firstChild : n.childNodes[1]; s != null; s = s.nextSibling) {
                if(s.childNodes.length > 0){
                        t = arguments.callee(s);
                } else {
                        t = new String (s.nodeValue);  //явно задан тип String
                }
                for (i in s.attributes) t[i] = s.attributes[i];
                if (o[s.nodeName] != undefined) {
                        if (!(o[s.nodeName] instanceof Array)) o[s.nodeName] = [o[s.nodeName]];
                        o[s.nodeName].push(t);
                        t.xmlCount = s.childNodes.length;
                } else {
                        o[s.nodeName] = t;
                }
                o[s.nodeName].xmlCount = s.childNodes.length;
        }
        return o;
}
return xparse (this);
}

Например, из такого XML:
Код:

<?xml version="1.0" ?>
<xmltest>
<num>500</num>
<txt attributeExample="Node 2 attribute">
        <some>777</some>
        <thing>qwerty</thing>
</txt>
</xmltest>

получается объект со свойствами:
Код:

xmltest.num; // = 500
xmltest.txt.attributeExample; // = Node 2 attribute
xmltest.txt.some; // = 777
xmltest.txt.thing; // = qwerty

Всё замечательно, пока дело не доходит до операций с этими свойствами - все они оказываются типа "object" выходит совсем не то, что должно:
Код:

var a = xmltest.num + xmltest.txt.some;
trace(a); // выводит 500777 вместо 1277
var b = "qwerty";
trace(typeof b) // - string
trace(b == xmltest.txt.thing); // выводит false вместо true
b = xmltest.txt.thing;
trace(typeof b) // - object
//... и прочие подобные неприятности, хотя функция быстрая и очень полезная для сокет-общения.

Почему так получается и как добиться, чтобы они получали правильный тип (для строк - string, для чисел - number, и т.п.) ?

iNils 08.01.2007 21:16

Код:

s = 5;
n1 = new String (s);
n2 = String (s);
trace (typeof n1);
trace (typeof n2);
/////
n = "5";
s1 = new Number (n);
s2 = Number (n);
trace (typeof s1);
trace (typeof s2);

Так понятно почему?

Annihilator 08.01.2007 21:29

непонятно почему из "n1 = new String (s)" получается тип object а не string ???

iNils 08.01.2007 21:41

Код:

s = 5;
n1 = new String (s);
n2 = String (s);
trace (n1.length);
trace (n2.length);

В первом случаи, это конструктор класса.
Во втором приведением типов.

Обычно, мы задаем строковой литерал, то есть
Код:

str = "234"
Но у литерала нет ни методов ни свойств. Поэтому когда мы делаем
Код:

trace (str.length)
интерпретатор автоматически преобразовывает литерал во временной объект String (то есть new String), выполняет метод, а потом удаляет временной объект.

PS. Поэтому все методы и свойства работают быстрее, если у нас объект String, а не литерал. Например length в 5 раз.

Annihilator 08.01.2007 22:07

Спасибо, это понял, но как это применить в моей функции не догоняю.
писал эту строку хоть так:
t = new String (s.nodeValue);
хоть так:
t = String (s.nodeValue);
хоть так:
t = s.nodeValue;

разницы никакой, все равно все свойства получают тип object.

iNils 08.01.2007 22:25

Я не понял как ваш метод применить.
Код:

XML.prototype.toObject = function () {
        var xparse = function (n) {
                var o = new String (n.firstChild.nodeValue), s, i, t;
                //trace (o)
                for (s = (o == "null") ? n.firstChild : n.childNodes[1]; s != null; s = s.nextSibling) {
                        if (s.childNodes.length > 0) {
                                t = arguments.callee (s);
                        } else {
                                t = new String (s.nodeValue);
                                //явно задан тип String
                        }
                        for (i in s.attributes) {
                                t[i] = s.attributes[i];
                        }
                        if (o[s.nodeName] != undefined) {
                                if (!(o[s.nodeName] instanceof Array)) {
                                        o[s.nodeName] = [o[s.nodeName]];
                                }
                                o[s.nodeName].push (t);
                                t.xmlCount = s.childNodes.length;
                        } else {
                                o[s.nodeName] = t;
                        }
                        o[s.nodeName].xmlCount = s.childNodes.length;
                }
                return o;
        };
        return xparse (this);
};
s = '<?xml version="1.0" ?><xmltest><num>500</num><txt attributeExample="Node 2 attribute"><some>777</some><thing>qwerty</thing></txt></xmltest>';
xml = new XML (s);
trace (xml.toObject ());

и простой вызов возращает null.

Annihilator 09.01.2007 14:14

Вот так:
Код:

s = '<?xml version="1.0" ?><xmltest><num>500</num><txt attributeExample="Node 2 attribute"><some>777</some><thing>qwerty</thing></txt></xmltest>';
var x:XML=new XML();
x.ignoreWhite=1; // это обязательно задавать
x.parseXML(s);
var xmlobj = x.toObject();
// дальше обращаться к свойствам созданого объекта xmlobj:
trace(xmlobj.xmltest.num); // 500
trace(typeof xmlobj.xmltest.num); // object    :(


etc 09.01.2007 14:28

А можно вопрос? Зачем объект преобразовывать в объект?

Annihilator 09.01.2007 15:03

где ты это видишь?
Я из XML-объекта делаю обычный объект со свойствами, чтобы не плутать по XML-ю через childNodes, nodeName, nodeValue и др., а обращаться к нормальным свойствам нормального объекта. Кроме того, таким способом можно сразу существующему объекту поменять свойства или добавить новые. У меня это отлично работает в связке с сокет-сервером.

etc 09.01.2007 15:18

Как это где вижу? XML — объект, им же и остался. А что будешь делать, когда у тебя будет два тега с одним именем?

Annihilator 09.01.2007 15:56

нет, ты немного не понял.
В примере выше объект "х" - это xml-объект, в котором доступ к значениям осуществляется через nodeValue.
Метод toObject возвращает стандартный флешовый объект с обычными свойствами/значениями, т.е. "x" и "xmlobj" - разные объекты по сути и по классам.

В случае нескольких тегов с одинаковым именем, метод создаёт свойство-массив. Например:
Код:

s = '<?xml version="1.0" ?>
<top>
<item name="one" id="23">first</item>
<item name="two" link="www.google.com">first</item>
<item param="Node 2 attribute">
        <some>777</some>
        <thing>qwerty</thing>
</item>
<item name="four">4 all</item>
</top>';
var x:XML=new XML();
x.ignoreWhite=true; // это обязательно задавать
x.parseXML(s);
var obj = x.toObject();
// дальше обращаться к свойствам созданого объекта obj
// например, чтобы прочесть значение узла <thing> :
trace(obj.top.item[2].thing); // выводит  qwerty


etc 09.01.2007 16:06

Нет, я все-равно не понимаю, зачем все эти преобразования и перемешивания данных? Облегчить жизнь? Скорее усложнить, о чем и свидетельствует эта тема…

Annihilator 09.01.2007 16:16

Да, а как ты обратишься к значению узла <thing> вышепреведеного xml-a?

etc 09.01.2007 16:25

Изменил бы архитектуру таким образом, чтобы одному логическому элементу не пришлось бы обращаться глубже своих детей. Не говоря уже о том, что была бы четкая структура XML, с определенными правилами построения.

iNils 09.01.2007 17:43

Цитата:

Сообщение от Annihilator
Да, а как ты обратишься к значению узла <thing> вышепреведеного xml-a?

Основа:
Код:

function getNode (node, name) {
        for (var i = 0; i < node.childNodes.length; i++) {
                if (node.childNodes[i].nodeName.toLowerCase () == name.toLowerCase ()) {
                        return node.childNodes[i];
                }
        }
};


Iv 09.01.2007 20:40

Ажно руки зачесались дописать книгу про XML.

Пара советов:
- etc дело говорит: преобразовывать стандартный объект (XML) в нестандартный дело сомнительное.

- чтобы достучаться до значения атрибута и получить его в нужном тебе типе, просто сделай методы конвертации/доступа. Поскольку расширить XMLNode своим классом нерентабельно, лучше юзать композицию. К примеру, желаем получить доступ к значению атрибута как к массиву:
(пример не рабочий, просто как принцип)
Код:

class XMLUtils {

 public static function getAttributeArray (node:XMLNode, name:String):Array {
 var arrtributes_obj:Object = node.attributes;
  if (typeof arrtributes_obj[name] == "string") {
  arrtributes_obj[name] = arrtributes_obj[name].split(",");
  }
  return arrtributes_obj[name];
 }

  .......

}

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

- разберись со своим стандартом XML, сделай правильную структуру. Работа с данными не должна быть в виде длинных иерархических обращений. Передавай узлы на обработку экземплярам, а не управляй ими централизованно. К примеру, у тебя на сцене несколько персонажей, привязанных к юзерам. Их состояние апдейтится из XML.
Тогда лучше сделать XML вида:
Код:

<state>
  <user id="iv">
    <action name="jumpLeft" arguments="10,12">
    <action name="totalWin" arguments="350">
  </user>
  <user id="etс">
    <action name="jumpDown" arguments="10,-30">
    <action name="totalLose" arguments="-200">
  </user>
</state>

далее, при получении данных, просто пробегаем по нодам первого уровня и раздаем их на обработку экземплярам:
Код:

private function onLoad (ok) {
....

  var node:XMLNode = this.firstChild.firstChild;
  while (node) {
    var id:String = XMLUtils.getAttributeString(node, "id");
    UserClass.updateInstance(id, node);
    node = node.nextSibling;
  }
}

Следующий этап - обработка полученных данных экземплярами:
Код:

class UserClass {

  private static var __users:Object;

  public static function updateInstance (id:String, node:XMLNode):Void {
    var user:UserClass = __users[id];
    user.updateState(node);
  }

  .....

  private function updateState(node:XMLNode):Void {
    node = node.firstChild;
    while (node) {
      var action_name:String = XMLUtils.getAttributeString(node, "name");
      var action:Function = this[action_name];
      var arguments_arr:Array = XMLUtils.getAttributeArray(node, "arguments");
      if (action) {
        action.apply(this, arguments_arr);
      }
      node = node.nextSibling
    }
  }

  private function jumpLeft (distance:Number, height:Number):Void {
      distance = Number(distance) || 0;
      height = Number(height) || 0;
      ......
  }

}

- собственно проверка и приведение типов также должны быть и непосредственно в методе-обработчике (мали ли откуда еще придется его вызывать).


Резюмируем:
- получили данные в приложение
- в приложении раскидали по экземплярам
- в экземплярах раскидали по обработчикам
- в обработчиках проверили типы, привели к нужным
- выполнили действия.

код выше - не рабочий, просто иллюстрация.
- оч тяжело писать код прямо здесь... три раза правил :)

Iv 09.01.2007 20:54

Да, обрати внимание, что нигде в коде не обращаемся к узлам - детям детей.
Исключение в onLoad, да и то потому, что this - пустой.
Второе исключение я допускаю для текстовых узлов в обращениях вида:
node.firstChild.nodeValue;
все остальные случаи - признак неидеальной организации проекта :)

Fl00r 09.01.2007 20:59

жаль тут в мемориз низзя.

WindWalker 16.07.2007 15:51

Цитата:

Сообщение от iNils
Основа:
Код:

function getNode (node, name) {
        for (var i = 0; i < node.childNodes.length; i++) {
                if (node.childNodes[i].nodeName.toLowerCase () == name.toLowerCase ()) {
                        return node.childNodes[i];
                }
        }
};


Пробегать по циклу ради каждого нода?
А если несколько нодов с одинаковым именем?

etc 16.07.2007 15:53

Цитата:

Сообщение от WindWalker
А если несколько нодов с одинаковым именем?

Этот вопрос задан мною в конце первой страницы. А в начале второй ответ на него.

WindWalker 16.07.2007 15:58

Наши вопросы касаются совершенно разных кодов и подходов.
Я спрашивал по поводу кода, приведённого iNils.

Подозреваю, что единственный способ разрешить его проблему - добавить ещё один параметр (индекс) и в теле метода завести счётчик.
Что получается совсем уж некрасиво и тормозно.

Dr.OH 16.07.2007 16:35

вот это реально дурдом )
тема вообще с другого начиналась, но раз уж понеслось, то, по-моему это немножко странный подход подбирать пример использования xml-данных под сами данные... обычно как-то наоборот бывает... (это я про пример, что взяли xml, раскидали его по клипам, там еще раз раскидали и еще:) )
ок, я никак не пойму чем не устраивает нормальная архитектура вида:
object(корень):
- name (имя)
- attributes(массив аттрибутов)
- cdata (текст)
- nodes (массив аналогичных объектов)
и пара вспомогательных методов для доступа к nodes.
Реализация по своему вкусу, хоть бинарное дерево строй, если структура сложная и нужен быстрый поиск.
оффтоп: может я чего не понимаю, но чего это за класс у которого все методы и свойства статические??? и как им потом пользоваться... или это такой извращенный вариант синглета???.. и зачем создавать класс с единственным методом, да еще и статическим?

WindWalker 16.07.2007 17:04

Цитата:

Сообщение от Dr.OH
ок, я никак не пойму чем не устраивает нормальная архитектура вида:
object(корень):
...
- nodes (массив аналогичных объектов)

1. Поиск нода выглядит громоздко (вложенные циклы для беготни по массивам детей).
2. В некоторых случаях поиск будет осуществляться дольше: пробежались в цикле - взяли один нод, снова пробежались по тому же массиву - взяли второй и т.д.

etc 16.07.2007 17:08

Цитата:

Сообщение от Dr.OH
оффтоп: может я чего не понимаю, но чего это за класс у которого все методы и свойства статические??? и как им потом пользоваться... или это такой извращенный вариант синглета???.. и зачем создавать класс с единственным методом, да еще и статическим?

Вместо _global. Мы же все-таки за ооп, как никак, да?

iNils 16.07.2007 23:28

Цитата:

Сообщение от WindWalker
1. Поиск нода выглядит громоздко (вложенные циклы для беготни по массивам детей).
2. В некоторых случаях поиск будет осуществляться дольше: пробежались в цикле - взяли один нод, снова пробежались по тому же массиву - взяли второй и т.д.

По какому признаку брать нод? По имени нода или чего? Если имени нода, то ведь их может быть несколько одинаковых, как иначе без цикла?
В последнее время я использую xml построенного на идеи древовидного id. То есть почти каждый потомок имеет id построенного из id предка + свой: /map/ > /map/city/ > /map/city/street/ и тд. Таким образом до нода я могу достучаться обычным способом и по абсолютному адресу.

Dr.OH 17.07.2007 00:18

WindWalker, это уже каждый может реализовывать как хочет, балго проблема поиска уже имеет сотни решений (характерный пример БД), если ты считаешь, что поиск будет осуществляться медленно, то просто попробуй применить другой алгоритм сортировки и поиска. не вопрос... т.е. это как бы дело вкуса каждого. или вот пример iNils - тоже вариант. А если ноды называются одинаково, то сделать функцию аналог "SELECT smth WHERE smth=val".
__etc, нет, ну не стоит ведь доходить до абсурда. ООП - это метод решения задач, позволяющий не запутаться и избежать кучи ошибок, а не самоцель... я конечно понимаю, заставь дурака Богу молиться, но по-моему это очень некрасивый вариант, который точно никогда не стоит использовать.

еще кстати тема классная, совсем про ее забыл. Если уж реально нужна высокая скорость (ни разу не видел таких приложений - все равно realtime не получится), то можно еще и кеширование результатов организовать с возможностью предугадывать следующие запросы.

etc 17.07.2007 00:24

Цитата:

Сообщение от Dr.OH
__etc, нет, ну не стоит ведь доходить до абсурда. ООП - это метод решения задач, позволяющий не запутаться и избежать кучи ошибок, а не самоцель...

В AS2 нет _global. Точка. Даже без запятых.

Dr.OH 17.07.2007 00:29

тогда вообще не понял - к чему здесь global??? и чем root не global (классно звучит :) )?

etc 17.07.2007 00:31

В AS2 классах не должно быть никаких _root и _global. Это не так уж и сложно соблюсти.

iNils 17.07.2007 00:36

Цитата:

Сообщение от __etc
В AS2 классах не должно быть никаких _root и _global. Это не так уж и сложно соблюсти.

В принципе да, но есть но:
_root, в смысле _level0 есть когда идет запрос к flashvars...
_global я часто использую, когда в FlashDevelop нужен setTimeout, иначе он ругается. А вобще, если _global используется в качестве get, а не set, то ничего страшного.

Dr.OH 17.07.2007 00:37

ладно, если без них ну никак нельзя, то пусть будет так.. хотя я все равно не понял, зачем они нужны...
в других языках они используются в основном только для создания каких-нибудь можных callback'ов, функциональных указателей или синглтонов - в общем редко применяются, так что я наверное просто чего-то не знаю про них.. пойду почитаю )

etc 17.07.2007 00:39

Для flashvars у меня есть класс ExternalData, в него переменные кладутся кодом во fla-файле (там я допускаю использование _levelN и прочие _xxxx). В классах _root, _global и прочие вещи отсутствуют напрочь (кроме тех моментов, где их использование действительно жизненно необходимо).
А то, что ругается FD — это исключительно проблема программы.

WindWalker 17.07.2007 00:56

Самый простой пример класса, у которого только статические методы - Math.

Dr.OH 17.07.2007 01:07

всё, ушли в оффтоп... Math - это не столько класс в смысле ООП, сколько namespace.

etc 17.07.2007 10:22

Цитата:

Сообщение от Dr.OH
всё, ушли в оффтоп... Math - это не столько класс в смысле ООП, сколько namespace.

Неправда. namespace-ы здесь вообще никаким боком.

Dr.OH 17.07.2007 10:59

да, конечно, это просто класс экземпляры которого нельзя создавать или по крайней мере не имеет смысла, т.к. они ничем не будут различаться; у которого все методы статические, т.е. он представляет из себя просто способ облегчения обращения к методам. Обычно это называется namespace.
Так, ладно, закрыли тему, если вы считаете, что класс, состоящий из 2-3 статических методов и пары статических свойств - это нормально и в стиле ООП... ну, ок... у вас свой стиль ООП ;)

etc 17.07.2007 11:03

Вообще говоря, в том же нативном наборе классов плеера полно классов, которым просто не нужен экземпляр. Тот же Mouse, Stage и иже с ними.
И ситуаций, когда не нужен экземпляр — полно.
Поясняй тогда, чем это не ООП.
И объясни, что ты будешь делать, когда тебе потребуются некоторые сервисные функции вроде проверки E-mail на валидность (в случае с AS3 можно создать сразу функцию в пакете, это же не зря придумано?). Просто мне интересен твой подход к таким вещам, если у тебя действительно вариант будет лучше, я подумаю, как писать в следующий раз свои проекты.

Dr.OH 17.07.2007 12:24

это не совсем класс - то, о чем ты говоришь называется синглет - класс, имеющий по определению только один экземпляр. и конструктор такого класса возвращает указатель на самого себя, не создавая при этом очередной экземпляр класса. Так это выглядит во всех языках программирования (на счет AS я точно не уверен, возможно выш выход - это единственно возможный). В случае, если не нужен класс и экземпляры создаваться не будут, то проще сделать clip с функциями (конечно это в принципе тот же класс, но все же) или просто набор функций. С точки зрения ООП это логичнее.
Класс сам по себе должен описывать некоторую абстракцию (как в школе учили, например, стол), а экземпляр детализирует эту абстракцию.

etc 17.07.2007 13:46

Я не получил ответ на свой вопрос.
Синглтон тут вообще не при делах.

WindWalker 17.07.2007 18:07

Вот так:
Код:

isEmailValid = new EmailValidator(tfEmail.text).isValid()
Тормознее, памяти больше жрёт и т.д. Зато по всем канонам ООП.
ООП - оно такое...


Часовой пояс GMT +4, время: 22:52.

Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2026, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.