手写算法: 杨辉三角

118. 杨辉三角open in new window

思路

  1. 杨辉三角的特点是,第 0 行 1 个元素,第 1 行 2 个元素,第 2 行 3 个元素,依次类推

  2. 同一行里首尾两个元素都是为 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;
};

手写题

找到第一个重复的字符

105. 找到第一个重复的字符open in new window

/**
 * @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

18. 优化一个 functionopen in new window

思路

理解题意:exclude 的意思是排除,在 items 里面排除 exclude 包含的内容,只要一项满足,就算满足条件。

  1. 用 map 储存 excludes 的内容,按照 items 的格式以 key-value 的形式存储。同是一类的即保存在一块。

  2. 遍历 items 筛选出未被排除的项目,判断 map 中是否存在对应的 key

  3. 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()open in new window

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);

解析

  1. finally(cb) 回调函数 cb 不接收任何入参

  2. catch 里面抛出了一个错误,就不会走 then 了,直接走到 catch 捕获异常。如果最后没有 catch 的话,就会报错

postMessage

60. postMessageopen in new window

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);

解析

执行顺序:

  1. 同步任务 statement

  2. 微任务 Promise

  3. Web Worker window.eventHandle ...

  4. setTimeout

if

67. ifopen in new window

if (true) {
  function foo() {
    console.log('BFE');
  }
}
if (false) {
  function bar() {
    console.log('dev');
  }
}

foo();
bar();

解析

当函数在 if-else块级作用域内声明,名称会被提升,但是定义仍在if-else块中。

Promise Order II

47. Promise Order IIopen in new window

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);

解析

关键点:

  1. 抛出异常后,给 catch 捕获到,能正常的往后执行,即还是会走 then

  2. setTimeout 推入异步队列,执行的时候还是要注意 delay 的时间,不能一股脑的冲上往下执行

Hoisting V

42. Hoisting Vopen in new window

(() => {
  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 expressionopen in new window

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

59. override setteropen in new window

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);

解析

  1. b.foo,实例 b 下面并没有 foo 属性,return undefined

  2. b.foo = 3,这里 setter 进行工作,将 val 改成 2。所以 b.val 为 2,但是仍然没有 getter foo 属性,所以 b.foo 仍不存在

Last Updated:
Contributors: kk