Лучшая замена 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], но и у всех объектов, получивших ссылку на это свойство. В общем, мне самому не нравится, так как никакого наследования у меня не получается, что-то с иерархией не то. :p Хочется ведь, чтобы каскад был направлен в одну сторону - меняя св-во в конструкторе (или в прототипе, или ещё где), я меняю у всех наследников, а если меняю у наследника - ничего не должно влиять на родителей или братьев. Собственно, вопрос звучит так, наверное: хотелось бы привязать заданные литерально объекты к определённому конструктору, чтобы менять свойства и методы централизованно и каскадно (если будет цепочка наследования). Простите за сумбур, JS - мой первый язык программирования, и на начальной стадии. :p P.S.: пока писал всё это, подумал, что м.б. будет правильно каждый элемент в массиве подменять объект new MyDb, через tempVar заменив дефолтные значения на уже имеющиеся? Т.о., они все будут привязаны к конструктору MyDb и сохранят то, что имеют. Дело в том, что помимо вложенности по наследованию тут предполагается ещё и вложенность объектов по сути myDbs.dbsList[i].ObjStoreList[j].IndxList[k], у каждого из которых предполагается свой прототип(или конструктор). :blink: P.P.S.: Спасибо тем, кто хотя бы прочёл это. |
Можешь попробовать вот такую парашу:
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 обещают, посмотрим. |
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() ] } Наследование, как можно было заметить, ни в том, ни в другом случае не нужно. |
|
Мне сегодня снились прототипы... :dance:
Спасибо Вам всем за отклик. :thanks: В обратном порядке: Erolast, сенкс за ссылки, добавил в букмаркс. Последнюю, правда, уже читал. :p Насчёт 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 оперирует ссылками вместо примитивов, о чём предупреждалось в примере с хомяками с общим животом, но моего понимания всех связей ещё очень недостаточно. ЧЯДНТ? :help: |
Цитата:
Цитата:
Цитата:
|
Цитата:
Касательно темы топа - скорее всего, на данном этапе придётся действовать постепенно. Поскольку знаний и понимания не хватает, буду оперировать тем, что есть. Я более-менее разобрался с обычными массивами, буду оттуда брать множества Dbs,objecStores,Indexes с их параметрами и перекручивать их через new MyDb. Или так, как уже писал: Цитата:
И вообще - странно, JSON появился и распространился уже достаточно давно, и, мне кажется, что вопрос с отнесением к какому-то классу (псевдоклассу) литерально заданных объектов должен быть уже обсосан со всех сторон. |
Цитата:
Цитата:
Цитата:
Цитата:
|
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 } , а нужно делегирование (если нужно конечно). |
Вложений: 2
krutoy, спасибо! Да, я не чётко мыслю => не чётко излагаю.
Ваш последний вариант лучше всего для меня на данном этапе. Наверное, я действительно не до конца понимаю, что хочу получить. Всё от того, что я делаю себе помощника в изучении HTML/CSS/JS, попутно изучая их. Вот такая вот рекурсия. :) Уже сделал себе заметки и сохранение параметров страниц в LocalStorage c импортом/экспортом в CSV (рис.#1) и решил заняться indexeddb, попутно разбираясь с объектами, ибо элементов на странице стал просто удивительно много. Например, для работы обычными массивами сделал себе нечто вроде проводника (в прилагаемой картинке #2), но тут подумалось, что правильнее было бы сразу работать сразу с объектами (элементами окна, объектами базы данных, файлами JS, etc.), однако и тут всё не так просто. :help: Хотелось сразу проектировать в своём "проводнике", чтобы "рисовать" объекты мышкой, а они чтобы - сразу в JSON. У меня так сейчас так с обычными массивами - тыкаю мышкой по экрану, а в результате имею нечитаемую строку с неограниченным количеством вложений. Да и читать её не надо, так как она всегда выводится древом на экран. Надеюсь, рано или поздно так будет и с объектами. Erolast, тоже спасибо, но я сначала хочу получить базовые знания по HTML, CSS и JS, а потом уж расширять свои возможности. Видите, я даже не до конца понимаю, что я хочу, и что JS в принципе может. Чисто в качестве хобби, никто меня не гонит и результат не спрашивает. Раньше, в детстве - да, было дело, на VBA приходилось такие чудеса в цейтноте на работе вытворять (по образцам из NorthWind.mdb), что потом даже краснеть сил не оставалось. :) И такие "программы" жили годами, блин, а ведь я даже не настоящий А насчёт невнимательности - с возрастом когнитивные способности не улучшаются, я примерно 90% Ваших слов просто не понимаю, да и остальные 10 приходится гуглить :D , так что не обижайтесь, я Вас не игнорирую. Такая небольшая шутка перед праздниками, настроение.:lol: |
ssadfaf,
Тут есть ньюанс. Я писал наспех, не думал, что вам это понадобиться. Данная версия extend некорректно работает со значениями false, и приводимыми к false 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: 0}, {foo: 100, bar: false} ] } 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: 1, bar: 2, baz: 3 } // { foo: 100, bar: 2, baz: 3 } используйте вот эту версию extend=function(src, trg){for(var i in src) if(!(i in trg)) trg[i]=src[i]} |
Цитата:
сейчас один проект в phpstorm голимого текста с хорошо организованной кучей файлов и каталогов (уже мегабайт на 300 накапало, если не больше, хорошо - условно, процесс переструктуризации бесконечный, голимого - без разметки, кроме выделения блоков с кодом, в целом, сложилась некоторая структура написания файлов, которая, при необходимости скриптом позволит добавить разметку) почти каждый файл решает некоторую задачу, во главе угла идеи процедурного программирования (одни файлы решают более мелкие задачи, другие используют их для решения более крупных) в продакшн, вероятно, не выйдет :) |
Цитата:
|
Цитата:
В общем-то, мой код делает то же, что и код крутого, только у меня сразу идет обертка в класс. Классы нужны, с ними при расширении структуры приложения кода придется писать меньше, при том, что на этом уровне ничего не усложняется. |
Erolast,
Цитата:
Ах да, ES7 пока ниразу не близится к завершению) |
Цитата:
Цитата:
Цитата:
|
Цитата:
|
Erolast,
Цитата:
Цитата:
|
krutoy,
Цитата:
|
Цитата:
Цитата:
|
Erolast,
Цитата:
|
Аха. Но не легче ли будет изучать прототипы сперва поняв, зачем классы вообще нужны?) А для этого нужно ими попользоваться на высоком уровне.
|
Erolast,
неа. Ты ведь сначала изучаешь основы и пишешь простенькие проги, и только потом переходишь к MVC, SPA и прочим крутым словам) Вот тут так же. |
Цитата:
Цитата:
Цитата:
Цитата:
Всем отписавшимся ещё раз - ОГРОМНОЕ СПАСИБО и с наступающим праздником! |
Цитата:
|
Erolast,
на высоком уровне всё проще, но я за то, что начинать нужно с основ. |
Часовой пояс GMT +3, время: 14:25. |