Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

yaji - ещё один вариант наследования (WingedFox, оценка: 1)
Goto page 1, 2, 3  Next
Author Message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Tue Feb 19, 2008 6:51 pm (написано за 6 минут 28 секунд)
   Post subject: yaji - ещё один вариант наследования
Reply with quote

Дошли руки набросать свой вариант наследования, как оно могло бы быть реализовано на JS.
Ключевые особенности:
1. Свойства parent, self (this на момент создания), clazz (функция-конструктор) определяются как локальные переменные объекта.
2. Доступ к родительским методам идёт в естественном для JS стиле: parent.method.call(this) или apply(this).
3. Минимальное использование памяти: все родительские методы спокойно живут в своих прототипах.
4. Не перегруженные поля объекта копируются (клонируются) потомку.
5. Можно создать неограниченную вложенность объектов.

Код и пример работы:
Code (JavaScript): скопировать код в буфер обмена
function isFunction (prop) {
  return (typeof prop == 'function');
}
function cloneObject (obj) {
   if ('object' != typeof obj || null == obj) return obj;
   try { var newObject = new obj.constructor(); } catch(e) {return null;}
   if (newObject instanceof Array) {
       for (var i=0,oL=obj.length;i<oL;i++) {
           newObject[i] = cloneObject(obj[i]);
       }
   } else {
       for (var i in obj) {
           if (!obj.hasOwnProperty(i)) continue;
           newObject[i] = cloneObject(obj[i]);
       }
   }
   return newObject;
}
if ('undefined' == typeof Object.hasOwnProperty) {
  Object.prototype.hasOwnProperty = function (prop) {
    return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]);
  }
}

function extend (clazz,obj) {
    if ('function' != typeof clazz)
        clazz = function(){};

    var o = 'var clazz = arguments.callee, parent = arguments.callee.parent, self = this;\
             for (var i in clazz.ext) {\
                 if (!clazz.ext.hasOwnProperty(i)) continue;\
                 this[i] = cloneObject(clazz.ext[i]);\
             };\n'
;
    for (var i in obj) {
         if (!obj.hasOwnProperty(i) || !isFunction(obj[i])) continue;
         o += "this."+i+" = "+obj[i]+";\n";
         delete obj[i];
    }

    var q = new Function ('',o);
    q.prototype = new clazz;
    q.parent = q.prototype;

    if (q.prototype) {
        var qpe = q.prototype;
        for (var i in qpe) {
            if (obj[i]) continue;
            obj[i] = cloneObject(qpe[i]);
        }
    }
    q.ext = obj;
    return q;
}

var Vehicle = extend(function(){}, {
    fuel : 10
   ,place : [1,2,3,4]
   ,drive : function () {
       document.writeln('Vehicle::drive()');
   }
   ,fill : function (n) {
       document.writeln('Vehicle::fill('+n+') liter(s) of fuel');
       this.fuel = n;
   }
   ,set : function (n,m) {
       this.place[n] = m;
   }
   ,get : function (n) {
       return this.place[n];
   }
   ,getFuel : function () {
       document.writeln('Vehicle::getFuel() has '+this.fuel+' liter(s) of fuel');
       return this.fuel;
   }
})
var Zaporojets = extend(Vehicle, {
   expense : [7,6,5,5,4]
  ,drive : function (n) {
      window.status += this.fuel+" ";
       var ex = this.expense[n];
       document.writeln('Zaporojets::drive()  '+n+'th speed at '+ex+'liter/km.');
       document.writeln('Zaporojets will make '+Math.floor(this.fuel/ex)+' full km.');
       this.fuel = this.fuel - Math.floor(this.fuel/ex)*ex;
       parent.drive.call(this);
  }
})
var TunedZaporojets = extend(Zaporojets, {
  expense : [14,12,10,10,8],
  drive : function (n) {
       document.writeln('TunedZaporojets has 2 times higher fuel expense.');
       parent.drive.call(this,n);
  }
})

var tz = new TunedZaporojets;
var z = new Zaporojets;
document.write('<pre>');
document.writeln('Filling TunedZaporojets with 100 liters of fuel.');
tz.fill(100);
document.writeln('==========');
tz.drive(1);
document.writeln('==========');
z.getFuel();
z.drive(4);
document.writeln('==========');

var f1 = tz.getFuel();
document.writeln('TunedZaporojets has '+f1+' liters left.');
document.writeln('==========');
var f2 = z.getFuel();
document.writeln('Zaporojets has '+f2+' liters left.');
document.writeln('==========');

document.writeln('Filling brand old Vehicle with fuel.');
var v = new Vehicle;
v.fill(20);

document.writeln('==========');
document.writeln('Getting fuel from brand new TunedZaporojets.');
var ntz = new TunedZaporojets;
ntz.getFuel();

document.writeln('==========');
PS: после появления аббревиатуры 'yaji' решил посмотреть, что это могло бы значить: en.wikipedia.org/wiki/Yaji

Last edited by WingedFox on Tue Feb 19, 2008 7:53 pm; edited 1 time in total
Back to top
View user's profile Send private message
Andrey Mindubaev
Участник форума



Joined: 27 Jun 2007
Posts: 34
Карма: 2
   поощрить/наказать

Location: Горький-Московский

PostPosted: Tue Feb 19, 2008 7:35 pm (спустя 43 минуты; написано за 1 минуту 27 секунд)
   Post subject:
Reply with quote

А не работает. Точнее работает, но не так:
Code (JavaScript): скопировать код в буфер обмена
var Class1 = extend(function() {}, {
  Func1: function() {
    alert("1.1");
    self.Func2();
  },
  Func2: function() {
    alert("1.2");
    this.Var1 = 1;
  }
});

var Class2 = extend(Class1, {
  Func1: function() {
    alert("2.1");
    parent.Func1();
  },
  Func2: function() {
    alert("2.2");
    parent.Func2();
  }
});

var Obj2 = new Class2();
Obj2.Func1(); // должно быть 4 алерта: 2.1, 1.1, 2.2, 1.2

var Obj2_1 = new Class2();
alert(Obj2_1.Var1); // должно быть undefined
 
Имхо, самый главный недостаток метода - это невозможность отладки.
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Tue Feb 19, 2008 7:43 pm (спустя 8 минут; написано за 4 минуты 16 секунд)
   Post subject:
Reply with quote

Andrey Mindubaev
Всё работает правильно.
1. self позволяет обращаться к переменным класса, независимо от this. Что и происходит (3 алерта)
2. про .call и .apply я упомянул не просто так
3. в реальной разработке никто не создаёт произвольные поля
4. Отладка вполне возможна

PS: кстати, это вполне себе достоинство - нефиг любителям reverse-engineeringа в коде копаться =)
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Tue Feb 19, 2008 7:45 pm (спустя 2 минуты; написано за 10 секунд)
   Post subject:
Reply with quote

Code (JavaScript): скопировать код в буфер обмена
var Class1 = extend(function() {}, {
  Func1: function() {
    alert("1.1");
    this.Func2();
  },
  Func2: function() {
    alert("1.2");
    this.Var1 = 1;
  }
});

var Class2 = extend(Class1, {
  Func1: function() {
    alert("2.1");
    parent.Func1.call(this);
  },
  Func2: function() {
    alert("2.2");
    parent.Func2.call(this);
  }
});

var Obj2 = new Class2();
Obj2.Func1(); //

var Obj2_1 = new Class2();
alert(Obj2_1.Var1); //
 
Back to top
View user's profile Send private message
Andrey Mindubaev
Участник форума



Joined: 27 Jun 2007
Posts: 34
Карма: 2
   поощрить/наказать

Location: Горький-Московский

PostPosted: Tue Feb 19, 2008 8:04 pm (спустя 19 минут; написано за 3 минуты 29 секунд)
   Post subject:
Reply with quote

WingedFox wrote:
2. про .call и .apply я упомянул не просто так
А! Я не заметил. Вобщем, тест "на дурака" не пройден =)
WingedFox wrote:
4. Отладка вполне возможна
У меня не получилось посмотреть почему не работает мой скрипт в FireBug - от части по этому я и поторопился отрапортовать.
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Tue Feb 19, 2008 8:08 pm (спустя 3 минуты; написано за 52 секунды)
   Post subject:
Reply with quote

Andrey Mindubaev wrote:
У меня не получилось посмотреть почему не работает мой скрипт в FireBug
Да... подловили файрбагу =)
Всё-таки, это скорее фича, нежели бага =)
Back to top
View user's profile Send private message
Andrey Mindubaev
Участник форума



Joined: 27 Jun 2007
Posts: 34
Карма: 2
   поощрить/наказать

Location: Горький-Московский

PostPosted: Tue Feb 19, 2008 8:32 pm (спустя 23 минуты; написано за 1 минуту 6 секунд)
   Post subject:
Reply with quote

WingedFox wrote:
3. Минимальное использование памяти: все родительские методы спокойно живут в своих прототипах.
За то свои методы живут далеко не в прототипе =)
Code (JavaScript): скопировать код в буфер обмена
var Class1 = extend(function() {}, {
  Func1: function() {
    alert(clazz);
  }
});
var Obj2 = new Class1();
Obj2.Func1();
Code (JavaScript): скопировать код в буфер обмена
function anonymous() {
    var clazz = arguments.callee, parent = arguments.callee.parent, self = this;
    for (var i in clazz.ext) {
        if (!clazz.ext.hasOwnProperty(i)) {
            continue;
        }
        this[i] = cloneObject(clazz.ext[i]);
    }
    this.Func1 = function () {alert(clazz);};
}
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Tue Feb 19, 2008 8:34 pm (спустя 2 минуты; написано за 52 секунды)
   Post subject:
Reply with quote

Andrey Mindubaev
Именно так оно и фунициклирует, всё верно.
Своим методам нефиг делать в прототипе. Что, кстати, совсем не мешает им жить в других прототипах.
Back to top
View user's profile Send private message
Andrey Mindubaev
Участник форума



Joined: 27 Jun 2007
Posts: 34
Карма: 2
   поощрить/наказать

Location: Горький-Московский

PostPosted: Tue Feb 19, 2008 10:39 pm (спустя 2 часа 4 минуты; написано за 1 минуту 34 секунды)
   Post subject:
Reply with quote

Quote:
Именно так оно и фунициклирует, всё верно.
Своим методам нефиг делать в прототипе. Что, кстати, совсем не мешает им жить в других прототипах.
WingedFox, ну тогда Вам шах (сдавайтесь =)
Code (JavaScript): скопировать код в буфер обмена
var Class1 = extend(function() {}, {
  Func1: function() {
    return {
      self: self,
      clazz: clazz
    }
  }
});
var Class2 = extend(Class1, {});

var Obj2 = new Class1();
var Obj3 = new Class2();

alert(Obj2.Func1().clazz == Obj3.Func1().clazz); // -> true /* это точно баг =)              */
alert(Obj3.Func1().clazz == Class1); // -> true             /* это причина                   */
alert(Obj3.Func1().self == Obj3); // -> false               /* и ещё один баг, самый главный */
 
Переменные clazz и self использовать нельзя! И всё из-за замыкания, в котором живут все неперекрытые функции класса.
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Tue Feb 19, 2008 10:57 pm (спустя 18 минут; написано за 2 минуты 58 секунд)
   Post subject:
Reply with quote

Andrey Mindubaev
Вы что-то странное делаете.
Результат вполне логичен, поскольку Вы получаете clazz и self из Class1. Геттера в Class2 для них нет, а методы родителя не могут иметь доступ к приватным переменным потомка.

Вы бы ещё добавили
Code (JavaScript): скопировать код в буфер обмена
Func2 : function () {
    return self == this;
}
и пожаловались, что возвращается false =)
Back to top
View user's profile Send private message
Andrey Mindubaev
Участник форума



Joined: 27 Jun 2007
Posts: 34
Карма: 2
   поощрить/наказать

Location: Горький-Московский

PostPosted: Tue Feb 19, 2008 11:16 pm (спустя 19 минут; написано за 1 минуту 6 секунд)
   Post subject:
Reply with quote

WingedFox
Да ладно Вам, перестаньте - если это не баг, то значит в этой фиче должен быть какой-то смысл !
Back to top
View user's profile Send private message
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Tue Feb 19, 2008 11:23 pm (спустя 6 минут; написано за 5 минут 57 секунд)
   Post subject:
Reply with quote

я тут поэкспериментировал на тему forum.dklab.ru/viewtopic.php?p=55543#55543
естественно, я сильно упростил "оригинал"

1. исходная библиотека WingedFox
2. немного кроссплатформенного "сахара"
Code (JavaScript): скопировать код в буфер обмена
/**
 * Little sugar for useful usage within various environment
 */

try {
        WSH_CORE = Boolean(window);
} catch (e) {
        WSH_CORE = true;
}


ASSERT = ( WSH_CORE ) ?

        function(string)
        {
                return WScript.Echo(string);
        }

:

        function(string)
        {
                return document.writeln(string);
        }

;
3. Стреляющее оружие, хватающая рука и шагающая нога
иерархия наследования
Quote:
нечто
    |--- ружье
    |--- конечность
                  |--- рука
                  |--- нога
Code (JavaScript): скопировать код в буфер обмена
/**
 * Gun-holding arm
 * Shooted leg
 * Shooting short-gun
 */

var Thing = extend(function() {}, {

        make: function(thing)
        {
        },

        myself: function()
        {
                return 'Thing';
        }

});

var Extremity = extend(Thing, {

        phalanx: 0,

        flex: function(thing, unbend)
        {
                var s = this.phalanx + ' phalanxes has been ';
                if ( unbend ) {
                        s += 'un';
                }
                s += 'bent around the ' + thing.myself() + '. ';
                ASSERT(s);
        },

        make: function(thing)
        {
                this.flex.call(this, thing, ! thing);
        },

        myself: function()
        {
                return 'Extremity';
        }

});

var Hand = extend(Extremity, {

        phalanx: 16,

        make: function(thing)
        {
                ASSERT('The ' + this.myself() + ' has catched the ' + thing.myself() + '. ');
                parent.make.call(this, thing);
        },

        myself: function()
        {
                return 'Hand';
        }

});

var Foot = extend(Extremity, {

        phalanx: 14,

        make: function(thing)
        {
                ASSERT('The ' + this.myself() + ' walks. ');
        },

        myself: function()
        {
                return 'Foot';
        }

});

var Gun = extend(Thing, {

        make: function(thing)
        {
                ASSERT('The ' + this.myself() + ' is shooting to the ' + thing.myself() + '. ');
        },

        myself: function()
        {
                return 'Gun';
        }

});
4. и сама детективная история
Code (JavaScript): скопировать код в буфер обмена
/**
 * Examples
 */

var gun = new Gun();
var hand = new Hand();
var foot = new Foot();


foot.make();
hand.make(gun);
gun.make(foot);


Last edited by Rumata on Tue Feb 19, 2008 11:34 pm; edited 1 time in total
Back to top
View user's profile Send private message
Rumata
Профессионал



Joined: 17 Aug 2003
Posts: 1850
Карма: 184
   поощрить/наказать


PostPosted: Tue Feb 19, 2008 11:25 pm (спустя 2 минуты; написано за 41 секунду)
   Post subject:
Reply with quote

cscript wrote:
The Foot walks.
The Hand has catched the Gun.
16 phalanxes has been bent around the Gun.
The Gun is shooting to the Foot.
я не следил за корректностью английской "речи".
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 12:02 am (спустя 37 минут; написано за 1 минуту 7 секунд)
   Post subject:
Reply with quote

Andrey Mindubaev
Фича вполне правильная.
self используется когда класс должен быть уверен, что будет вызван метод этого же класса, а не какой-нибудь потомок.
clazz пока что не используется нигде =)
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 12:03 am (спустя 39 секунд; написано за 10 секунд)
   Post subject:
Reply with quote

Rumata
Насколько я вижу, отработало корректно =)
Back to top
View user's profile Send private message
Andrey Mindubaev
Участник форума



Joined: 27 Jun 2007
Posts: 34
Карма: 2
   поощрить/наказать

Location: Горький-Московский

PostPosted: Wed Feb 20, 2008 1:16 am (спустя 1 час 13 минут; написано за 4 минуты 6 секунд)
   Post subject:
Reply with quote

WingedFox
Code (JavaScript): скопировать код в буфер обмена
var Class1 = extend(function() {}, {
    pNumber: 1
});

var Class2 = extend(Class1, {
    pNumber: 0
});

var Obj1 = new Class2();
alert(Obj1.pNumber); // -> 1
 
Ну и не работает в IE6 (потому что super - это зарезервированное слово) и в Safari (пёс его знает почему - у меня не получилось приделать инструменты для разработчика)

Я считаю, что будет справедливым хотябы один раз переделать! Ведь этот форум не Склад готовых решений =))
Кстати, а зачем Вы используете cloneObject ?
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 1:28 am (спустя 11 минут; написано за 2 минуты 20 секунд)
   Post subject:
Reply with quote

Andrey Mindubaev wrote:
Ну и не работает в IE6
Это было пофиксано
Quote:
Tue 19 Feb, 2008 19:53;
Под сафарей не работало под той же причине.

cloneObject нужен для того, чтобы объекты сохраняли свои свойства на момент определения класса. Без него возможна ситуация, когда в свойствах окажется совсем не то, что ожидается.
Back to top
View user's profile Send private message
Andrey Mindubaev
Участник форума



Joined: 27 Jun 2007
Posts: 34
Карма: 2
   поощрить/наказать

Location: Горький-Московский

PostPosted: Wed Feb 20, 2008 1:39 am (спустя 11 минут; написано за 1 минуту 11 секунд)
   Post subject:
Reply with quote

WingedFox wrote:
cloneObject нужен для того, чтобы объекты сохраняли свои свойства на момент определения класса. Без него возможна ситуация, когда в свойствах окажется совсем не то, что ожидается.
У меня в моём проекте у самого корневого "класса" в прототипе есть свойство __common, которому в самом начале присваивается new Object().
На странице PHP генерит код, который заполняет это свойство какими-то значениями. И самое интересное в том, что эти значения доступны для всех объектов, созданных на основе какого-либо "класса", как this.__common.[имя] - имхо, это очень удобно (правда я только недавно это придумал, поэтому __common используется не на полную катушку)
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 1:49 am (спустя 10 минут; написано за 2 минуты 14 секунд)
   Post subject:
Reply with quote

Andrey Mindubaev
Посмотрите forum.dklab.ru/viewtopic.php?p=151051#151051 и ниже.

Проблема в том, что вызов
Code (JavaScript): скопировать код в буфер обмена
field.splice(0,field.length);
поломает все прочие объекты, которые могут рассчитывать на наличие данных в этом массиве.
Back to top
View user's profile Send private message
Andrey Mindubaev
Участник форума



Joined: 27 Jun 2007
Posts: 34
Карма: 2
   поощрить/наказать

Location: Горький-Московский

PostPosted: Wed Feb 20, 2008 2:13 am (спустя 24 минуты; написано за 5 секунд)
   Post subject:
Reply with quote

WingedFox
Я думаю, я понял о чём Вы.
Понятное дело, что объект в прототипе класса будет одним на все объекты, построенные на его основе - тут и спорить нечего. Я просто не считаю, что это нужно исправлять. Нужно этим пользоваться!
Видимо проблема в том, что у вас не предусмотрена функция "инициализатор" объекта - по типу initialize в prototype.js - в ней можно было бы записать в this все необходимые свойства-объекты и одновременно пользоваться объектами в прототипах классов.
Back to top
View user's profile Send private message
Guest






Карма: 388
   поощрить/наказать


PostPosted: Wed Feb 20, 2008 9:38 am (спустя 7 часов 24 минуты; написано за 19 секунд)
   Post subject:
Reply with quote

> clazz (функция-конструктор)
а чем стандартный constructor не угодил?
Back to top
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 12:31 pm (спустя 2 часа 52 минуты; написано за 3 минуты 14 секунд)
   Post subject:
Reply with quote

Andrey Mindubaev
Одно другому не мешает, можно добавить и _constructor, и _destructor и любых других зверей.
Вопрос в том: зачем это делать.
Andrey Mindubaev wrote:
Нужно этим пользоваться!
Личные данные класса и общие надо отделять друг от друга. Как - отдельный вопрос.

Guest
Добавьте
Code (JavaScript): скопировать код в буфер обмена
alert([this.constructor,clazz].join("\n\n"));
в любой метод и посмотрите что получится.
Back to top
View user's profile Send private message
Zeroglif
Участник форума



Joined: 02 Jan 2006
Posts: 293
Карма: 61
   поощрить/наказать


PostPosted: Wed Feb 20, 2008 1:12 pm (спустя 41 минуту; написано за 29 секунд)
   Post subject:
Reply with quote

WingedFox wrote:
и посмотрите что получится
Родной прототип переопределён, поэтому свойство constructor как бы "чужое", можно было бы восстановить своё:
Code (JavaScript): скопировать код в буфер обмена
q.prototype.constructor = q;
Пара вопросов: А зачем в тело функции q попадают удалённые позже методы (собственные), а остальные свойства висят на объекте q.ext? В чём идея? И почему объект q.ext "подсасывает" в себя ещё и свойства прототипа? Результирующая картина выходит немного странная - имеем "функцию-конструктор", которая не cформирована сразу, а держит ссылку на объект, опрашиваемый при каждом создании экземпляра. Одновременно с этим, при создании экземпляра наследуемые от ближнего прототипа свойства перекрываются собственными одноимёнными свойствами. Для чего?
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 1:34 pm (спустя 21 минуту; написано за 14 минут 2 секунды)
   Post subject:
Reply with quote

Zeroglif
Можно и восстановить конструктор. Этот код был написан часа за 1.5, так что есть где пройтись напильником.
Zeroglif wrote:
А зачем в тело функции q попадают удалённые позже методы (собственные)
Затем, что
1) Надо было как-то определить приватные parent, self, clazz. Наиболее логичным решением для меня является перекомпиляция методов в контексте новой обёртки - класса. Без этого надо как-то иначе сохранять "свой" контекст. (i.e. обёртки типа method.parent())
Удаляются они из .ext для того, чтобы не перекрывали откомпилированные методы.
2) Чтобы целиком сконструировать класс надо написать .toSource, чтобы можно было собирать не только функции и литералы, но и массивы, и произвольные объекты. Это было делать просто лениво 8*)
В результате, в .ext лежат объекты и свойства в состоянии на момент создания класса, которые в момент создания экземпляра копируются в его свойства. Кроме того, ext выполняет функции "репозитория" из которого берутся недостающие потомку свойства.
3) Копирование потомку свойств происходит для того, чтобы они не конфликтовали между собой когда будут обращаться к сложным свойствам родителя (i.e. родитель имеет arr=[1,2,3,4,5,6], а потомок скажет this.arr[1] = 1000, на чём может споткнуться другой экземпляр потомка). В принципе скалярные свойства можно вынести из .ext, потому как при записи значения оно будет переопределено у потомка, а не обновлено на родителе.
Back to top
View user's profile Send private message
Zeroglif
Участник форума



Joined: 02 Jan 2006
Posts: 293
Карма: 61
   поощрить/наказать


PostPosted: Wed Feb 20, 2008 2:48 pm (спустя 1 час 13 минут; написано за 13 секунд)
   Post subject:
Reply with quote

WingedFox wrote:
Надо было как-то определить приватные parent, self, clazz.
Надо было мне поточнее спросить - с функциями-то понятно, но почему все свойства сразу не вырисовываются в теле. Вы говорите, что нужен объект, "из которого берутся недостающие потомку свойства". Недостающие в каком смысле? Пример бы.
WingedFox wrote:
Копирование потомку свойств происходит для того, чтобы они не конфликтовали между собой когда будут обращаться к сложным свойствам родителя
Роль прототипа тогда никакая, только чтобы с него свойства слить и оставить в виде объекта, "из которого берутся недостающие потомку свойства". ;)
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 3:02 pm (спустя 13 минут; написано за 9 минут 17 секунд)
   Post subject:
Reply with quote

Zeroglif wrote:
почему все свойства сразу не вырисовываются в теле
1)
WingedFox wrote:
2) Чтобы целиком сконструировать класс надо написать .toSource, чтобы можно было собирать не только функции и литералы, но и массивы, и произвольные объекты. Это было делать просто лениво 8*)
2) сложные свойства (typeof == object) будут расшарены между всеми потомками.
Zeroglif wrote:
Пример бы.
В первом примере у Zaporojets есть свойство expense, определяющее расход топлива на определённой передаче.
Если не скопировать это свойство в класс TunedZaporojets, то
Code (JavaScript): скопировать код в буфер обмена
this.expense.splice(0,this.expense.length);
сломает все существующие и новые тюненые запорожцы.
Если же оно скопировано, то сломается только один экземпляр.
Zeroglif wrote:
Роль прототипа тогда никакая,
Роль прототипа - хранение методов родителя. Можно там же хранить и скалярные свойства.
Back to top
View user's profile Send private message
Zeroglif
Участник форума



Joined: 02 Jan 2006
Posts: 293
Карма: 61
   поощрить/наказать


PostPosted: Wed Feb 20, 2008 3:12 pm (спустя 10 минут; написано за 20 секунд)
   Post subject:
Reply with quote

WingedFox wrote:
Это было делать просто лениво 8*)
OK OK
WingedFox wrote:
сломает все существующие и новые тюненые запорожцы
Ради отдельного случая перекрывать наследуемые свойства разом? Нестандартный подход.
WingedFox wrote:
Роль прототипа - хранение методов родителя.
Методы вы тоже копируете в экземпляр.
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 3:23 pm (спустя 10 минут; написано за 3 минуты 45 секунд)
   Post subject:
Reply with quote

Zeroglif wrote:
Ради отдельного случая перекрывать наследуемые свойства разом?
Ради того, чтобы не писать себе большую простыню "исключительных ситуациеф".
Тем более, если кто-то станет этот код использовать...
Zeroglif wrote:
Методы вы тоже копируете в экземпляр.
Можно подробнее?
После создания текстового представления метод из .ext удаляется и дальше фигурирует только в прототипе.
Можете добавить
Code (JavaScript): скопировать код в буфер обмена
    o+="alert(clazz);"
перед new Function и посмотреть результат.
Back to top
View user's profile Send private message
Zeroglif
Участник форума



Joined: 02 Jan 2006
Posts: 293
Карма: 61
   поощрить/наказать


PostPosted: Wed Feb 20, 2008 3:38 pm (спустя 14 минут; написано за 21 секунду)
   Post subject:
Reply with quote

WingedFox wrote:
Можно подробнее?
Насколько я вижу, вот в этот момент:
Code (JavaScript): скопировать код в буфер обмена
for (var i in qpe) {
вы обходите все свойства (свои, наследуемые) прототипа (q.prototype) и копируете их в ext. Далее при создании экземпляра все эти свойства становятся "собственными" свойствами экземпляра. Таким образом, свойства прототипа перекрыты, наследование уплыло...
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 3:44 pm (спустя 6 минут; написано за 2 минуты 28 секунд)
   Post subject:
Reply with quote

Zeroglif
Копируются только свойства, которые сами по себе совершенно не интересны (ну за исключением контейнерных объектов).
Наследование предполагает наследование функционала, а не данных.

Т.е. всё работает ровно так, как и в классическом наследовании:
1) после создания объекта ему доступны изначальные значения свойств
2) изменение любого свойства не влияет на другие объекты
Back to top
View user's profile Send private message
Zeroglif
Участник форума



Joined: 02 Jan 2006
Posts: 293
Карма: 61
   поощрить/наказать


PostPosted: Wed Feb 20, 2008 3:57 pm (спустя 12 минут; написано за 3 минуты 37 секунд)
   Post subject:
Reply with quote

WingedFox wrote:
Копируются только свойства
Code (JavaScript): скопировать код в буфер обмена
var class1 = extend(0, {p1: 'p1', f1: function(){}});
class1.prototype = {inh_p1: 'inh_p1', inh_f1: function(){}};

var class2 = extend(class1, {p2: 'p2', f2: function(){}});

var c1 = new class1;
var c2 = new class2;
Вопрос - есть три свойства (f1, inh_f1, f2), какие из них будут унаследованы экземпляром с2, а какие станут собственными свойствами экземпляра с2?
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Wed Feb 20, 2008 4:15 pm (спустя 18 минут; написано за 1 минуту 53 секунды)
   Post subject:
Reply with quote

Zeroglif
Блин, трудно сказать что бага в наличии? =)

Теперь в ext лежат только объекты (typeof == 'object')
Code (JavaScript): скопировать код в буфер обмена
function cloneObject (obj) {
   if ('object' != typeof obj || null == obj) return obj;
   try { var newObject = new obj.constructor(); } catch(e) {return null;}
   if (newObject instanceof Array) {
       for (var i=0,oL=obj.length;i<oL;i++) {
           newObject[i] = cloneObject(obj[i]);
       }
   } else {
       for (var i in obj) {
           if (!obj.hasOwnProperty(i)) continue;
           newObject[i] = cloneObject(obj[i]);
       }
   }
   return newObject;
}
if ('undefined' == typeof Object.hasOwnProperty) {
  Object.prototype.hasOwnProperty = function (prop) {
    return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]);
  }
}

function extend (clazz,obj) {
    if ('function' != typeof clazz)
        clazz = function(){};

    var o = 'var clazz = arguments.callee, parent = arguments.callee.parent, self = this;\
             for (var i in clazz.ext) {\
                 if (!clazz.ext.hasOwnProperty(i)) continue;\
                 this[i] = cloneObject(clazz.ext[i]);\
             };\n'
;
    for (var i in obj) {
         if (!obj.hasOwnProperty(i) || 'object' == typeof obj[i]) continue;
         o += "this."+i+" = "
             +(('string' == typeof obj[i])?"'"+obj[i].replace(/'/g,"\\'")+"'"
                                          :obj[i])
             +";\n";
         delete obj[i];
    }

    var q = new Function ('
',o);
    q.prototype = new clazz;
    q.parent = q.prototype;

    if (q.prototype) {
        var qpe = q.prototype;
        for (var i in qpe) {
            if (obj[i] || '
object' != qpe[i]) continue;
            obj[i] = cloneObject(qpe[i]);
        }
    }
    q.ext = obj;
    return q;
}
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Mon Feb 25, 2008 10:34 am (спустя 4 дня 18 часов 18 минут; написано за 5 минут 15 секунд)
   Post subject:
Reply with quote

Zeroglif
Тут пришло в голову, что моя последняя фраза может быть воспринята совсем не так, как я её себе представляю. Извините, и спасибо за помощь в отлове этой баги. Я был до последнего уверен, что разговор идёт об идеологической части.

Новая версия скрипта с реализованным конструктором:
Code (JavaScript): скопировать код в буфер обмена
function cloneObject (obj) {
   if ('object' != typeof obj || null == obj) return obj;
   try { var newObject = new obj.constructor(); } catch(e) {return null;}
   if (newObject instanceof Array) {
       for (var i=0,oL=obj.length;i<oL;i++) {
           newObject[i] = cloneObject(obj[i]);
       }
   } else {
       for (var i in obj) {
           if (!obj.hasOwnProperty(i)) continue;
           newObject[i] = cloneObject(obj[i]);
       }
   }
   return newObject;
}
if ('undefined' == typeof Object.hasOwnProperty) {
  Object.prototype.hasOwnProperty = function (prop) {
    return !('undefined' == typeof this[prop] || this.constructor && this.constructor.prototype[prop] && this[prop] === this.constructor.prototype[prop]);
  }
}

function extend (clazz,obj) {
    if ('function' != typeof clazz)
        clazz = function(){};
    var _c = '_constructor'
       ,ex = '_extending'

    var o = 'var clazz = arguments.callee, parent = arguments.callee.parent, self = this;\
             for (var i in clazz.ext) {\
                 if (!clazz.ext.hasOwnProperty(i)) continue;\
                 this[i] = cloneObject(clazz.ext[i]);\
             };\n'
;

    for (var i in obj) {
         if (!obj.hasOwnProperty(i) || 'object' == typeof obj[i]) continue;

         o += "this."+i+" = "
             +(('string' == typeof obj[i])?"'"+obj[i].replace(/'/g,"\\'")+"'"
                                          :obj[i])
             +";\n";
         delete obj[i];
    }
    o += '
if (\'function\' != typeof self.'+_c+') this.'+_c+' = function(){};\n';
    o += 'if (!clazz.'+ex+' && \'function\' == typeof self.'+_c+') self.'+_c+'.apply(this,arguments);\n';

    var q = new Function ('',o);
    clazz[ex] = true;
    q.prototype = new clazz;
    q.parent = q.prototype;
    delete (clazz[ex]);

    if (q.prototype) {
        var qpe = q.prototype;
        for (var i in qpe) {
            if (obj[i] || 'object' != qpe[i]) continue;
            obj[i] = cloneObject(qpe[i]);
        }
    }
    q.ext = obj;
    return q;
}
Конструктор вызывается автоматически с аргументами переданными new, за исключением создания экземпляров в extend.
Родительский конструктор вызывается как parent._constructor.call(this)
Back to top
View user's profile Send private message
alexkunin
Участник форума



Joined: 25 Feb 2006
Posts: 113
Карма: 11
   поощрить/наказать


PostPosted: Sat Mar 01, 2008 2:17 pm (спустя 5 дней 3 часа 43 минуты; написано за 15 минут 1 секунду)
   Post subject:
Reply with quote

Кажется, у вас в следующей строке пропущен typeof:
Code (JavaScript): скопировать код в буфер обмена
if (obj[i] || 'object' != qpe[i]) continue;
А в последних строках генереного кода вы проверяете, а может self._constructor не функция, и делаете ее функцией. В следующей строке снова проверяете, не функция ли.

Простите грешного, осмелился почистить ваш код (еще один пардон за стилизацию):
Code (JavaScript): скопировать код в буфер обмена
function extend(clazz, obj) {
    if ('function' != typeof clazz) {
        clazz = function () {};
    }

    var q = function () {
        var clazz = arguments.callee,
            parent = arguments.callee.prototype,
            self = this;

        for (var i in obj) {
            if (obj.hasOwnProperty(i)) {
                this[i] = 'function' == typeof obj[i] ?
                    eval('(' + obj[i] + ')') : cloneObject(obj[i]);
            }
        }

        if ('function' != typeof this._constructor) {
            this._constructor = function () {};
        }

        if (this._extending) {
            this._constructor.apply(this, arguments);
        }
    };

    clazz._extending = true;
    q.prototype = new clazz();
    delete clazz._extending;

    return q;
}
Мои ИМХО:
  1. Решение с перезамыканием - в самом деле очень интересно, пока нигде такого не видел и сам не додумался.
  2. Городить строку с телом конструктора не стоит, потому что весь перфоманс съедает перезамыкание каждого метода, зато читабельность падает в разы.
  3. При перезамыкании теряются все МОИ замыкания на неглобальные, определенные за рамками extend().
  4. Вы просто копируете все нескалярное, без разбору, всегда рекурсивно. Я бы повесил эту ответственность на юзера: вот, мол, тебе cloneObject в руки, копируй в своем конструкторе что душе угодно и на произвольную глубину. А то ведь не дай Бог кто-то в проперти сохранил ссылку на window или document...
В итоге, плюсом метода является изящное перезамыкание - удобно и симпатично смотрится юзерский код. Минусами являются огромный удар по перфомансу и пренебрежение чужими замыканиями. Если в проекте объекты создаются не очень часто, а свои замыкания используются ограниченно, то красота решения стоит всех минусов. В других же типах проектов лучше воспользоваться каким-нибудь вычислительным способом, вроде this.callParent('methodName', arg1, arg2, arg3).

Еще я бы сделал некий объект, представляющий собой сам класс, т.е. чтобы можно было лепить наследование так:
Code (JavaScript): скопировать код в буфер обмена
//
var MyObj = extend.call({}, {
    ...
});

var Vehicle = MyObj.extend({
    ...
});

var Zaporozhets = Vehicle.extend({
    ...
});

var TunedZaporozhets = Zaporozhets.extend({
    ...
});
Back to top
View user's profile Send private message Send e-mail
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Sat Mar 01, 2008 4:59 pm (спустя 2 часа 42 минуты; написано за 17 минут 3 секунды)
   Post subject:
Reply with quote

alexkunin wrote:
пропущен typeof
Да, потерялся.
Спасибо.
alexkunin wrote:
Вы просто копируете все нескалярное, без разбору, всегда рекурсивно.
У меня поддержка произвольных объектов чисто символическая, дабы можно было использовать хеши и они не конфликтовали в нескольких экземплярах одного класса. В принципе, согласен: вызов cloneObject на момент конструирования можно спокойно убрать.

Кстати, в "стилизованном" коде эта проблема никак не решена. ;-)
alexkunin wrote:
Минусами являются огромный удар по перфомансу и пренебрежение чужими замыканиями.
Такие фразы имеет смысл подтверждать кодом.

В проектах с созданием большого количества объектов мой вариант куда выгоднее по производительности в силу следующих причин:
1. тело функции-конструктора формируется один раз в момент создания нового класса, против перманентного вызова eval в Вашем коде.
2. обычно хэши содержат небольшие объёмы данных на момент объявления класса и, напротив, относительно большок количество скаляров. В результате, мой код обрабатывает и эту ситуацию значительно эффективнее, поскольку каждый new вызывает минимум итераций по свойствам.
alexkunin wrote:
Городить строку с телом конструктора не стоит, потому что весь перфоманс съедает перезамыкание каждого метода, зато читабельность падает в разы.
Смысл этого предложения я не понял.
В частности, откуда возьмётся "локальное перезамыкание" в случае объявления функции в явном виде, как поле объекта?
Случаи динамического создания объектов перед тем, как довесить к ним наследование можно рассматривать как клинические, поскольку порядок действий всегда имеет значение.
alexkunin wrote:
Еще я бы сделал некий объект
Так сделайте.
Я не вижу в этом особого смысла, поскольку ради сомнительной удобности придётся вводить некие посторонние сущности.
Посмотрите реализацию base2, где сие видно очень хорошо.
Back to top
View user's profile Send private message
alexkunin
Участник форума



Joined: 25 Feb 2006
Posts: 113
Карма: 11
   поощрить/наказать


PostPosted: Sat Mar 01, 2008 5:27 pm (спустя 28 минут; написано за 34 минуты 26 секунд)
   Post subject:
Reply with quote

WingedFox wrote:
Кстати, в "стилизованном" коде эта проблема никак не решена. ;-)
Я именно стилизовал. Взял за основу вывод вашего примера - ну вроде как тест на регрессию, и переписал более понятным мне языком. Ну, и сократил по ходу дела, понял (вроде) сам принцип вашего предложения.
WingedFox wrote:
1. тело функции-конструктора формируется один раз в момент создания нового класса, против перманентного вызова eval в Вашем коде.
Да, вы правы, я неправильно "рефакторнул" и неправильно выразился, причем преувеличил перфоманс хит. Но он все же есть, хоть и не такой заметный, как при эвале. Тело конструктора получается довольно объемное, при этом завязано на замыканиях, а это нездорово. В одном из проектов сначала перешел на такие вот замыкания (объектов создавалось множество), затем убрал замыкания и добавил поля к this, при этом перфоманс вырос очень значительно. Наверное, имеет смысл сделать тест: нативное наследование без использования замыканий, конструктор с замыканиями (т.е. ваш метод в развороте) и собственно ваш метод.
WingedFox wrote:
Смысл этого предложения я не понял.
В частности, откуда возьмётся "локальное перезамыкание" в случае объявления функции в явном виде, как поле объекта?
Под перезамыканием я имел в виду тот факт, что вы берете функцию в виде исходного кода (т.е. теряется ее изначальный контекст) и перекомпилируете ее в своем контексте, в котором добавляете свои замыкания. Практика показала, что вот эти так называемые protected methods замедляют создание новых экземпляров (писал выше, чисел предоставить не могу - нужно написать тест).
WingedFox wrote:
Так сделайте.
Себе я сделал, собой доволен. :) А в "перестилизацию" добавление такой фичи передалало бы в "развитие вашего кода". Говорю ж, я просто перевыразил его (как вижу теперь, не вполне удачно).

Если говорить о посторонних сущностях, то сама попытка реализовать классическое наследование - лишняя. Но бывает так, что нужно. У вас и так уже есть неявный этот самый объект класса - его код "вшит" в конструктор. Переменные ex и _c также были лишними сущностями, мешающими читабельности. Добавление и удаление свойства с имемем ex - тоже.

А над eval() нужно подумать, чем сейчас и займусь. Наверное, и тест нужно написать сразу.

Добавка: "пренебрежение чужими замыканиями" вроде как не требует подтверждения кодом, ведь так? Если замыкается неглобальная переменная, определенная не внутри метода, то замыкание теряется.
Back to top
View user's profile Send private message Send e-mail
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Sat Mar 01, 2008 6:10 pm (спустя 42 минуты; написано за 4 минуты 47 секунд)
   Post subject:
Reply with quote

alexkunin wrote:
Если замыкается неглобальная переменная, определенная не внутри метода, то замыкание теряется.
На это я ответил выше:
WingedFox wrote:
Случаи динамического создания объектов перед тем, как довесить к ним наследование можно рассматривать как клинические, поскольку порядок действий всегда имеет значение.
alexkunin wrote:
Под перезамыканием я имел в виду тот факт, что вы берете функцию в виде исходного кода (т.е. теряется ее изначальный контекст) и перекомпилируете ее в своем контексте, в котором добавляете свои замыкания. Практика показала, что вот эти так называемые protected methods замедляют создание новых экземпляров (писал выше, чисел предоставить не могу - нужно написать тест).
Вот это и хочется увидеть "живьём", поскольку создаётся самая обычная динамическая функция, при вызове new не имеющая никакого оверхеда в случае отсутсвия тяжелых вложенных объектов.
alexkunin wrote:
Добавление и удаление свойства с имемем ex - тоже.
Имеется в виду ext?
Это свойство было введено по той причине, что много раз встречал буквально такой код:
Code (any language): скопировать код в буфер обмена
var obj = {
  'a' : 1
 ,'b' : 2
}
extend(class1,obj);
obj.c = 3;
extend(class2.obj);
Back to top
View user's profile Send private message
alexkunin
Участник форума



Joined: 25 Feb 2006
Posts: 113
Карма: 11
   поощрить/наказать


PostPosted: Sat Mar 01, 2008 6:48 pm (спустя 37 минут; написано за 17 минут 43 секунды)
   Post subject:
Reply with quote

Упустил из позапрошлого поста:
Quote:
и они не конфликтовали в нескольких экземплярах одного класса.
Это понятно и нужно. Только я бы оставил это на совести программиста, как уже и сказал.
Quote:
На это я ответил выше:
Не понял вашего ответа, честно говоря. Как это относится к замыканиям? Приведите, пожалуйста, один или два примера клиники.
Quote:
Вот это и хочется увидеть "живьём"
Вот чисто пример сам по себе, т.е. техника (требуется код из аттача):
Code (JavaScript): скопировать код в буфер обмена
(function () {

var a = 0, b = 0;

var A = WF.extend(function () {}, {
    method:function () {
        a++;
    }
});

var B = AK2.Base.extend({
    method:function () {
        b++;
    }
});

document.write(a + ', ' + b + '<br />' );
try {
    new A().method();
}
catch (e) {
    document.write('Houston, we have a problem: ' + e + '<br />');
}
new B().method();
document.write(a + ', ' + b + '<br />' );

}());
Пример реалистичный - вот эта a могла быть глобальным для модуля частным кешем, синглетоном и т.д. Понятное дело, что можно переписать без замыканий. Но вы лишаете человека инструмента.
Quote:
Имеется в виду ext?
Нет, имеется в виду флаг "мы конструируем прототип объекта или сам объект" - его имя находится в переменной ex.

Да, так вот я тут тест провел (в аттаче код и полный результат). Для меня результаты более чем удивительны. :)

Немного о тесте. Сто тысяч итераций (для некоторых браузеров пришлось снизить до 10К по понятным причинам; браузеры с разных машин, поэтому абсолютное время особого значения не имеет), на каждой создается объект, его конструктор вызывает все родительские конструкторы, потом вызывается некий метод - ну, чтобы было. Методы func1 и др. - просто "мясо", которое требует переработки при вашем способе наследования. "WingedFox original" - ваш код, "WingedFox modified" - моя перестилизация, "AlexKunin" - где-то таким способом я обычно пользуюсь, и который является "нашлепкой" к "встроенному" прототипному наследованию. Способы неравноценны в том смысле, что из наследника у меня можно вызвать только родительский конструктор, причем один раз (это просто сокращение "this.constructor.prototype.....call(this, ...)"). Вообще же хотелось сравнить с чистым прототипным наследованием, но это ж сколько печатать надо. :)

Safari 3.0.4:
WingedFox original: 2.739ms
WingedFox modified: 2.662ms
AlexKunin: 1.95ms

Firefox 3b3
WingedFox original: 4.279ms
WingedFox modified: 4.254ms
AlexKunin: 2.888ms

Opera 9.26:
WingedFox original: 3.575ms
WingedFox modified: 3.605ms
AlexKunin: 2.664ms

IE 6.0:
WingedFox original: 0.711ms
WingedFox modified: 0.721ms
AlexKunin: 0.771ms

Firefox 2.0.0.12:
WingedFox original: 0.801ms
WingedFox modified: 0.782ms
AlexKunin: 0.691ms

Итого:
  1. как ни странно, eval не дал практически никакой потери :))) Видать, кеш по аргументу eval'а, или еще что. Или это не eval так быстро работет, а первый ваш способ - медленно.
  2. чистое прототипное наследование без замыканий почти всегда дает прирост на 15 - 40%.
  3. ие 6 как всегда отличился :)) Ваш способ и eval на нем работают быстрее, чем более прямой (!).
А может в моем кусочке кода какая-нибудь глупая ошибка. Но тогда у чистого прототипного скорость еще выше.


wf.zip
 Description:
код теста и его результаты

Download
 Filename:  wf.zip
 Filesize:  2.79 KB
 Downloaded:  611 Time(s)

Back to top
View user's profile Send private message Send e-mail
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Sat Mar 01, 2008 9:24 pm (спустя 2 часа 36 минут; написано за 9 минут 16 секунд)
   Post subject:
Reply with quote

alexkunin
У Вас в тесте ошибка одна, но большая: BBB создаётся моим оригинальным методом. При использовании AK.extend результаты получаются несколько иные...
Я добавил в тест вызов родительских методов .run, правда только для моего метода, поскольку не нашёл как у Вас их вызывать.
Различие составило около 1%, т.ч. цифры приведены с его учётом.

FireFox 2.0.0.12
Пришлось запускать на 1000 итераций, т.к. 10000 отжирают ~1.5Гб и он падает
WingedFox original: 0.063ms
WingedFox modified: 3.156ms
AlexKunin: 0.047ms

IE 6
WingedFox original: 0.531ms
WingedFox modified: object not found
AlexKunin: 0.469ms

IE7
WingedFox original: 0.578ms
WingedFox modified: object not found
AlexKunin: 0.516ms

Opera 9.0.1
WingedFox original: 0.359ms
WingedFox modified: 2.235ms
AlexKunin: 0.172ms

Safari 3.0.3
WingedFox original: 0.218ms
WingedFox modified: 2.094ms
AlexKunin: 0.141ms

По результатам могу сказать, что большой разницы я не вижу, поскольку создание 10000 объектов в цикле интересно только для синтетических тестов.
К тому же, было бы интересно посмотреть насколько быстро будут вызываться родительские методы в Вашем варианте реализации.

PS: вообще, синтетические тесты на языке имеющем примерно 100-кратное замедление относительно машинного кода - это мегавещь =)
PPS:
alexkunin wrote:
Методы func1 и др. - просто "мясо", которое требует переработки при вашем способе наследования.
Вот с этого момента поподробнее, пожалуйста.


wf.zip
 Description:
Исправленые тесты

Download
 Filename:  wf.zip
 Filesize:  2.7 KB
 Downloaded:  604 Time(s)



Last edited by WingedFox on Sat Mar 01, 2008 9:37 pm; edited 1 time in total
Back to top
View user's profile Send private message
WingedFox
Профессионал



Joined: 29 Apr 2003
Posts: 4064
Карма: 269
   поощрить/наказать

Location: Питер

PostPosted: Sat Mar 01, 2008 9:36 pm (спустя 12 минут; написано за 6 минут 46 секунд)
   Post subject:
Reply with quote

alexkunin wrote:
Это понятно и нужно. Только я бы оставил это на совести программиста, как уже и сказал.
Тогда на совесть программиста можно оставить и всё остальное =)
А людям свойственно ошибаться или просто забывать о требованиях "техники безопасности", или даже не знать про них =)
alexkunin wrote:
Не понял вашего ответа, честно говоря. Как это относится к замыканиям? Приведите, пожалуйста, один или два примера клиники.
Пример:
Code (JavaScript): скопировать код в буфер обмена
function getPiPowTable () {
    var pi = 3.14
       ,pt = []
    for (var i=0;i<100;i++) {
        pt[i] = (function(z) { return function() { return Math.pow(z,pi)}})(i);
    }
    return pt;
}

extend (SomeMathClass,{
    piPowTable : getPiPowTable();
});
Больше вариантов где замыкания могут поломаться до фактического конструирования класса я придумать не могу.
Но даже этот вариант легко исправляется так, чтобы ничего не ломалось.
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Goto page 1, 2, 3  Next
Page 1 of 3    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML