1 (изменено: -red-, 2014-04-02 11:22:30)

Тема: JS: Неявное наследование объекта?

При обходе всех объектов приходится вводить ограничение.


function ObjWalker(obj,count,name){
    var result = "";
    count = count + 1;
    // Ограничение итераций, иначе попытается скушать всю память или не будет работать - в зависимости от среды запуска.
    if(count > 3) return name+": "+obj+" is limited ["+typeof obj+"]\n";
    if(null == obj) return name+"."+obj+" = null ["+typeof obj+"]\n";
    var tmp = null;
    for (var ch in obj){
        tmp = obj[ch];
        if( typeof tmp != "object" ){
            result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
        }else{
            result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
            result += ObjWalker(tmp,count,name+"."+ch.toString());
        }
        tmp = null;
    }
    if("" == result){
        return name+" "+obj+" is empty ["+typeof obj+"] \n"
    }
    return result;
}
var pocient1 = new Object();
var pocient = this;
var result  = "this:\n"+ObjWalker(pocient,0,"this")+"\n===========\n";
WScript.Echo(result);

Вот что выводится в результате:

>cscript selfinfo.js
Сервер сценариев Windows (Microsoft ®) версия 5.8
© Корпорация Майкрософт (Microsoft Corp.), 1996-2001. Все права защищены.

this:
this.WScript = Windows Script Host [object]
this.WScript Windows Script Host is empty [object]
this.WSH = Windows Script Host [object]
this.WSH Windows Script Host is empty [object]
this.ObjWalker = function ObjWalker(obj,count,name){
        var result = "";
        count = count + 1;
        // Ограничение итераций, иначе попытается скушать всю память или не будет работать - в зависимости от среды запуска.
        if(count > 3) return name+": "+obj+" is limited ["+typeof obj+"]\n";
        if(null == obj) return name+"."+obj+" = null ["+typeof obj+"]\n";
        var tmp = null;
        for (var ch in obj){
                tmp = obj[ch];
                if( typeof tmp != "object" ){
                        result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
                }else{
                        result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
                        result += ObjWalker(tmp,count,name+"."+ch.toString());
                }
                tmp = null;
        }
        if("" == result){
                return name+" "+obj+" is empty ["+typeof obj+"] \n"
        }
        return result;
} [function]
this.pocient1 = [object Object] [object]
this.pocient1 [object Object] is empty [object]
this.pocient =  [object]
this.pocient.WScript = Windows Script Host [object]
this.pocient.WScript Windows Script Host is empty [object]
this.pocient.WSH = Windows Script Host [object]
this.pocient.WSH Windows Script Host is empty [object]
this.pocient.ObjWalker = function ObjWalker(obj,count,name){
        var result = "";
        count = count + 1;
        // Ограничение итераций, иначе попытается скушать всю память или не будет работать - в зависимости от среды запуска.
        if(count > 3) return name+": "+obj+" is limited ["+typeof obj+"]\n";
        if(null == obj) return name+"."+obj+" = null ["+typeof obj+"]\n";
        var tmp = null;
        for (var ch in obj){
                tmp = obj[ch];
                if( typeof tmp != "object" ){
                        result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
                }else{
                        result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
                        result += ObjWalker(tmp,count,name+"."+ch.toString());
                }
                tmp = null;
        }
        if("" == result){
                return name+" "+obj+" is empty ["+typeof obj+"] \n"
        }
        return result;
} [function]
this.pocient.pocient1 = [object Object] [object]
this.pocient.pocient1 [object Object] is empty [object]
this.pocient.pocient =  [object]
this.pocient.pocient.WScript = Windows Script Host [object]
this.pocient.pocient.WScript: Windows Script Host is limited [object]
this.pocient.pocient.WSH = Windows Script Host [object]
this.pocient.pocient.WSH: Windows Script Host is limited [object]
this.pocient.pocient.ObjWalker = function ObjWalker(obj,count,name){
        var result = "";
        count = count + 1;
        // Ограничение итераций, иначе попытается скушать всю память или не будет работать - в зависимости от среды запуска.
        if(count > 3) return name+": "+obj+" is limited ["+typeof obj+"]\n";
        if(null == obj) return name+"."+obj+" = null ["+typeof obj+"]\n";
        var tmp = null;
        for (var ch in obj){
                tmp = obj[ch];
                if( typeof tmp != "object" ){
                        result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
                }else{
                        result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
                        result += ObjWalker(tmp,count,name+"."+ch.toString());
                }
                tmp = null;
        }
        if("" == result){
                return name+" "+obj+" is empty ["+typeof obj+"] \n"
        }
        return result;
} [function]
this.pocient.pocient.pocient1 = [object Object] [object]
this.pocient.pocient.pocient1: [object Object] is limited [object]
this.pocient.pocient.pocient =  [object]
this.pocient.pocient.pocient:  is limited [object]
this.pocient.pocient.result = undefined [undefined]
this.pocient.result = undefined [undefined]
this.result = undefined [undefined]

===========

Можно ли сделать обход, так чтоб не требовалось вводить ограничение?
Помогите определить в каком месте происходит неявное создание наследника, у меня две версии:
1. Вот тут: for (var ch in obj){
2. Или тут при рекурсивном вызове: result += ObjWalker(tmp,count,name+"."+i.toString());

2

Re: JS: Неявное наследование объекта?

Что значит "неявное наследование" в данном случае? Может быть Вы имеете в виду циклические ссылки объектов друг на друга. Например:


var x = {};
var y = {};

x.y = y;
y.x = x;

var z = {};
z.z = z;

Можно ли сделать обход, так чтоб не требовалось вводить ограничение?

Теоретически - да. В том же jQuery.extend как-то делается клонирование объектов с циклическими ссылками. Задача для меня не особо актуальна, поэтому я и не пытаюсь разобраться, как это реализовано там.

Для себя я решил отслеживать явные ссылки "на себя" (как в z) и ограничивать некоторой глубиной вложенности по умолчанию, которую можно переопределять явно.

( 2 * b ) || ! ( 2 * b )

3

Re: JS: Неявное наследование объекта?

-red- пишет:

в каком месте происходит неявное создание наследника

-red-, я бы предпочел термин циклическая ссылка (iterative reference) или что-то в этом роде, поскольку, на мой взгляд, у Вас в коде всё происходит явно:

var pocient = this;

Что можно представить как:

this.pocient = this;

Иными словами, одно из свойств глобального объекта ссылается на самого себя. Для того, чтобы в данном случае избежать циклической ссылки, достаточно добавить проверку является ли свойство объекта самим объектом:

function ObjWalker(obj,count,name){
    var result = "";
    count = count + 1;
    // Ограничение итераций, иначе попытается скушать всю память или не будет работать - в зависимости от среды запуска.
    // if(count > 3) return name+": "+obj+" is limited ["+typeof obj+"]\n";
    if(null == obj) return name+"."+obj+" = null ["+typeof obj+"]\n";
    var tmp = null;
    for (var ch in obj){
        tmp = obj[ch];
        if( typeof tmp != "object" ){
            result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
        }else{
            result += name+"."+ch+" = "+tmp+" ["+typeof tmp+"]\n";
            // дополнительная проверка
            if(obj !== tmp){ 
                result += ObjWalker(tmp,count,name+"."+ch.toString());
            }else{
                result += "(iterative reference)\n";
            }
        tmp = null;
        }
    }
    if("" == result){
        return name+" "+obj+" is empty ["+typeof obj+"] \n"
    }
    return result;
}
var pocient1 = new Object();
var pocient = this;
var result  = "this:\n"+ObjWalker(pocient,0,"this")+"\n===========\n";
WScript.Echo(result);

Конечно, для более сложных циклических ссылок, состоящих из многих звеньев (как в примере Rumata), необходим более мощный и гибкий алгоритм проверки на цикличность. Оптимальным решением была бы запись всей цепочки "родословной" для каждого анализируемого объекта, и тогда в случае циклической ссылки любой сложности, анализ этой цепочки позволил бы выявить 2 последовательных повторяющихся отрезка - второй отрезок должен отсекаться, заменяться сообщением о начале циклической ссылки.

Щт Уккщк Куыгьу Туче
’ҐЄгй п Є®¤®ў п бва Ёж : 1251

4 (изменено: -red-, 2014-04-04 18:05:49)

Re: JS: Неявное наследование объекта?

Спасибо!

omegastripes пишет:

Что можно представить как:

this.pocient = this;

Иными словами, одно из свойств глобального объекта ссылается на самого себя.

Действительно, если первый вызов заменить на

var result  = "this:\n"+ObjWalker(this,0,"this")+"\n===========\n";

То циклическая ссылка не появляется.
Однако:
В HTA можно обратиться к объекту так или так:

<HTML>
<HEAD>
<HTA:APPLICATION ID="oHTA"/>
<SCRIPT>
    window.onload = function(){
        document.body.innerHTML = "<PRE id=oPre>"+
oHTA.attributes.onclick.ownerDocument.documentElement.firstChild.children.
oHTA.attributes.onclick.ownerDocument.documentElement.firstChild.children.
oHTA.commandLine
+"\n"+
oHTA.commandLine+"</PRE>";
    }
</SCRIPT>
</HEAD>

Изначально этот факт ввел меня в заблуждение.