Accessing 'this' inside JS iterator's next() method? [duplicate] - javascript

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);
}

Related

Uexpected Function Behavior. JS Classes

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());

JavaScript Array Sort with Dynamic Column [duplicate]

This question already has answers here:
JavaScript property access: dot notation vs. brackets?
(17 answers)
Closed 3 years ago.
I have some code using JavaScript Array Sorting that works but seems to be really inefficient.
I have an array of objects defined as follows for example purposes
dummyData = [];
dummyData.push({ col01:"aa", col02:"ac", col03:"ab" });
dummyData.push({ col01:"ab", col02:"ab", col03:"ac" });
dummyData.push({ col01:"ac", col02:"aa", col03:"aa" });
Which I can then sort on col01 using a function like this
function f_sort_col01(dataArg) {
dataArg.sort(function(res01, res02) {
var arg01 = res01.col01.toLowerCase();
var arg02 = res02.col01.toLowerCase();
if(arg01 < arg02) { return -1; }
if(arg01 > arg02) { return 1; }
return 0;
});
return dataArg;
}
This works just fine but the problem is that when I need to sort on a different column I then have to create an entire new function like this
function f_sort_col02(dataArg) {
dataArg.sort(function(res01, res02) {
var arg01 = res01.col02.toLowerCase();
var arg02 = res02.col02.toLowerCase();
if(arg01 < arg02) { return -1; }
if(arg01 > arg02) { return 1; }
return 0;
});
return dataArg;
}
Which is pretty much the same thing only on a different column. I was wondering if it's possible to do something along the lines of this
function f_sort(dataArg, colName) {
dataArg.sort(function(res01, res02) {
var arg01 = res01.colName.toLowerCase();
var arg02 = res02.colName.toLowerCase();
if(arg01 < arg02) { return -1; }
if(arg01 > arg02) { return 1; }
return 0;
});
return dataArg;
}
So that the name of the column can be included in the parameters
Use square brackets like following
function f_sort(dataArg, colName) {
dataArg.sort(function(res01, res02) {
var arg01 = res01[colName].toLowerCase();
var arg02 = res02[colName].toLowerCase();
if(arg01 < arg02) { return -1; }
if(arg01 > arg02) { return 1; }
return 0;
});
return dataArg;
}
You coud reverse the approach by using a closure over the wanted key.
function sortBy(key) {
return function (a, b) {
return a[key].toLowerCase().localeCompare(b[key].toLowerCase());
};
}
var data = [{ col01: "aa", col02: "ac", col03: "ab" }, { col01: "ab", col02: "ab", col03: "ac" }, { col01: "ac", col02: "aa", col03: "aa" }];
console.log(data.sort(sortBy('col01')));
console.log(data.sort(sortBy('col02')));
console.log(data.sort(sortBy('col03')));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Use [colName] instead of .colName
function f_sort(dataArg, colName) {
dataArg.sort(function(res01, res02) {
var arg01 = res01[colName].toLowerCase();
var arg02 = res02[colName].toLowerCase();
if(arg01 < arg02) { return -1; }
if(arg01 > arg02) { return 1; }
return 0;
});
return dataArg;
}
Square bracket notation:
var arg01 = res01[colName].toLowerCase();
var arg02 = res02[colName].toLowerCase();

Javascript loop not returning true, when String === String

When looping through an array to find if the array contains a word that I am looking for, the loop always returns 'false' when if I console.log out the what is being compared I can clearly see that the word I am looking for (collectionNameLookingFor) is in the array (collectionNameArray) so it should return true.
function checkCollectionNames(arrayOfCollections, collectionName) {
for (let i = 0; i < arrayofCollections.length; i++) {
if (arrayOfCollections[i] === collectionName) {
return true;
}
}
return false;
}
function saveContentToDb(req, res) {
const db = getDb();
const pageDetails = req.body;
let saveType;
db.db(pageDetails.databaseName).listCollections().toArray((error, collections) => {
if (error) {
throw error;
} else {
collections.map(collection => (collection.name)).forEach(collectionNameArray => {
const collectionNameLookingFor = req.body.page;
const check = checkCollectionNames(collectionNameArray, collectionNameLookingFor);
console.log('===========Looking to see if it is true or false==========');
console.log(check);
console.log(`Name of collection in Database: ${collectionNameArray} ::: ${collectionNameLookingFor}`);
console.log('==========================================================');
if (check === true) {
saveType = 'updated';
console.log(`saveType = ${saveType}`);
} else {
saveType = 'created';
console.log(`saveType = ${saveType}`);
}
});
}
});
}
You might need to check against collectionName, because that is the parameter you hand over, beside arrayOfCollections, instead of the array itself.
function checkCollectionNames(arrayOfCollections, collectionName) {
for (let i = 0; i < arrayOfCollections.length; i++) {
if (arrayOfCollections[i] === collectionName) {
return true;
}
}
return false;
}
Short Version:
function checkCollectionNames(arrayOfCollections, collectionName) {
return arrayOfCollections.includes(collectionName);
}

Java Script: Assignment operator not working for a matrix

I'm trying to populate a matrix that I declared with random variables, but for some explicable reason the random values aren't being assigned to the cells in the Matrix.
Here is the declaration of said matrix:
this.weights_ih= new Matrix(this.hidden_nodes,this.input_nodes);
Please Keep in mind that this declaration is is part of a constructor of a class as shown below:
class NeuralNetwork
{
constructor (input_nodes,hidden_nodes,output_nodes)
{
this.input_nodes=input_nodes;
this.output_nodes=output_nodes;
this.hidden_nodes=hidden_nodes;
this.weights_ih= new Matrix(this.hidden_nodes,this.input_nodes);
this.weights_ho= new Matrix(this.output_nodes,this.hidden_nodes);
this.weights_ih.randomize();
this.weights_ho.randomize();
this.bias_h= new Matrix(this.hidden_nodes,1);
this.bias_0= new Matrix(this.output_nodes,1);
this.bias_h.randomize();
this.bias_0.randomize();
this.learning_rate=0.1;
}
}
The randomize() function returns a value between 1 and -1 and the definition is given below:
randomize()
{
for(let i=0;i<this.rows;i++)
{
for(let j=0;j<this.cols;j++)
{
this.data[i][j]=Math.floor(Math.random()*2 -1);
}
}
}
I have made sure that the randomize() is working as I did console log the variable this.data[i][j]. Here is the screen shot of that:
Therefore I assumed that the randomize() was not to blame as it was generating random values as expected and the data was being assigned to this.data[i][j].
But when I tabled the matrix this.weights_ih. This was the output I received:
I really do not understand why all the cells are undefined as in the randomize()values were being assigned to the variable this.data[i][j].
Do let me know if I've made an error.
Here's the Matrix class definition if that in any way might help you:
class Matrix
{
constructor (rows,cols)
{
this.rows=rows;
this.cols=cols;
this.data=[];
for(let i=0;i<this.rows;i++)
{
this.data[i]=[];
for(let j=0;j<this.cols;j++)
{
let temp=this.data[i];
temp[j]=0;
//this.data[i][j]=0;
}
}
}
static transpose(matrix)
{
let result = new Matrix(matrix.cols,matrix.rows)
for (let i=0;i<matrix.rows;i++)
{
for(let j=0;j<matrix.cols;j++)
{
result.data[j][i]=matrix.data[i][j];
}
}
return result;
}
toArray()
{
let arr=[];
for(let i=0;i<this.rows;i++)
{
for(let j=0;j<this.cols;j++)
{
arr.push(this.data[i][j]);
}
}
return arr;
}
static fromArray(arr)
{
let m= new Matrix(arr.length,1);
let v= arr.length;
for(let i=0;i<v;i++)
{
m.data[i][0]=arr[i];
}
return m;
}
randomize()
{
console.log("Rows:"+this.rows+"cols"+this.cols);
for(let i=0;i<this.rows;i++)
{
for(let j=0;j<this.cols;j++)
{
this.data[i][j]=Math.floor(Math.random()*2 -1);
}
}
}
static subtract(a,b)
{
let result= new Matrix(a.rows,a.cols);
for( let i=0;i<result.rows;i++)
{
for(let j=0;j<result.cols;j++)
{
result.data[i][j]=a.data[i][j]-b.data[i][j];
}
}
return result;
}
add(n)
{
if(n instanceof Matrix)
{
for( let i=0;i<this.rows;i++)
{
for(let j=0;j<this.cols;j++)
{
this.data[i][j]+=n.data[i][j];
}
}
}
else
{
for( let i=0;i<this.rows;i++)
{
for(let j=0;j<this.cols;j++)
{
this.data[i][j]+=n;
}
}
}
}
static multiply(a,b)
{
if(a.cols!==b.rows)
{
console.log("Error 001");
return undefined;
}
let result = new Matrix(a.rows,b.cols);
let sum=0;
for(let i=0;i<result.rows;i++)
{
for(let j=0;j<result.cols;j++)
{
sum=0;
for(let k=0;k<a.cols;k++)
{
sum+=a.data[i][k]*b.data[k][j];
}
result.data[i][j]=sum;
}
}
return result;
}
multiply(n)
{
for( let i=0;i<this.rows;i++)
{
for(let j=0;j<this.cols;j++)
{
this.data[i][j]*=n;
}
}
}
map(func)
{
//Apply a fucntion to every element
for( let i=0;i<this.rows;i++)
{
for(let j=0;j<this.cols;j++)
{
let val = this.data[i][j];
this.data[i][j]=func(val);
}
}
}
static map(matrix,func)
{
let result= new Matrix(matrix.rows, matrix.cols);
for(let i=0;i<matrix.rows;i++)
{
for(let j=0;j<matrix.cols;j++)
{
let val= matrix.data[i][j];
result.data[i][j]=func(val);
}
}
return result;
}
print()
{
console.table(this.data);
}
}
NeuralNetwork Declaration:
function setup()
{
let nn= new NeuralNetwork(2,2,2);
let input=[1,0];
let targets=[1,1];
nn.train(input,targets);
}
Thanks In Advance!

Chrome storage custom serialization

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);

Categories