I have the following code to implement singleton
const singleton = Symbol();
const singletonEnforcer = Symbol()
class SingletonTest {
constructor(enforcer) {
if(enforcer != singletonEnforcer) throw "Cannot construct singleton";
}
static get instance() {
if(!this[singleton]) {
this[singleton] = new SingletonTest(singletonEnforcer);
}
return this[singleton];
}
}
export default SingletonTest
And
import SingletonTest from 'singleton-test';
const instance = SingletonTest.instance;
I have a race condition problem , when SingletonTest.instance is executed at same time twice , I have two instance of SingletonTest , How can I solve issue?
Related
I'm trying to destructure return values of a Class instance method. Condider the snippet below
//define class of birds
class Birds {
//save each bird name
constructor(birdName, birdType = "Not Stated", canYouFly = true) {
this.birdName = birdName,
this.birdType = birdType,
this.canYouFly = canYouFly
}
//METHODS
introduce() {
return `hello, I'm ${this.birdName} of ${this.birdType} family`;
}
doYouFly() {
return this.canYouFly ? `Oh yeah! I fly baby` : `Oops! I'm not meant for that`;
}
}
//make new bird
let roi = new Birds("Roi", "Peacock", false);
//destructure
const { introduce, doYouFly } = roi;
console.log(introduce, doYouFly)
The code of the methods are logged to the console in this case.
Also, I tried
...
const { introduce(), doYouFly() } = roi;
...
Here, My IDE log the following error
expected Expression expected Declaration or Statement expected.
Now, my question is, is there a way to safely destructure return values of a class instance method?
In your (first) destructure assignment you are not calling the methods; you are just getting the function objects. The second attempt is indeed not valid syntax.
One way to make it work, is to define your methods as getters. So just prefix them with the keyword get:
//define class of birds
class Birds {
//save each bird name
constructor(birdName, birdType = "Not Stated", canYouFly = true) {
this.birdName = birdName,
this.birdType = birdType,
this.canYouFly = canYouFly
}
//METHODS
get introduce() {
return `hello, I'm ${this.birdName} of ${this.birdType} family`;
}
get doYouFly() {
return this.canYouFly ? `Oh yeah! I fly baby` : `Oops! I'm not meant for that`;
}
}
//make new bird
let roi = new Birds("Roi", "Peacock", false);
//destructure
const { introduce, doYouFly } = roi;
console.log(introduce, doYouFly)
Note that this changes the signature of your class. You would not add parentheses anymore to these getters in order to call them. They are now accessed as if they are plain properties:
console.log(roi.introduce);
I am working on a language that transpiles to javascript and has a similar syntax. However I want to include some new type of block statements. For syntax purposes they are the same as an IfStatement. How can I get esprima or acorn to parse this program MyStatement {a=1;} without throwing an error? Its fine if it calls it an IfStatement. I would prefer not to fork esprima.
It turns out, that the plugin capabilities of acorn are not really documented. It seems like forking acorn would be the easiest route. In this case, it is as simple as searching for occurances of _if and following a similar pattern for _MyStatement.
However it is possible to write a plugin to accomplish what I was trying to do. It seems a bit of a hack, but here is the code. The basic steps are:
To exend Parse and add to the list of keywords that will be recognized by the first pass
Create a TokenType for the new keyword and add it to the Parser.acorn.keywordTypes, extend parseStatement so that it processes the new TokenType
Create a handler for the new TokenType which will add information to the Abstract Syntax Tree as required by the keyword functionality and also consume tokens using commands like this.expect(tt.parenR) to eat a '(' or this.parseExpression() to process an entire expression.
Here is the code:
var program =
`
MyStatement {
MyStatement(true) {
MyStatement() {
var a = 1;
}
}
if (1) {
var c = 0;
}
}
`;
const acorn = require("acorn");
const Parser = acorn.Parser;
const tt = acorn.tokTypes; //used to access standard token types like "("
const TokenType = acorn.TokenType; //used to create new types of Tokens.
//add a new keyword to Acorn.
Parser.acorn.keywordTypes["MyStatement"] = new TokenType("MyStatement",{keyword: "MyStatement"});
//const isIdentifierStart = acorn.isIdentifierStart;
function wordsRegexp(words) {
return new RegExp("^(?:" + words.replace(/ /g, "|") + ")$")
}
var bruceware = function(Parser) {
return class extends Parser {
parse(program) {
console.log("hooking parse.");
//it appears it is necessary to add keywords here also.
var newKeywords = "break case catch continue debugger default do else finally for function if return switch throw try var while with null true false instanceof typeof void delete new in this const class extends export import super";
newKeywords += " MyStatement";
this.keywords = wordsRegexp(newKeywords);
return(super.parse(program));
}
parseStatement(context, topLevel, exports) {
var starttype = this.type;
console.log("!!!hooking parseStatement", starttype);
if (starttype == Parser.acorn.keywordTypes["MyStatement"]) {
console.log("Parse MyStatement");
var node = this.startNode();
return this.parseMyStatement(node);
}
else {
return(super.parseStatement(context, topLevel, exports));
}
}
parseMyStatement(node) {
console.log("parse MyStatement");
this.next();
//In my language, MyStatement doesn't have to have a parameter. It could be called as `MyStatement { ... }`
if (this.type == tt.parenL) {
node.test = this.parseOptionalParenExpression();
}
else {
node.test = 0; //If there is no test, just make it 0 for now (note that this may break code generation later).
}
node.isMyStatement = true; //set a flag so we know that this if a "MyStatement" instead of an if statement.
//process the body of the block just like a normal if statement for now.
// allow function declarations in branches, but only in non-strict mode
node.consequent = this.parseStatement("if");
//node.alternate = this.eat(acornTypes["else"]) ? this.parseStatement("if") : null;
return this.finishNode(node, "IfStatement")
};
//In my language, MyStatement, optionally has a parameter. It can also by called as MyStatement() { ... }
parseOptionalParenExpression() {
this.expect(tt.parenL);
//see what type it is
console.log("Type: ", this.type);
//allow it to be blank.
var val = 0; //for now just make the condition 0. Note that this may break code generation later.
if (this.type == tt.parenR) {
this.expect(tt.parenR);
}
else {
val = this.parseExpression();
this.expect(tt.parenR);
}
return val
};
}
}
process.stdout.write('\033c'); //cls
var result2 = Parser.extend(bruceware).parse(program); //attempt to parse
console.log(JSON.stringify(result2,null,' ')); //show the results.
For example, if I have 3 classes and 2 of them are part of the 3rd, how do I know that the types are correct and what to do if they're not:
class A {
constructor(someString) {
this.shouldBeString = someString
}
}
class B {
constructor(someBoolean) {
this.shouldBeBoolean = someBoolean
}
}
class C {
constructor(classAObject, classBObject) {
this.shouldBeClassAObj = classAObject
this.shouldBeClassBObj = classBObject
}
}
let a = new A("hello")
let b = new B(true)
let c = new C(a, b)
Is there some way in Javascript to deal with the lack of static types so that you don't have to write lines and lines of validation code? And if there is, and it fails, how do you handle a failed constructor? Do you return null, undefined, throw exception?
I am writing a custom operator to load a csv file and emit each line as data. This operator is supposed to work like the of operator, which is a static function to create observable. I follow the instruction of operator creation and add the operator function directly to Observable prototype.
All following code is written in JavaScript ES6.
My source code is this
import { Observable } from 'rxjs';
import { createInterface } from 'readline';
import { createReadStream } from 'fs';
function fromCSV(path, options) {
return Observable.create((subscriber) => {
let readStream = createReadStream(path);
let reader = createInterface({ input: readStream });
let isHeader = true;
let columns;
reader.on('line', (line) => {
if (isHeader) {
columns = line.split(',');
isHeader = false;
} else {
let values = line.split(',');
let valueObject = {};
for (let i = 0, n = columns.length; i < n; i++) {
valueObject[columns[i]] = values[i] || undefined;
}
subscriber.next(valueObject);
}
});
reader.on('close', () => subscriber.complete());
readStream.on('error', (error) => subscriber.error(error));
});
}
Observable.prototype.fromCSV = fromCSV;
The operator function looks totally correct, but when I try to use this operator like
import { Observable } from 'rxjs';
import './rx-from-csv';
Observable.fromCSV(testCSV)
.subscribe((row) => {
console.log(row);
});
It throws an error TypeError: _rxjs.Observable.fromCSV is not a function. So the function binding fails and I have no idea why it happens :-( Any help is appreciated.
This particularly confuses me because I have successfully done a similar operator binding for another custom csv operator.
The problem is that TypeScript doesn't know about the operator because it couldn't find it in RxJS's *.d.ts.
Have a look at how it's done by the default RxJS operators: https://github.com/ReactiveX/rxjs/blob/master/src/add/operator/bufferCount.ts
In you case you'll need just the declare module ... part with a correct path to the Observable definition. For example:
function fromCSV(path, options) {
...
}
Observable.prototype.fromCSV = fromCSV;
declare module 'rxjs/Observable' {
interface Observable<T> {
fromCSV: typeof fromCSV;
}
}
It turns out that I used a wrong way to add static function. See this post for more information.
To add a static function to the Observable class, the code needs to be
Observable.fromCSV = fromCSV;
Adding the function to the class's prototype will make it only available after newing that class.
I'm trying to implement some basic operations to the Set object like says here
This is the code
export class Conjunto extends Set<any>{
constructor(initialValues?) {
super();
return new Conjunto(initialValues);
}
isSuperset(subset) {
//some code
}
}
Do you guys have any idea to make it work? or am I doing something wrong?
For the moment I'm using the hack this guy found here
if you are trying to add functions to the Set prototype, or add polyfills to Set, you can do the following:
declare global {
interface Set<T> {
// polyfill
isSuperset(subset: Set<T>) : boolean;
// new function
someNewFunc(): boolean;
}
}
// add polyfill to the Set prototype as mentioned in the doc you provided: https://developer.mozilla.org/es/docs/Web/JavaScript/Referencia/Objetos_globales/Set
Set.prototype.isSuperset = function(subset) {
for (var elem of subset) {
if (!this.has(elem)) {
return false;
}
}
return true;
}
//add the new someNewFunc;
Set.prototype.someNewFunc = function() {
// some logic here...
return true;
}
to use:
stringSet = new Set<string>()
stringSet.isSuperset(someOtherSet);
stringSet.someNewFunc(); // returns true