Nothing special - indexOf()
will return -1 in case of mismatch, not false or zero because we need zero just in case that was catched by QA.
Honestly in ES6/ES7 world we already have includes()
that will fit better in our case - we don't need to know substring position, just is it included or not. Or maybe RegExp
with special flag that will ignore case.
But because of initial requirenments my answer is:
function validateString(str) {
if (str.toLowerCase().indexOf('superman') === -1) {
throw new Error('String does not contain superman');
}
}
Btw I don't like uncautch exception here, boolean value as return seems more suitable in such cases, but without outer code it's just a proposal.
Just
function isPresented(arr, val) {
return arr.includes(val);
}
Ofcource we can talk about perfomance, even on level what is faster - for or while. But according to task desciption (no any note that this is crytical bottle-neck code) I think we can prefer readbility instead of other aspects. Maybe it's a good topic ๐ค to discuss on next step of hirhing process.
If regular expressions are not REQUIRED doesn't means that they are FORBIDDEN ๐. For function getNumbersFromString
regular expression is the best approuch I think.
Delimiter insertion tested with this tool. For validation I used only phone number length.
const Formatter = function (delimiter) {
const initialDelimiter = delimiter;
const getNumbersFromString = function (str) {
return str.replace(/\D/g,'');
}
const validatePhoneValue = function (phone) {
return phone.length === 10;
}
const insertDelimiter = function (phone, delimiter, position) {
return phone.substr(0, position) + delimiter + phone.substr(position);
}
const insertDelimiters = function (phone, delimiter) {
let updatedPhone = phone;
updatedPhone = insertDelimiter(updatedPhone, delimiter, 3);
updatedPhone = insertDelimiter(updatedPhone, delimiter, 7);
return updatedPhone;
}
const formatPhone = function (originalPhone, customDelimiter) {
let formattedPhone = getNumbersFromString(originalPhone)
if (validatePhoneValue(formattedPhone)) {
formattedPhone = insertDelimiters(formattedPhone, customDelimiter || initialDelimiter);
} else {
console.warn('Invalid phone was provided')
formattedPhone = null;
}
return formattedPhone;
}
return {
format: formatPhone
}
}
try { fizzBuzz(1, 0) } catch (e) {}
try { fizzBuzz(-1, 1) } catch (e) {}
try { fizzBuzz(1, -1) } catch (e) {}
fizzBuzz(1,1) === '1'
fizzBuzz(3,3) === 'Fizz'
fizzBuzz(5,5) === 'Buzz'
fizzBuzz(5, 6) === 'BuzzFizz'
fizzBuzz(15,15) === 'FizzBuzz'
fizzBuzz(7,9) === '78Fizz'
fizzBuzz(15,16) === 'FizzBuzz16'
Nor nested loops but huge RegExp ๐ฎ. I decided to merge all exclude patterns to one regexp with additional wild cart symbol for directories. After that we can filter all items during one loop. Technically during reduce we have one more loop too, but it's not nested. This is my favorite task today
Here is my solution:
const files = [
'/src/common/api.js',
'/src/common/preferences.js',
'/src/styles/main.css',
'/src/styles/base/_base.scss',
'/src/assets/apple-touch-icon-57.png',
];
const exclude = [
'/src/styles/',
'/src/assets/apple-touch-icon-57.png',
];
const patterns = exclude.reduce((result, current) => {
if (current.match(/\/$/)) {
current = current + '.';
}
return `${result}|(${current})`;
}, '').substr(1);
console.log(files.filter(file => !file.match(patterns)));
In this case we need to use any hash function, implementation doesn't matter I think. And we need to connect this result to hex values from #000000 to #FFFFFF. Maybe CRC24 will be most suitable because it has result in the same range. But there implementation is too difficult, so I prefer to use next:
function getHash(string) {
let hash = 0;
let index = 0;
const length = string.length;
if (length > 0) {
while (index < length) {
hash = (hash << 5) - hash + string.charCodeAt(index++) | 0;
}
}
return hash;
}
function getColorFromName(name) {
const hash = getHash(name);
const hex = hash.toString(16).padStart(6, "0");
return `#${hex.replace('-', '').substr(0, 6).toUpperCase()}`;
}
Hmmmmm, I think you provided already fixed code ๐ค Console output will be:
You clicked button #0
You clicked button #3
You have next code:
var nodes = document.querySelectorAll('button');
for (var i = 0; i < nodes.length; i++) {
nodes[i].addEventListener('click', function() {
console.log(`You clicked button #${i}`);
});
}
Why button index is always same. Please fix it. (instead of event handler feel free to use setTimeout)
Your example works correctly because of block scoped index variable - private scope of the for
blocks will store correct value each iteration.
Basically it enough to check Symbol.iterator
property. But we cannot do this in IE...
I haven't found 100% correct way to solve issue with IE, so I think my answer is to take code from most popular npm packet.
function isIterable(val) {
return (typeof Symbol !== 'undefined' && Symbol && 'iterator' in Symbol
&& val != null
&& (typeof val[Symbol.iterator] === 'function'));
}