手写算法: 杨辉三角
思路
杨辉三角的特点是,第 0 行 1 个元素,第 1 行 2 个元素,第 2 行 3 个元素,依次类推
同一行里首尾两个元素都是为 1,计算中间的即可,中间 = 上一行同一列的元素 + 上一行前一列的元素
要点就是上面两点,记住即可计算
/**
* @param {number} numRows
* @return {number[][]}
*/
var generate = function(numRows) {
let result = [];
for (let i = 0; i < numRows; i++) {
// 计算每行的个数
let row = new Array(i + 1).fill(1);
for (let j = 1; j < row.length - 1; j++) {
// 上一行同一列 + 上一行前一列
row[j] = result[i - 1][j] + result[i - 1][j - 1];
}
result.push(row);
}
return result;
};
手写题
找到第一个重复的字符
/**
* @param {string} str
* @return {string | null}
*/
function firstDuplicate(str) {
let set = new Set();
for (let i = 0; i < str.length; i++) {
if (set.has(str[i])) {
return str[i];
}
set.add(str[i]);
}
return null;
}
优化一个 function
思路
理解题意:exclude 的意思是排除,在 items 里面排除 exclude 包含的内容,只要一项满足,就算满足条件。
用 map 储存 excludes 的内容,按照 items 的格式以 key-value 的形式存储。同是一类的即保存在一块。
遍历 items 筛选出未被排除的项目,判断 map 中是否存在对应的 key
Array.prototype.some(),只要一个元素执行完回调函数后返回 true,就立即返回。
/**
* @param {object[]} items
* @excludes { Array< {k: string, v: any} >} excludes
*/
/**
* @param {object[]} items
* @param { Array< {k: string, v: any} >} excludes
* @return {object[]}
*/
function excludeItems(items, excludes) {
const excludesMap = excludes.reduce((map, { k, v }) => {
if (!map.has(k)) {
map.set(k, new Set());
}
map.get(k).add(v);
return map;
}, new Map());
return items.filter(item => {
return !Object.keys(item).some(
key => excludesMap.has(key) && excludesMap.get(key).has(item[key])
);
});
}
JS 简答题
Promise.prototype.finally()
36. Promise.prototype.finally()
Promise.resolve(1)
.finally(data => {
console.log(data);
return Promise.reject('error');
})
.catch(error => {
console.log(error);
throw 'error2';
})
.finally(data => {
console.log(data);
return Promise.resolve(2).then(console.log);
})
.then(console.log)
.catch(console.log);
解析
finally(cb)回调函数 cb 不接收任何入参catch 里面抛出了一个错误,就不会走 then 了,直接走到 catch 捕获异常。如果最后没有 catch 的话,就会报错
postMessage
console.log(1);
window.onmessage = () => {
console.log(2);
};
Promise.resolve().then(() => {
console.log(3);
});
setTimeout(() => {
console.log(4);
}, 0);
console.log(5);
window.postMessage('');
console.log(6);
解析
执行顺序:
同步任务 statement
微任务 Promise
Web Worker window.eventHandle ...
setTimeout
if
if (true) {
function foo() {
console.log('BFE');
}
}
if (false) {
function bar() {
console.log('dev');
}
}
foo();
bar();
解析
当函数在 if-else块级作用域内声明,名称会被提升,但是定义仍在if-else块中。
Promise Order II
console.log(1);
setTimeout(() => {
console.log(2);
}, 10);
setTimeout(() => {
console.log(3);
}, 0);
new Promise((_, reject) => {
console.log(4);
reject(5);
console.log(6);
})
.then(() => console.log(7))
.catch(() => console.log(8))
.then(() => console.log(9))
.catch(() => console.log(10))
.then(() => console.log(11))
.then(console.log)
.finally(() => console.log(12));
console.log(13);
解析
关键点:
抛出异常后,给 catch 捕获到,能正常的往后执行,即还是会走 then
setTimeout 推入异步队列,执行的时候还是要注意 delay 的时间,不能一股脑的冲上往下执行
Hoisting V
(() => {
if (!fn) {
function fn() {
console.log('2');
}
}
fn();
})();
function fn() {
console.log('1');
}
// another one
function fn1() {
console.log('3');
}
(() => {
if (!fn1) {
function fn1() {
console.log('4');
}
}
fn1();
})()(
// another one !
() => {
if (false) {
function fn3() {
console.log('5');
}
}
fn3();
}
)();
解析
if 作用域的函数,声明会上浮,就会变成 var fn1 = undefined
name for Function expression
20. name for Function expression
function a() {}
const b = function() {};
const c = function d() {
console.log(typeof d);
d = 'e';
console.log(typeof d);
};
console.log(typeof a);
console.log(typeof b);
console.log(typeof c);
console.log(typeof d);
c();
解析
在命名函数 d 内,函数名称在函数内部不允许再赋值。在严格模式下,会报错Uncaught TypeError: Assignment to constant variable
override setter
class A {
val = 1;
get foo() {
return this.val;
}
}
class B {
val = 2;
set foo(val) {
this.val = val;
}
}
const a = new A();
const b = new B();
console.log(a.foo);
console.log(b.foo);
b.foo = 3;
console.log(b.val);
console.log(b.foo);
解析
b.foo,实例 b 下面并没有 foo 属性,return undefinedb.foo = 3,这里 setter 进行工作,将 val 改成 2。所以 b.val 为 2,但是仍然没有 getter foo 属性,所以 b.foo 仍不存在