For example. I have something like this:
class Qwe {
constructor(q, w, e) {
this.q = q;
this.w = w;
this.e = e;
}
toJSON() {
return {q: this.q, w: this.w};
}
}
And i want to store object of this class in chrome.storage, but it would be something like this:
{q:q, w:w, e:e}
And i wonder if there is any way to custom serialization like here with toJSON, or if not how you would resolve this problem.
Only way to do this is implement your own serialization (and perhaps deserialization) and call it on main object before store in chrome.storage:
...
let qwe = new Qwe("q", "w", "e");
...
let item = {qwe: qwe.serialize()}; // in this case toJSON()
chrome.storage.local.set(item);
...
About implementation of serialization:
I have created something like this for main object:
let mainObject = {
//...
//a lot of objects literals, arrays, and our classes (objects)
//...
}
function serialize(sourceObject, object) {
if(sourceObject instanceof Array) {
if(object instanceof Array) {
let id = sourceObject.push([]) - 1;
object.forEach(item => {
serialize(sourceObject[id], item);
});
} else if(object instanceof Object) {
if(object.serializable) {
sourceObject.push(object.serialize());
} else {
let id = sourceObject.push({}) - 1;
serialize(sourceObject[id], object);
}
} else {
sourceObject.push(object);
}
} else {
for(let property in object) {
if(object.hasOwnProperty(property)) {
if(object[property] instanceof Array) {
sourceObject[property] = [];
object[property].forEach(item => {
serialize(sourceObject[property], item);
});
} else if(object[property] instanceof Object) {
if(object[property].serializable) {
sourceObject[property] = object[property].serialize();
} else {
sourceObject[property] = {};
serialize(sourceObject[property], object[property]);
}
} else {
sourceObject[property] = object[property];
}
}
}
}
}
If object has property serializable then i know that it implements serialize() otherwise i go deeper. I don't know if this is optimal solution ;).
Usage:
let o = {
mainObject: {}
};
serialize(o.mainObject, mainObject);
chrome.storage.local.set(o);
Related
I've created HTML builder (finally!)
It just has methods: create div, span, p, br.
As you can see in console.logs it has nesting and chaining behavior.
And for detecting nesting and chaining I have item instanceof Class
But it doesn't show me correct return when I have nesting condition.
Need help to find the mistake and get output in first console.log =
<div><p>Hello</p><p>World</p></div>
class Templater {
constructor() {
this.arr = [];
this.nesting = false;
}
transform(tags) {
return tags.join("");
}
div(...tags) {
tags.forEach(item => {
this.nesting = (item instanceof Templater);
});
this.arr.push(`<div>${this.transform(tags)}</div>`)
return this;
}
span(...tags) {
tags.forEach(item => {
this.nesting = (item instanceof Templater);
});
this.arr.push(`<span>${this.transform(tags)}</span>`);
return this
}
br(argument) {
tags.forEach(item => {
this.nesting = (item instanceof Templater);
});
if (argument) {
throw new Error('Nested content is not allowed');
} else {
this.arr.push(`<br>`);
return this;
}
}
p(...tags) {
tags.forEach(item => {
this.nesting = (item instanceof Templater);
});
this.arr.push(`<p>${this.transform(tags)}</p>`);
return this
}
toString() {
if (this.nesting) {
this.nesting = false;
let qwe = [...this.arr];
this.arr = [];
return qwe[qwe.length-1];
} else {
let qwe = [...this.arr];
this.arr = [];
return qwe.join('');
}
}
}
const template = new Templater();
console.log(template.div(
template.p('Hello'),
template.p('World')
).toString());
console.log(template.div().toString());
console.log(template.div('Hello').p('fix').toString());
Worked for me with :
console.log(template.div(
template.p('Hello').p('World').toString()
).toString());
I am developing web project using TypeScript. Here i need HashTable functionality in typescript like C# HashTable. But i have already developed that in JavaScript.
this.length = 0;
this.items = [];
this.add = function (key, value) {
this.previous = undefined;
if (this.containsKey(key)) {
this.previous = this.items[key];
} else {
this.length++;
}
this.items[key] = value;
return this.previous;
};
this.clear = function () {
this.items = {};
this.length = 0;
};
this.contains = function (key) {
return this.items.hasOwnProperty(key);
};
this.containsKey = function (key) {
return this.items.hasOwnProperty(key);
};
this.containsValue = function (key) {
return (this.items.hasOwnProperty(key) && this.items[key] != undefined) ? true : false;
};
this.getItem = function (key) {
if (this.containsKey(key))
{
return this.items[key]
}
else
{
return undefined;
}
};
this.keys = function () {
var keys = [];
for (var k in this.items) {
if (this.containsKey(k)) {
keys.push(k);
}
}
return keys;
};
this.remove = function (key) {
if (this.containsKey(key)) {
this.previous = this.items[key];
this.length--;
delete this.items[key];
return this.previous;
} else {
return undefined;
}
};
this.values = function () {
var values = [];
for (var k in this.items) {
if (this.containsKey(k)) {
values.push(this.items[k]);
}
}
return values;
};
this.each = function (fn) {
for (var k in this.items) {
if (this.containsKey(k)) {
fn(k, this.items[k]);
}
}
};
var previous = undefined;
}
return HashTable;
Like this, Typescript having predefined code? or i need to rewrite these codes from JS to TS? is there any simple property or class for this HashTable in typescript?
Or any other properties in TS to do the same HashTable functionality?
Modern JavaScript has three options:
Map, is closest to HashTable to my knowlage. It main advantage is that it’s keys may be of type Object.
Set, it is basically an unique array.
Object also known an {}. Key value store.
I would suggest to use object, but if your keys need to be object, use the Map.
JavaScript Object, or {}, is about 20x faster than Map. So use Map only if you need to use objects as keys.
Map is probably the right answer as suggested above, but maybe a hashmap with types looks something like this would work:
{ [key: string]: Type; }
or
{ [key: number]: Type; }
This question already has an answer here:
Is there a way to have lexical `this` in methods using the ES6 shorthand method notation?
(1 answer)
Closed 4 years ago.
I'm currently working on a Eloquent JavaScript's object assignments and I'm wondering if there is any way that I can use this inside iterator's next() method (see the code)
class Group {
constructor() {
this.members = [];
}
add(member) {
if (this.has(member)) return;
this.members.push(member);
}
delete(member) {
if (!this.has(member)) return;
this.members.splice(this.members.indexOf(member), 1);
}
has(member) {
return this.members.indexOf(member) !== -1
}
static from(iterable) {
const group = new Group();
for (const element of iterable) {
group.add(element);
}
return group;
}
[Symbol.iterator]() {
let current = 0;
let last = this.members.length - 1;
const that = this;
return {
next() {
if (current <= last) {
return {
done: false,
value: that.members[current++]
}
} else return { done:true }
}
}
}
}
for (let value of Group.from(["a", "b", "c"])) {
console.log(value);
}
As you can see there I'm using this weird const that = this pattern. Is there any way I can get rid of it? Besides using arrow function and extracting iterator to a separate class, as suggested in the solution.
The sortest way, could be an implementation of a default iterator of the object in the constructor section and use yield* expression for delegating to another generator of the array this.members.
constructor() {
this.members = [];
this[Symbol.iterator] = function* () {
yield* this.members;
}
}
class Group {
constructor() {
this.members = [];
this[Symbol.iterator] = function* () {
yield* this.members;
}
}
add(member) {
if (this.has(member)) return;
this.members.push(member);
}
delete(member) {
if (!this.has(member)) return;
this.members.splice(this.members.indexOf(member), 1);
}
has(member) {
return this.members.indexOf(member) !== -1
}
static from(iterable) {
const group = new Group();
for (const element of iterable) {
group.add(element);
}
return group;
}
}
for (let value of Group.from(["a", "b", "c"])) {
console.log(value);
}
.as-console-wrapper { max-height: 100% !important; top: 0; }
you can use the arrow function
class Group {
constructor() {
this.members = [];
}
add(member) {
if (this.has(member)) return;
this.members.push(member);
}
delete(member) {
if (!this.has(member)) return;
this.members.splice(this.members.indexOf(member), 1);
}
has(member) {
return this.members.indexOf(member) !== -1
}
static from(iterable) {
const group = new Group();
for (const element of iterable) {
group.add(element);
}
return group;
}
[Symbol.iterator]() {
let current = 0;
let last = this.members.length - 1;
return {
next: () => {
if (current <= last) {
return {
done: false,
value: this.members[current++]
}
} else return { done:true }
}
}
}
}
for (let value of Group.from(["a", "b", "c"])) {
console.log(value);
}
I had a use case to remove multiple keys from an JSON object or an array of objects.Below is my code.If anyone has more optimized approach for this then suggest.
exports.removeAttributes = function (arrayOfAttributesToRemove, object, callback) {
let checkForRemoveOrRetain = true;
removeORRetain(arrayOfAttributesToRemove, object, checkForRemoveOrRetain, (err, object) => {
if (err) {
callback(err);
} else {
callback( object);
}
});
};
exports.retainAttributes = function (arrayOfAttributesToRetain, object, callback) {
let checkForRemoveOrRetain = false;
removeORRetain(arrayOfAttributesToRemove, object, checkForRemoveOrRetain, (err, object) => {
if (err) {
callback(err);
} else {
callback(object);
}
});
}
let removeORRetain = function (arrayOfAttributesToRemove, object, checkForRemoveOrRetain, callback) {
if (Array.isArray(object)) {
for (let i = 0; i < object.length; i++) {
for (let key in object[i]) {
if (arrayOfAttributesToRemove.includes(key) === checkForRemoveOrRetain) {
delete object[i][key];
}
}
}
callback(object);
} else {
for (let key in object) {
if (arrayOfAttributesToRemove.includes(key) === checkForRemoveOrRetain) {
delete object[key];
}
}
callback( object);
}
};
You can do it with lodash very easily.
const _ = require('lodash');
exports.removeAttributes = function (arrayOfAttributesToRemove, object, callback) {
// check for errors etc. Then
// Create an array of objects if not already.
const arr = _.concat([], object);
// call callback with new arr with omitted properties using _.map and _.omit
callback(null, _.map(arr, e => _.omit(e, arrayOfAttributesToRemove)));
};
If you want to retain properties then use _.pick
Is there an existing javascript library which will deserialize Json.Net with reference loop handling?
{
"$id": "1",
"AppViewColumns": [
{
"$id": "2",
"AppView": {"$ref":"1"},
"ColumnID": 1,
}
]
}
this should deserialize to an object with a reference loop between the object in the array and the outer object
The answers given almost worked for me, but the latest version of MVC, JSON.Net, and DNX uses "$ref" and "$id", and they may be out of order. So I've modified user2864740's answer.
I should note that this code does not handle array references, which are also possible.
function RestoreJsonNetReferences(g) {
var ids = {};
function getIds(s) {
// we care naught about primitives
if (s === null || typeof s !== "object") { return s; }
var id = s['$id'];
if (typeof id != "undefined") {
delete s['$id'];
// either return previously known object, or
// remember this object linking for later
if (ids[id]) {
throw "Duplicate ID " + id + "found.";
}
ids[id] = s;
}
// then, recursively for each key/index, relink the sub-graph
if (s.hasOwnProperty('length')) {
// array or array-like; a different guard may be more appropriate
for (var i = 0; i < s.length; i++) {
getIds(s[i]);
}
} else {
// other objects
for (var p in s) {
if (s.hasOwnProperty(p)) {
getIds(s[p]);
}
}
}
}
function relink(s) {
// we care naught about primitives
if (s === null || typeof s !== "object") { return s; }
var id = s['$ref'];
delete s['$ref'];
// either return previously known object, or
// remember this object linking for later
if (typeof id != "undefined") {
return ids[id];
}
// then, recursively for each key/index, relink the sub-graph
if (s.hasOwnProperty('length')) {
// array or array-like; a different guard may be more appropriate
for (var i = 0; i < s.length; i++) {
s[i] = relink(s[i]);
}
} else {
// other objects
for (var p in s) {
if (s.hasOwnProperty(p)) {
s[p] = relink(s[p]);
}
}
}
return s;
}
getIds(g);
return relink(g);
}
I'm not aware of existing libraries with such support, but one could use the standard JSON.parse method and then manually walk the result restoring the circular references - it'd just be a simple store/lookup based on the $id property. (A similar approach can be used for reversing the process.)
Here is some sample code that uses such an approach. This code assumes the JSON has already been parsed to the relevant JS object graph - it also modifies the supplied data. YMMV.
function restoreJsonNetCR(g) {
var ids = {};
function relink (s) {
// we care naught about primitives
if (s === null || typeof s !== "object") { return s; }
var id = s['$id'];
delete s['$id'];
// either return previously known object, or
// remember this object linking for later
if (ids[id]) {
return ids[id];
}
ids[id] = s;
// then, recursively for each key/index, relink the sub-graph
if (s.hasOwnProperty('length')) {
// array or array-like; a different guard may be more appropriate
for (var i = 0; i < s.length; i++) {
s[i] = relink(s[i]);
}
} else {
// other objects
for (var p in s) {
if (s.hasOwnProperty(p)) {
s[p] = relink(s[p]);
}
}
}
return s;
}
return relink(g);
}
And the usage
var d = {
"$id": "1",
"AppViewColumns": [
{
"$id": "2",
"AppView": {"$id":"1"},
"ColumnID": 1,
}
]
};
d = restoreJsonNetCR(d);
// the following works well in Chrome, YMMV in other developer tools
console.log(d);
DrSammyD created an underscore plugin variant with round-trip support.
Ok so I created a more robust method which will use $id as well as $ref, because that's actually how json.net handles circular references. Also you have to get your references after the id has been registered otherwise it won't find the object that's been referenced, so I also have to hold the objects that are requesting the reference, along with the property they want to set and the id they are requesting.
This is heavily lodash/underscore based
(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
define(['lodash'], factory);
} else {
factory(_);
}
})(function (_) {
var opts = {
refProp: '$ref',
idProp: '$id',
clone: true
};
_.mixin({
relink: function (obj, optsParam) {
var options = optsParam !== undefined ? optsParam : {};
_.defaults(options, _.relink.prototype.opts);
obj = options.clone ? _.clone(obj, true) : obj;
var ids = {};
var refs = [];
function rl(s) {
// we care naught about primitives
if (!_.isObject(s)) {
return s;
}
if (s[options.refProp]) {
return null;
}
if (s[options.idProp] === 0 || s[options.idProp]) {
ids[s[options.idProp]] = s;
}
delete s[options.idProp];
_(s).pairs().each(function (pair) {
if (pair[1]) {
s[pair[0]] = rl(pair[1]);
if (s[pair[0]] === null) {
if (pair[1][options.refProp] !== undefined) {
refs.push({ 'parent': s, 'prop': pair[0], 'ref': pair[1][options.refProp] });
}
}
}
});
return s;
}
var partialLink = rl(obj);
_(refs).each(function (recordedRef) {
recordedRef['parent'][recordedRef['prop']] = ids[recordedRef['ref']] || {};
});
return partialLink;
},
resolve: function (obj, optsParam) {
var options = optsParam !== undefined ? optsParam : {};
_.defaults(options, _.resolve.prototype.opts);
obj = options.clone ? _.clone(obj, true) : obj;
var objs = [{}];
function rs(s) {
// we care naught about primitives
if (!_.isObject(s)) {
return s;
}
var replacementObj = {};
if (objs.indexOf(s) != -1) {
replacementObj[options.refProp] = objs.indexOf(s);
return replacementObj;
}
objs.push(s);
s[options.idProp] = objs.indexOf(s);
_(s).pairs().each(function (pair) {
s[pair[0]] = rs(pair[1]);
});
return s;
}
return rs(obj);
}
});
_(_.resolve.prototype).assign({ opts: opts });
_(_.relink.prototype).assign({ opts: opts });
});
I created a gist here