28.12.2014, 20:37
|
Интересующийся
|
|
Регистрация: 28.12.2014
Сообщений: 20
|
|
Лучшая замена deprecated __proto__ при литеральном создании объекта
C наступающим!
Начал знакомиться с JS, в основном - на этом сайте, спасибо Вам!
К вопросу - сначала заготовил значения по умолчанию - конструктор:
var MyDb = function (name) {
this.name=name;
this.objStoreList=['fromCons'];
this.origin='coreJSON'
// other props}
И есть объект (будет получаться в виде JSON по XHR)
var myDbs = {
dbsList:
[
{name:'CoreDb',objStoreList:['theFirst1']},
{name:'OtherDb'},
{name:'MiscDb', origin:'miscJSON'}
],
up2Date:TS22().TimeStamp, //etc...};
И необходимо заполнить отсутствующие свойства и методы объектов из массива dbsList дефолтными из конcтруктора MyDb (сохраняя уже имеющиеся значения).
Сначала вдохновился примерами с prototype#наследование-через-ссылку-proto:
Через цикл myDbs.dbsList.forEach делал
item.__proto__ = new MyDb
Что прекрасно меня удовлетворяло, ибо в прототипе каждого объекта были зарезервированы дефолтные значения.
Однако потом прочитал, что использование __proto__ - bad practice и вообще - оно deprecated.
Тогда я, тоже через цикл myDbs.dbsList.forEach сделал
var tempMyDb = new MyDb;
for (var key in tempMyDb) {
if (item.hasOwnProperty(key)) {continue;}
item[key]=tempMyDb[key];};
Таким образом, каждый объект из массива получил недостающие свойства как собственные (hasOwnProperty), а не в его прототипе.
Причём
var tempMyDb = new MyDb;
я загнал в цикл forEach сознательно, чтобы у каждого item была своя ссылка на отдельный объект, и ещё один
var tempMyDb = new MyDb;
после всех циклов, чтобы разрушить связь. Потому что, в противном случае, действие
myDbs.dbsList.forEach(function(item,i){
if (i==0) {item.objStoreList.push('Settings','Pettings', 'Elems')}
});
почему-то меняло свойство не только у item[0], но и у всех объектов, получивших ссылку на это свойство.
В общем, мне самому не нравится, так как никакого наследования у меня не получается, что-то с иерархией не то.
Хочется ведь, чтобы каскад был направлен в одну сторону - меняя св-во в конструкторе (или в прототипе, или ещё где), я меняю у всех наследников, а если меняю у наследника - ничего не должно влиять на родителей или братьев.
Собственно, вопрос звучит так, наверное: хотелось бы привязать заданные литерально объекты к определённому конструктору, чтобы менять свойства и методы централизованно и каскадно (если будет цепочка наследования).
Простите за сумбур, JS - мой первый язык программирования, и на начальной стадии.
P.S.: пока писал всё это, подумал, что м.б. будет правильно каждый элемент в массиве подменять объект new MyDb, через tempVar заменив дефолтные значения на уже имеющиеся? Т.о., они все будут привязаны к конструктору MyDb и сохранят то, что имеют.
Дело в том, что помимо вложенности по наследованию тут предполагается ещё и вложенность объектов по сути
myDbs.dbsList[i].ObjStoreList[j].IndxList[k], у каждого из которых предполагается свой прототип(или конструктор).
P.P.S.: Спасибо тем, кто хотя бы прочёл это.
|
|
29.12.2014, 03:42
|
Профессор
|
|
Регистрация: 09.11.2014
Сообщений: 610
|
|
Можешь попробовать вот такую парашу:
extend=function(src, trg){for(var i in src) trg[i]=src[i]}
function Db(ob){
extend(ob, this)
return this
}
Db.prototype.foo=1
Db.prototype.bar=1
Db.prototype.baz=1
dbs={
list: [
{foo: 10},
{foo: 100, bar: 10}
]
}
for(var i in dbs.list) dbs.list[i]=new Db(dbs.list[i])
console.log(
dbs.list[0].foo,
dbs.list[0].bar,
dbs.list[0].baz,
dbs.list[1].foo,
dbs.list[1].bar,
dbs.list[1].baz,
dbs.list[0].constructor,
dbs.list[1].constructor,
dbs.list[0].hasOwnProperty("foo"),
dbs.list[0].hasOwnProperty("bar"),
dbs.list[0].hasOwnProperty("baz"),
dbs.list[1].hasOwnProperty("foo"),
dbs.list[1].hasOwnProperty("bar"),
dbs.list[1].hasOwnProperty("baz")
)
// 10 1 1 100 10 1 [Function: Db] [Function: Db] true false false true true false
Так у тебя восстановится вся иерархия. Но по-хорошему, следовало бы сраным комитетчикам яйца оторвать. __proto__ , в общем случае, без бубнов, ничем не заменишь, это сердце языка, блять. Вроде, какой то setPrototypeOf обещают, посмотрим.
|
|
29.12.2014, 10:41
|
|
Профессор
|
|
Регистрация: 24.09.2013
Сообщений: 1,436
|
|
krutoy, 1) пощади JS, не учи новичков говнокоду, 2) сраным комитетчикам, наверное, виднее? Никто у тебя гибкости не отнимает, setPrototypeOf полностью аналогичен сеттеру __proto__.
ssadfaf, учи сразу ES6 и ES7. Это пока что неутвержденные (но близящиеся к тому) версии стандарта JS, сейчас ими можно пользоваться через компиляцию. В ES6 задача решается элементарно встроенными средствами:
class Character {
constructor(data) {
Object.assign(this, {//Default properties
hp: 1000,
energy: 500,
speed: 100
}, data);
}
}
function loadCharacters() {
return [
new Character({hp: 10000, energy: 10000, speed: 10}),
new Character({hp: 100}),
new Character()
];
}
console.log(loadCharacters());
Для решения на ES5- тебе нужна функция extend из, например, underscore или jQuery, выглядеть это будет так (в примере применен underscore):
function Character(data) {
_.extend(this, {//Default properties
hp: 1000,
energy: 500,
speed: 100
}, data);
}
function loadCharacters() {
return [
new Character({hp: 10000, energy: 10000, speed: 10}),
new Character({hp: 100}),
new Character()
]
}
Наследование, как можно было заметить, ни в том, ни в другом случае не нужно.
Последний раз редактировалось Erolast, 29.12.2014 в 11:13.
|
|
29.12.2014, 10:49
|
|
Профессор
|
|
Регистрация: 24.09.2013
Сообщений: 1,436
|
|
Да, почитать про ES6+ можно здесь, здесь, здесь, здесь и здесь.
Последний раз редактировалось Erolast, 29.12.2014 в 10:53.
|
|
29.12.2014, 13:49
|
Интересующийся
|
|
Регистрация: 28.12.2014
Сообщений: 20
|
|
Мне сегодня снились прототипы...
Спасибо Вам всем за отклик.
В обратном порядке:
Erolast, сенкс за ссылки, добавил в букмаркс. Последнюю, правда, уже читал.
Насчёт jQuery и прочего - мне ещё чистый JS изучать и изучать. Эти библиотеки прекрасны, но есть опасность, получив их неограниченные возможности и не разбравшись в основах, тупо фигачить по шаблонам и примерам, пока не упрешься в какую-нибудь проблему, которую ты и сформулировать-то не сможешь. Вот как сейчас, например.
Касательно ES6 - а как скоро он будет имплементирован в webkit Android? По моей задумке хочу сделать себе лайтового универсального помощника на ПК и Андроид (от 4.4, чтобы с поддержкой indexeddb и HTML5). Посмотрел на в таблицы совместимости через MDN - setPrototypeOf и Object.assign пока как-то не очень с мобильными платформами.
Но за надежду на лучшее - сенкс.
krutoy, я, наверное, сильно переврал Ваш код, но у меня не получилось. Я пока во всяких this плаваю, как топор.
Вот мои конструктор и расширитель:
var MyDb11111 = function (x3) {
extend(x3, this);
return this;
}
MyDb11111.prototype.name='nameFromPrototype';
MyDb11111.prototype.objStList=['objStListFromPrototype0', 'objStListFromPrototype1'];
MyDb11111.prototype.origin='originFromPrototype';
MyDb11111.prototype.destination='destinationFromPrototype';
var extend=function(src, trg){for(var key in src) trg[key]=src[key]};
А вот тестовая функция:
function TestPest242() {
var myDbs = {dbsList:[{name:'CoreDb',origin:'zz_core'},{name:'Misc'},{name:'BkMrks',destination:'stayHere', objStList:['Hrefs']}],up2Date:TS22().TimeStamp};
for(var key in myDbs.dbsList) myDbs.dbsList[key]=new MyDb11111(myDbs.dbsList[key]);
var testMyDb = new MyDb11111; // (1) тест на возможность создания нового объекта
myDbs.dbsList.push(testMyDb); // (2) тест на возможность добавления нового объекта
MyDb11111.prototype.newProperty='newPropertyFromPrototype'; // (3) тест на возможность добавления нового свойства для всех объектов
myDbs.dbsList.forEach(function(item,i){ // тесты:
if (i==0) {item.objStList.push('Settings','Pettings', 'Elems');}; // (4) нет своих, push новых
if (i==1) {item.objStList.push('Elems1')}; // (5) нет своих, push новых
if (i==1) {item.origin = 'MiscJSON'}; // (6) нет своих, создание новых
if (i==2) {item.objStList.push('Elems2')}; // (7) есть свои, push новых
if (i==2) {item.destination = 'zz_core'}; // (8) есть свои, изменение значения
if (i==3) {item.objStList.push('Elems3')}; // (9) нет своих, push новых
if (i==3) {item.newProperty = 'propertyNext'}; // (10) нет своих, создание новых
});
myDbs.dbsList.forEach(function(item,i){
console.log(" i " + i );
for (var key in item) {console.log(' ownProp: ' + item.hasOwnProperty(key) +' >>> '+ key + " = " + item[key] );}});}
Консоль:
i 0
ownProp: true >>> name = CoreDb
ownProp: true >>> origin = zz_core
ownProp: false >>> objStList = objStListFromPrototype0,objStListFromPrototype1,Settings,Pettings,Elems,Elems1,Elems3
ownProp: false >>> destination = destinationFromPrototype
ownProp: false >>> newProperty = newPropertyFromPrototype
i 1
ownProp: true >>> name = Misc
ownProp: true >>> origin = MiscJSON
ownProp: false >>> objStList = objStListFromPrototype0,objStListFromPrototype1,Settings,Pettings,Elems,Elems1,Elems3
ownProp: false >>> destination = destinationFromPrototype
ownProp: false >>> newProperty = newPropertyFromPrototype
i 2
ownProp: true >>> name = BkMrks
ownProp: true >>> destination = zz_core
ownProp: true >>> objStList = Hrefs,Elems2
ownProp: false >>> origin = originFromPrototype
ownProp: false >>> newProperty = newPropertyFromPrototype
i 3
ownProp: true >>> newProperty = propertyNext
ownProp: false >>> name = nameFromPrototype
ownProp: false >>> objStList = objStListFromPrototype0,objStListFromPrototype1,Settings,Pettings,Elems,Elems1,Elems3
ownProp: false >>> origin = originFromPrototype
ownProp: false >>> destination = destinationFromPrototype
Собственно, большинство тестов пройдены успешно, кроме главных.
Например, при наличии своего свойства-массива
// (7) есть свои, push новых
всё происходит правильно.
А вот если
// (4), (5), (9) нет своих, push новых
то в них происходит тупо добавление в прототип с искажением всего массива.
Есть предположение, что это как-то связано с тем, что массив - сам по себе объект и JS оперирует ссылками вместо примитивов, о чём предупреждалось в примере с хомяками с общим животом, но моего понимания всех связей ещё очень недостаточно.
ЧЯДНТ?
Последний раз редактировалось ssadfaf, 29.12.2014 в 13:53.
|
|
29.12.2014, 14:18
|
|
Профессор
|
|
Регистрация: 24.09.2013
Сообщений: 1,436
|
|
Цитата:
|
Насчёт jQuery и прочего - мне ещё чистый JS изучать и изучать. Эти библиотеки прекрасны, но есть опасность, получив их неограниченные возможности и не разбравшись в основах, тупо фигачить по шаблонам и примерам, пока не упрешься в какую-нибудь проблему, которую ты и сформулировать-то не сможешь.
|
Плохое решение. Правильный программист - ленивый программист, ты должен уметь максимально упрощать свою задачу. Ну, и если таки сильно хочется практики - кто мешает написать свою реализацию extend? Описание можно взять с MDN:
Цитата:
|
The Object.assign() method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
Syntax:
Object.assign(target, ...sources)
|
Цитата:
|
Касательно ES6 - а как скоро он будет имплементирован в webkit Android? По моей задумке хочу сделать себе лайтового универсального помощника на ПК и Андроид (от 4.4, чтобы с поддержкой indexeddb и HTML5). Посмотрел на в таблицы совместимости через MDN - setPrototypeOf и Object.assign пока как-то не очень с мобильными платформами
|
Ты невнимательно читаешь. Я же сказал - на ES6+ можно писать уже сейчас через компиляцию и подключение полифилла, и работать это будет везде.
Последний раз редактировалось Erolast, 29.12.2014 в 14:23.
|
|
29.12.2014, 15:15
|
Интересующийся
|
|
Регистрация: 28.12.2014
Сообщений: 20
|
|
Сообщение от Erolast
|
Ты невнимательно читаешь. Я же сказал - на ES6+ можно писать уже сейчас через компиляцию и подключение полифилла, и работать это будет везде.
|
Спс, буду разбираться.
Касательно темы топа - скорее всего, на данном этапе придётся действовать постепенно. Поскольку знаний и понимания не хватает, буду оперировать тем, что есть. Я более-менее разобрался с обычными массивами, буду оттуда брать множества Dbs,objecStores,Indexes с их параметрами и перекручивать их через new MyDb.
Или так, как уже писал:
Сообщение от ssadfaf
|
м.б. будет правильно каждый элемент в массиве подменять объектом new MyDb, через tempVar заменив дефолтные значения на уже имеющиеся. Т.о., они все будут привязаны к конструктору MyDb и сохранят те свойства, что уже имеют
|
Честно говоря, на данном этапе моего разумения не хватает, чтобы понять, зачем вообще нужен прототип, если всё равно приходится перебирать каждую пару ключ-значение.
И вообще - странно, JSON появился и распространился уже достаточно давно, и, мне кажется, что вопрос с отнесением к какому-то классу (псевдоклассу) литерально заданных объектов должен быть уже обсосан со всех сторон.
|
|
29.12.2014, 16:35
|
|
Профессор
|
|
Регистрация: 24.09.2013
Сообщений: 1,436
|
|
Цитата:
|
Честно говоря, на данном этапе моего разумения не хватает, чтобы понять, зачем вообще нужен прототип, если всё равно приходится перебирать каждую пару ключ-значение.
|
Тренируй внимательность. Я же говорил - работа с прототипами не нужна:
Цитата:
|
Наследование, как можно было заметить, ни в том, ни в другом случае не нужно.
|
Цитата:
|
Касательно темы топа - скорее всего, на данном этапе придётся действовать постепенно. Поскольку знаний и понимания не хватает, буду оперировать тем, что есть. Я более-менее разобрался с обычными массивами, буду оттуда брать множества Dbs,objecStores,Indexes с их параметрами и перекручивать их через new MyDb.
|
Зачем все это? Я же написал решение, чем оно тебя не устраивает?
Цитата:
|
function Character(data) {
_.extend(this, {//Default properties
hp: 1000,
energy: 500,
speed: 100
}, data);
}
function loadCharacters() {
return [
new Character({hp: 10000, energy: 10000, speed: 10}),
new Character({hp: 100}),
new Character()
]
}
|
|
|
29.12.2014, 17:22
|
Профессор
|
|
Регистрация: 09.11.2014
Сообщений: 610
|
|
ssadfaf,
все так и должно работать, так как это св-во наследуется. чтобы работало по другому, надо создать свое свойство в объекте, которое затрет наследуемое
extend=function(src, trg){for(var i in src) trg[i]=src[i]}
function Db(ob){
extend(ob, this)
return this
}
Db.prototype.arr=["foo"]
dbs={
list: [
{}
]
}
for(var i in dbs.list) dbs.list[i]=new Db(dbs.list[i])
dbs.list[0].arr.push("bar")
console.log(Db.prototype.arr, dbs.list[0].arr)
dbs.list[0].arr=[]
dbs.list[0].arr.push("baz")
console.log(Db.prototype.arr, dbs.list[0].arr)
// [ 'foo', 'bar' ] [ 'foo', 'bar' ]
// [ 'foo', 'bar' ] [ 'baz' ]
В Вашем изначальном случае с __proto__ в подобной ситуации тоже менялось свойство прототипа а не самого объекта, просто у каждого объекта, в Вашем случае, был свой "личный" прототип, что неверно, с точки зрения проектирования.
item.__proto__ = new MyDb // это неверно.
// правильно вот так
parent=new MyDb
item.__proto__=parent
и тогда бы было то же самое. Ваш Вариант не имеет смысла, с тем же успехом можно было тупо экстендить каждый item
extend=function(src, trg){for(var i in src) if(!trg[i]) trg[i]=src[i]}
pattern={foo: 1, bar: 2, baz: 3}
dbs={
list: [
{foo: 10},
{foo: 100, bar: 10}
]
}
for(var i=0; i<dbs.list.length; i++){
extend(pattern, dbs.list[i])
}
for(var i=0; i<dbs.list.length; i++){
console.log(dbs.list[i])
}
// { foo: 10, bar: 2, baz: 3 }
// { foo: 100, bar: 10, baz: 3 }
, а нужно делегирование (если нужно конечно).
Последний раз редактировалось krutoy, 29.12.2014 в 18:04.
|
|
29.12.2014, 22:29
|
Интересующийся
|
|
Регистрация: 28.12.2014
Сообщений: 20
|
|
krutoy, спасибо! Да, я не чётко мыслю => не чётко излагаю.
Ваш последний вариант лучше всего для меня на данном этапе.
Наверное, я действительно не до конца понимаю, что хочу получить. Всё от того, что я делаю себе помощника в изучении HTML/CSS/JS, попутно изучая их. Вот такая вот рекурсия.
Уже сделал себе заметки и сохранение параметров страниц в LocalStorage c импортом/экспортом в CSV (рис.#1) и решил заняться indexeddb, попутно разбираясь с объектами, ибо элементов на странице стал просто удивительно много. Например, для работы обычными массивами сделал себе нечто вроде проводника (в прилагаемой картинке #2), но тут подумалось, что правильнее было бы сразу работать сразу с объектами (элементами окна, объектами базы данных, файлами JS, etc.), однако и тут всё не так просто. Хотелось сразу проектировать в своём "проводнике", чтобы "рисовать" объекты мышкой, а они чтобы - сразу в JSON. У меня так сейчас так с обычными массивами - тыкаю мышкой по экрану, а в результате имею нечитаемую строку с неограниченным количеством вложений. Да и читать её не надо, так как она всегда выводится древом на экран. Надеюсь, рано или поздно так будет и с объектами.
Erolast, тоже спасибо, но я сначала хочу получить базовые знания по HTML, CSS и JS, а потом уж расширять свои возможности. Видите, я даже не до конца понимаю, что я хочу, и что JS в принципе может. Чисто в качестве хобби, никто меня не гонит и результат не спрашивает. Раньше, в детстве - да, было дело, на VBA приходилось такие чудеса в цейтноте на работе вытворять (по образцам из NorthWind.mdb), что потом даже краснеть сил не оставалось. И такие "программы" жили годами, блин, а ведь я даже не настоящий сварщик программист. Вот и хочу хоть один язык попытаться базово освоить, пусть и не знаю, далеко ли продвинусь.
А насчёт невнимательности - с возрастом когнитивные способности не улучшаются, я примерно 90% Ваших слов просто не понимаю, да и остальные 10 приходится гуглить , так что не обижайтесь, я Вас не игнорирую. Такая небольшая шутка перед праздниками, настроение.
|
|
|
|