make sure a solution always shows up, use "demo" if exists
This commit is contained in:
parent
360be9ed99
commit
408ba7d4e4
25 changed files with 59 additions and 95 deletions
|
@ -1,10 +1 @@
|
|||
Just loop over the object and `return false` immediately if there's at least one property.
|
||||
|
||||
```js
|
||||
function isEmpty(obj) {
|
||||
for (let key in obj) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
```
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
``` js run
|
||||
|
||||
// before the call
|
||||
let menu = {
|
||||
width: 200,
|
||||
height: 300,
|
||||
title: "My menu"
|
||||
};
|
||||
|
||||
function multiplyNumeric(obj) {
|
||||
for (let key in obj) {
|
||||
if (typeof obj[key] == 'number') {
|
||||
obj[key] *= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
alert(menu);
|
||||
```
|
|
@ -1,6 +1,5 @@
|
|||
|
||||
|
||||
```js run demo
|
||||
```js run demo solution
|
||||
let calculator = {
|
||||
sum() {
|
||||
return this.a + this.b;
|
||||
|
@ -20,4 +19,3 @@ calculator.read();
|
|||
alert( calculator.sum() );
|
||||
alert( calculator.mul() );
|
||||
```
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
The solution is to return the object itself from every call.
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
let ladder = {
|
||||
step: 0,
|
||||
up() {
|
||||
|
@ -28,7 +28,7 @@ ladder.up().up().down().up().down().showStep(); // 1
|
|||
|
||||
We also can write a single call per line. For long chains it's more readable:
|
||||
|
||||
```js
|
||||
```js
|
||||
ladder
|
||||
.up()
|
||||
.up()
|
||||
|
@ -37,4 +37,3 @@ ladder
|
|||
.down()
|
||||
.showStep(); // 1
|
||||
```
|
||||
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
|
||||
|
||||
```js run demo
|
||||
function Calculator() {
|
||||
|
||||
|
|
|
@ -2,10 +2,9 @@ The maximal length must be `maxlength`, so we need to cut it a little shorter, t
|
|||
|
||||
Note that there is actually a single unicode character for an ellipsis. That's not three dots.
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function truncate(str, maxlength) {
|
||||
return (str.length > maxlength) ?
|
||||
return (str.length > maxlength) ?
|
||||
str.slice(0, maxlength - 1) + '…' : str;
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -1,5 +0,0 @@
|
|||
```js run
|
||||
function extractCurrencyValue(str) {
|
||||
return +str.slice(1);
|
||||
}
|
||||
```
|
|
@ -1,4 +1,4 @@
|
|||
# The slow solution
|
||||
# Slow solution
|
||||
|
||||
We can calculate all possible subsums.
|
||||
|
||||
|
@ -67,7 +67,7 @@ Let's walk the array and keep the current partial sum of elements in the variabl
|
|||
|
||||
If the description is too vague, please see the code, it's short enough:
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function getMaxSubSum(arr) {
|
||||
let maxSum = 0;
|
||||
let partialSum = 0;
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
function camelize(str) {
|
||||
return str
|
||||
.split('-') // my-long-word -> ['my', 'long', 'word']
|
||||
.map(
|
||||
.split('-') // splits 'my-long-word' into array ['my', 'long', 'word']
|
||||
.map(
|
||||
// capitalizes first letters of all array items except the first one
|
||||
// converts ['my', 'long', 'word'] into ['my', 'Long', 'Word']
|
||||
(word, index) => index == 0 ? word : word[0].toUpperCase() + word.slice(1)
|
||||
) // ['my', 'long', 'word'] -> ['my', 'Long', 'Word']
|
||||
.join(''); // ['my', 'Long', 'Word'] -> myLongWord
|
||||
)
|
||||
.join(''); // joins ['my', 'Long', 'Word'] into 'myLongWord'
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ Let's walk the array items:
|
|||
- For each item we'll check if the resulting array already has that item.
|
||||
- If it is so, then ignore, otherwise add to results.
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function unique(arr) {
|
||||
let result = [];
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
``` js run
|
||||
```js run demo
|
||||
function filterRange(arr, a, b) {
|
||||
// added brackets around the expression for better readability
|
||||
return arr.filter(item => (a <= item && item <= b));
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
|
||||
|
||||
function filterRangeInPlace(arr, a, b) {
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
|
@ -12,4 +11,4 @@ function filterRangeInPlace(arr, a, b) {
|
|||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
``` js run
|
||||
```js run demo
|
||||
function filterRangeInPlace(arr, a, b) {
|
||||
|
||||
for (let i = 0; i < arr.length; i++) {
|
||||
|
@ -18,5 +18,4 @@ let arr = [5, 3, 8, 1];
|
|||
filterRangeInPlace(arr, 1, 4); // removed the numbers except from 1 to 4
|
||||
|
||||
alert( arr ); // [3, 1]
|
||||
|
||||
```
|
||||
|
|
|
@ -59,7 +59,7 @@ Here we could also use a plain object instead of the `Map`, because keys are str
|
|||
|
||||
That's how the solution can look:
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function aclean(arr) {
|
||||
let obj = {};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
```js run
|
||||
```js run demo
|
||||
function sumSalaries(salaries) {
|
||||
|
||||
let sum = 0;
|
||||
|
@ -8,7 +8,22 @@ function sumSalaries(salaries) {
|
|||
|
||||
return sum; // 650
|
||||
}
|
||||
|
||||
let salaries = {
|
||||
"John": 100,
|
||||
"Pete": 300,
|
||||
"Mary": 250
|
||||
};
|
||||
|
||||
alert( sumSalaries(salaries) ); // 650
|
||||
```
|
||||
Or, optionally, we could also get the sum using `Object.values` and `reduce`:
|
||||
|
||||
`Object.values(salaries).reduce((a, b) => a + b) // 650`
|
||||
```js
|
||||
// reduce loops over array of salaries,
|
||||
// adding them up
|
||||
// and returns the result
|
||||
function sumSalaries(salaries) {
|
||||
return Object.values(salaries).reduce((a, b) => a + b, 0) // 650
|
||||
}
|
||||
```
|
||||
|
|
|
@ -2,7 +2,7 @@ The method `date.getDay()` returns the number of the weekday, starting from sund
|
|||
|
||||
Let's make an array of weekdays, so that we can get the proper day name by its number:
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function getWeekDay(date) {
|
||||
let days = ['SU', 'MO', 'TU', 'WE', 'TH', 'FR', 'SA'];
|
||||
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
```js run
|
||||
function getLocalDay(date) {
|
||||
|
||||
let day = date.getDay();
|
||||
|
||||
if (day == 0) { // 0 becomes 7
|
||||
day = 7;
|
||||
}
|
||||
|
||||
return day;
|
||||
}
|
||||
|
||||
alert( getLocalDay(new Date(2012, 0, 3)) ); // 2
|
||||
```
|
|
@ -11,7 +11,7 @@ function getDateAgo(date, days) {
|
|||
|
||||
To implement it let's clone the date, like this:
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function getDateAgo(date, days) {
|
||||
let dateCopy = new Date(date);
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
Let's create a date using the next month, but pass zero as the day:
|
||||
```js run
|
||||
```js run demo
|
||||
function getLastDayOfMonth(year, month) {
|
||||
let date = new Date(year, month + 1, 0);
|
||||
return date.getDate();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
To get the time from `date` till now -- let's substract the dates.
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function formatDate(date) {
|
||||
let diff = new Date() - date; // the difference in milliseconds
|
||||
|
||||
|
@ -57,12 +57,12 @@ function formatDate(date) {
|
|||
let diffSec = Math.round(diffMs / 1000);
|
||||
let diffMin = diffSec / 60;
|
||||
let diffHour = diffMin / 60;
|
||||
|
||||
|
||||
// formatting
|
||||
year = year.toString().slice(-2);
|
||||
month = month < 10 ? '0' + month : month;
|
||||
dayOfMonth = dayOfMonth < 10 ? '0' + dayOfMonth : dayOfMonth;
|
||||
|
||||
|
||||
if (diffSec < 1) {
|
||||
return 'right now';
|
||||
} else if (diffMin < 1) {
|
||||
|
|
|
@ -14,7 +14,7 @@ alert( arr.filter(inBetween(3, 6)) ); // 3,4,5,6
|
|||
|
||||
# Filter inArray
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function inArray(arr) {
|
||||
return function(x) {
|
||||
return arr.includes(x);
|
||||
|
|
|
@ -55,9 +55,9 @@ function makeArmy() {
|
|||
|
||||
As a result, all `shooter` functions get from the outer lexical envrironment the same, last value `i=10`.
|
||||
|
||||
The fix can be very simple:
|
||||
We can fix it by moving the variable definition into the loop:
|
||||
|
||||
```js run
|
||||
```js run demo
|
||||
function makeArmy() {
|
||||
|
||||
let shooters = [];
|
||||
|
@ -80,9 +80,9 @@ army[0](); // 0
|
|||
army[5](); // 5
|
||||
```
|
||||
|
||||
Now it works correctly, because every time the code block in `for (..) {...}` is executed, a new Lexical Environment is created for it, with the corresponding value of `i`.
|
||||
Now it works correctly, because every time the code block in `for (let i=0...) {...}` is executed, a new Lexical Environment is created for it, with the corresponding variable `i`.
|
||||
|
||||
So, the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds the current loop iteration. A `shooter` gets the value exactly from the one where it was created.
|
||||
So, the value of `i` now lives a little bit closer. Not in `makeArmy()` Lexical Environment, but in the Lexical Environment that corresponds the current loop iteration. That's why now it works.
|
||||
|
||||

|
||||
|
||||
|
@ -90,7 +90,6 @@ Here we rewrote `while` into `for`.
|
|||
|
||||
Another trick could be possible, let's see it for better understanding of the subject:
|
||||
|
||||
|
||||
```js run
|
||||
function makeArmy() {
|
||||
let shooters = [];
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
The solution:
|
||||
|
||||
```js
|
||||
```js run demo
|
||||
function delay(f, ms) {
|
||||
|
||||
return function() {
|
||||
|
@ -8,20 +8,25 @@ function delay(f, ms) {
|
|||
};
|
||||
|
||||
}
|
||||
|
||||
let f1000 = delay(alert, 1000);
|
||||
|
||||
f1000("test"); // shows "test" after 1000ms
|
||||
```
|
||||
|
||||
Please note how an arrow function is used here. As we know, arrow functions do not have own `this` and `arguments`, so `f.apply(this, arguments)` takes `this` and `arguments` from the wrapper.
|
||||
|
||||
If we pass a regular function, `setTimeout` would call it without arguments and `this=window` (in-browser), so we'd need to write a bit more code to pass them from the wrapper:
|
||||
If we pass a regular function, `setTimeout` would call it without arguments and `this=window` (assuming we're in the browser).
|
||||
|
||||
We still can pass the right `this` by using an intermediate variable, but that's a little bit more cumbersome:
|
||||
|
||||
```js
|
||||
function delay(f, ms) {
|
||||
|
||||
// added variables to pass this and arguments from the wrapper inside setTimeout
|
||||
return function(...args) {
|
||||
let savedThis = this;
|
||||
let savedThis = this; // store this into an intermediate variable
|
||||
setTimeout(function() {
|
||||
f.apply(savedThis, args);
|
||||
f.apply(savedThis, args); // use it here
|
||||
}, ms);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
|
||||
|
||||
```js run no-beautify
|
||||
```js demo
|
||||
function debounce(f, ms) {
|
||||
|
||||
let isCooldown = false;
|
||||
|
@ -18,7 +16,7 @@ function debounce(f, ms) {
|
|||
}
|
||||
```
|
||||
|
||||
The call to `debounce` returns a wrapper. There may be two states:
|
||||
A call to `debounce` returns a wrapper. There may be two states:
|
||||
|
||||
- `isCooldown = false` -- ready to run.
|
||||
- `isCooldown = true` -- waiting for the timeout.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
```js
|
||||
```js demo
|
||||
function throttle(func, ms) {
|
||||
|
||||
let isThrottled = false,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue