eliminating duplication not working as expected - javascript

I'm defining a processor method that returns the lower-case version of the content to achieve this behaviour:
> phrase = new TranslatedPhrase("recognize", "reconocer");
> phrase.palindrome();
true
function reverse(string) {
return Array.from(string).reverse().join("");
}
function Phrase(content) {
this.content = content;
this.processor = function(string) {
return string.toLowerCase();
}
this.processedContent = function processedContent() {
return this.processor(this.content);
}
// Returns true if the phrase is a palindrome, false otherwise.
this.palindrome = function palindrome() {
return this.processedContent() === reverse(this.processedContent());
}
}
function TranslatedPhrase(content, translation) {
this.content = content;
this.translation = translation;
// Returns translation processed for palindrome testing.
this.processedContent = function processedContent() {
return this.processor(this.translation);
}
}
I also tried return this.string.toLowerCase(); but this also doesn't work.
The error I'm currently getting is this:
> let phrase = new TranslatedPhrase("recognize", "reconocer");
undefined
> phrase.palindrome();
Thrown:
TypeError: phrase.palindrome is not a function
Any suggestions as to what I'm missing are greatly appreciated, thx!

Related

Need help solving this method chaining question?

I got asked this in an Interview and I couldn't solve it. Was wondering if any of you guys can help me.
fn("hello").fn("world").fn("!!!").fn();
function fn (str){
// Enter Solution Here
}
The solution should return 'hello world !!!'.
I tried method chaining and was able to get a partially right answer which is as follows:
function fn(str) {
var string = str;
this.fn1 = function(str1) {
string += " "+str1;
return this;
}
this.fn = function() {
console.log(string)
}
}
new fn("hello").fn1("world").fn1("!!!").fn();
but as you can see I cant get it to work unless I use fn1 as the function to concat the string. Any help will be appreciated, thanks.
Have the function return an object with one fn method. If, when you call it, it has an argument, update the string, otherwise return the string so you can log it.
function fn(str = '') {
return {
fn: function (s) {
if (s) {
str += ` ${s}`;
return this;
}
return str;
}
};
}
const output = fn('hello').fn('world').fn('!!!').fn();
console.log(output);
Additional documentation
Template/string literals
You could return an object with two properties, one for returning the complete string and another for collecting parts and retuning the object.
function fn(str) {
const
fns = {
fn: function () {
return str;
},
fn1: function (s) {
str += ' ' + s;
return fns;
}
};
return fns;
}
console.log(fn("hello").fn1("world").fn1("!!!").fn());
I think this should do the trick:
function fn(s){
return new function(){
this.str = s;
this.fn = (ns) => {if(ns){this.str += " "+ns; return this;} else return this.str;};
}
}
let a = fn("hello").fn("world").fn("!!!").fn();
console.log(a);
Seems like you need to use objects
const generic = {
"fn1":null,
"current":"",
"fn": () => {
//what do you want to do with "this.current"?
}
}
function fn(str) {
var ret = generic;
ret.fn1 = (wa) =>{
var again = generic;
again.current +=wa;
return again;
}
ret.current += str;
return ret;
}
You can return an object with a .fn() method which will
check if an argument is passed in or not to determine when to terminate the chain or continue chaining.
When no argument is sent, then it simply returns the accumulated string.
Otherwise, it calls fn() function again to accumulate to the string and get the next copy of the same structure as before:
const result = fn("hello").fn("world").fn("!!!").fn();
console.log(result);
function fn (str){
return {
fn(nextString) {
if (nextString === undefined)
return str;
return fn(`${str} ${nextString}`);
}
};
}
Since this operation is immutable, it means each link in the chain is independent, therefore it is no problem with assigning to variables to continue with different chains:
const helloWorld = fn("hello").fn("world");
const one = helloWorld.fn("one").fn();
const two = helloWorld.fn("two").fn();
const three = helloWorld.fn("three").fn();
console.log(one);
console.log(two);
console.log(three);
function fn (str){
return {
fn(nextString) {
if (nextString === undefined)
return str;
return fn(`${str} ${nextString}`);
}
};
}

How to implement more than one method in JS es6 class?

I have a class of validations that I have created in JS:
let test = new Validator(req.body);
Now I want to test something, maybe that a specific key in this object is 2-5 char length, I would do it like this:
let myBoolean = test.selector("firstName").minLength(2).maxLength(5);
// firstName is like: req.body.firstName
And how this could be done in the class?
EDIT
I made something like this:
audit.isLength({selector: "from", gte: 2, lte: 35})
class Validator {
constructor(obj) {
this.obj = obj;
this.isValid = true;
}
isExists(sel) {
if (typeof this.obj[sel] === "undefined") return false;
return true;
}
isLength(info) {
let sel = this.obj[info.selector];
if (typeof sel === "undefined") return false;
if (info.gte) {
if (sel.length<info.gte) return false;
}
if (info.lte) {
if (sel.length>info.lte) return false;
}
if (info.gt) {
if (sel.length<=info.gt) return false;
}
if (info.lt) {
if (sel.length>=info.lt) return false;
}
return true;
}
}
Try something like this - assign the object to validate to a property on the instantiation, return this from each validating call, and when validating, assign to an isValid property on the object (if it isn't already false). Note that you need to access the isValid property finally in order to retrieve the boolean.
class Validator {
constructor(obj) {
this.obj = obj;
this.isValid = true;
}
selector(sel) {
this.sel = sel;
return this;
}
minLength(min) {
if (this.isValid) this.isValid = this.obj[this.sel].length >= min;
return this;
}
maxLength(max) {
if (this.isValid) this.isValid = this.obj[this.sel].length <= max;
return this;
}
}
const test = new Validator({firstName: 'foobar'}); // 6 chars: invalid
console.log(test.selector("firstName").minLength(2).maxLength(5).isValid);
const test2 = new Validator({firstName: 'fooba'}); // 5 chars: valid
console.log(test2.selector("firstName").minLength(2).maxLength(5).isValid);
const test3 = new Validator({firstName: 'f'}); // 1 char: invalid
console.log(test3.selector("firstName").minLength(2).maxLength(5).isValid);
Create a class with fluent methods/chainable methods, that return this, which is an instance of the class itself and when you finally run validation according to the rules, call .validate(), which will act as a final method to return the result:
class Validator {
constructor (body) {
this._body = body;
}
selector(str) {
this._selector = str;
return this;
}
minLength(num) {
this._minLength = num;
return this;
}
maxLength(num) {
this._maxLength = num;
return this;
}
validate() {
// run your validation logic here and return true or false accordingly
return true
}
}
const req = { body: 'body' };
const test = new Validator(req.body);
const myBoolean = test
.selector('firstName')
.minLength(2)
.maxLength(5)
.validate();
console.log('rules:');
console.log(test);
console.log(`result: ${myBoolean}`);
This is the builder pattern (sort of). You'll probably want to define a separate class that has a minLength and maxLength function. Those functions will set some state on the builder, and return either this (the builder its self), or a new builder that's a copy of this. Then you'd have some finalize function on the builder, which looks at the state, handles all the logic based on the min/max, and returns a boolean.

Javascript adding variable to a regular expression

I've written the following function in Typescript:
public searchPosts(keyword ? : string): Post[] {
return this._posts.filter(function(post) {
if (post.title.search(new RegExp('money', 'gi')) >= 0) {
return post;
}
});
}
It's working just fine but, I need to make it a little dynamic so that instead of hardcoded value i.e. money, I can put my keyword variable in RegExp (new RegExp(keyword, 'gi')). But doing so does not return anything even for 'money' as a keyword.
Any ideas on what I'm doing wrong here?
This is how it should work
var keyword = '345';
var f = ['1234', '3456'].filter(function(post) {
return (post.search(new RegExp(keyword, 'gi')) >= 0);
});
console.log(f);
This is your function in pure JS
var posts = [{title: '1234'}, {title: '3456'}];
function searchPosts (keyword) {
return posts.filter(function(post) {
return (post.title.search(new RegExp(keyword, 'gi')) >= 0);
});
}
console.log(searchPosts('345'));
If this doesnt work, the problem is somewhere else ;].

Evaluate passed value using .filter in JavaScript

I have a method that takes a language abbreviation and matches it using a .constant dictionary, and returns the matching language name.
How can I do an evaluation with .filter to check whether the passed isoCode/language abbreviation exists?
Here is my method:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
var categoryObject = Languages.filter(function ( categoryObject ) {
return categoryObject.code === isoCode;
})[0];
return categoryObject.name;
};
}]);
Here is the method with some error catching I have tried:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
var categoryObject = Languages.filter(function (categoryObject) {
if (isoCode != null || isoCode != undefined) {
return categoryObject.code === isoCode;
}
else {
return categoryObject.code === 'und';
}
})[0];
if (categoryObject.name != undefined || categoryObject.name != null) {
return categoryObject.name;
}
else {
return "undefined";
}
};
}]);
Thank you!
I would recommend you organize your data at Languagesin an object or map, it'll be much faster and simpler when you fetch your translation by an abbreviation. A short example:
angular.module('portalDashboardApp')
.factory('Languages', function(){
var dictionary = {
ISO: {name: 'International Organization for Standardization'}
};
return {
get: function(abbr){
return dict[abbr];
}
};
}).service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
if(!isoCode) {
return "Answer for empty isoCode";
}
var categoryObject = Languages.get(isoCode);
return (categoryObject || {}).name || "I don't know this abbr";
};
}]);
I'm not sure that this JS works without any syntax error (I've not try to launch it) but idea is that you don't need array and filter on big dictionaries and you are able to get any abbreviation from dict with O(1) complexity even with huge dictionary.
If you don't want to have a refactoring with your code you can do something like this:
angular.module('portalDashboardApp')
.service('ISOtoLanguageService', ['Languages', function(Languages) {
this.returnLanguage = function(isoCode) {
if (!isoCode) {
return;
}
var resultAbbrs = Languages.filter(function (categoryObject) {
return categoryObject.code === isoCode;
});
if (resultAbbrs.length > 0) {
return resultAbbrs[0].name;
}
};
}]);
In this case if isoCode is null, undefined or empty string or this key is not found in dictionary return undefined will be by default. Outside you should check a result of this function with if (result === undefined) ...
I hope it helped you)

Cant figure out why this is giving me a TypeError

I have written a function wherein I want the arguments to be concatenated with a space:
function sayIt(str) {
var stringCollection = [];
this.addToCollection = function(str){
stringCollection.push(str);
if(!str){ // for the () part in the call
return stringCollection.join(" ");
}
};
return this.addToCollection(str);
}
console.log(sayIt('my')('name')('is')('Harry')()); // should log "my name is Harry"
Its giving me a TypeError. Any idea, why?
You are not returning a function when you have a word as an argument -- try this;
function sayIt(str) {
var stringCollection = [];
function concat(str){
stringCollection.push(str);
if(!str){ // for the () part in the call
return stringCollection.join(" ");
}
return concat;
};
return concat(str);
}
alert(sayIt('my')('name')('is')('Harry')()); // should log "my name is Harry"
I don't quite fancy the design of your method because it appears fragile to me, but I am sure you have a rationale behind it.
Modify
this.addToCollection = function(str){
stringCollection.push(str);
if(!str){ // for the () part in the call
return stringCollection.join(" ");
}
};
To
this.addToCollection = function(str){
stringCollection.push(str);
if(!str){ // for the () part in the call
return stringCollection.join(" ");
}
return this.addToCollection;
};

Categories