手写算法: 将有序数组转换为二叉搜索树

108. 将有序数组转换为二叉搜索树open in new window

思路

一个有序数组对于 BST 来说就是一个中序遍历的结果,跟节点在数组的中心,数组左侧是左子树元素,右侧是右子树元素。

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {number[]} nums
 * @return {TreeNode}
 */
var sortedArrayToBST = function(nums) {
  const buildTree = (nums, left, right) => {
    if (left > right) return null;

    const mid = left + ((right - left) >> 1);
    const root = new TreeNode(nums[mid]);
    root.left = buildTree(nums, left, mid - 1);
    root.right = buildTree(nums, mid + 1, right);
    return root;
  };
  return buildTree(nums, 0, nums.length - 1);
};

手写题: 压缩字符串

97. 压缩字符串open in new window

理解题意:这里是找连续的字符串,不是字符出现的次数

/**
 * @param {string} str
 * @return {string}
 */
function compress(str) {
  let result = [];
  let count = 0;

  for (let i = 0; i < str.length; i++) {
    count++;
    if (str[i] !== str[i + 1]) {
      result.push(str[i]);
      count > 1 && result.push(count);
      count = 0;
    }
  }
  return result.join('');
}

JS 简答题

method

51. methodopen in new window

// case 1
const obj1 = {
  foo() {
    console.log(super.foo());
  },
};

Object.setPrototypeOf(obj1, {
  foo() {
    return 'bar';
  },
});

obj1.foo();

// case 2
const obj2 = {
  foo: function() {
    console.log(super.foo());
  },
};

Object.setPrototypeOf(obj2, {
  foo() {
    return 'bar';
  },
});

obj2.foo();

解析

obj1 是Object的普通实例,它没有prototype属性,只有构造函数才具有prototype属性。实例只能拥有__proto__属性,指向由其构造函数的prototype

而,obj2 定义一个名为 foo 的属性,该属性是一个函数。【这是一个普通函数】

方法和普通函数之前的区别:

  1. 方法有个HomeObject(同源对象),这就是允许他们使用 super 的原因

  2. 方法没有构造器,不能被 new

  3. 在方法的作用域中,不能用方法名做绑定(与命名的函数表达式不同)

参考链接open in new window

try...catch

88. try...catchopen in new window

var a = 'a';
try {
  throw new Error('BFE.dev');
} catch {
  var a = 'a1';
}
console.log(a);

var b = 'b';
try {
  throw new Error('BFE.dev');
} catch (b) {
  var b = 'b1';
}
console.log(b);

var c = 'c';
try {
  throw new Error('BFE.dev');
} catch (error) {
  var c = 'c1';
}
console.log(c);

解析

try...catch语句,两块作用域,在 try 中跑出异常,会走到 catch 中。catch 传进来的值只能在 catch 作用域内使用。

// 全局变量a
var a = 'a';
try {
  throw new Error('BFE.dev');
} catch {
  // 覆盖全局变量a
  var a = 'a1';
}
console.log(a); // a1

// 全局变量b
var b = 'b';
try {
  throw new Error('BFE.dev');
} catch (b) {
  // 局部变量b,其实相当于定义多一个变量 var _b = 'b1',没有对全局变量b进行操作
  var b = 'b1';
}
console.log(b);

var c = 'c';
try {
  throw new Error('BFE.dev');
} catch (error) {
  var c = 'c1';
}
console.log(c); // 同a

reference type

64. reference typeopen in new window

const obj = {
  msg: 'BFE',
  foo() {
    console.log(this.msg);
  },
  bar() {
    console.log('dev');
  },
};

obj.foo();
obj.foo();
(obj.foo || obj.bar)();

解析

  1. obj.foo()(obj.foo)() 都是一个意思,作用域都是指向 obj

  2. (obj.foo || obj.bar)()()是一个分组运算符,先执行括号里面的。||表达式返回第一个真实的值,那么这里返回的是 obj.foo。 拿到的是匿名函数,作用域指向 window

Promise then callbacks II

4. Promise then callbacks IIopen in new window

Promise.resolve(1)
  .then(val => {
    console.log(val);
    return val + 1;
  })
  .then(val => {
    console.log(val);
  })
  .then(val => {
    console.log(val);
    return Promise.resolve(3).then(val => {
      console.log(val);
    });
  })
  .then(val => {
    console.log(val);
    return Promise.reject(4);
  })
  .catch(val => {
    console.log(val);
  })
  .finally(val => {
    console.log(val);
    return 10;
  })
  .then(val => {
    console.log(val);
  });

解析

  1. return 了值,接下来的 then 和 catch 才能接收到

  2. Promise.reject(),catch 和 finally 才能拿到,then 拿不到

  3. finally 的回调函数不接收任何参数,它仅用于无论最终结果如何都要执行的情况。不会对 Promise 产生影响,即不会影响后续的函数结果。

Promise.resolve(1)
  .then(val => {
    console.log(val); // 1
    return val + 1; // return 2
  })
  .then(val => {
    console.log(val); // 2
  })
  .then(val => {
    console.log(val); // undefined, 上一层没有传东西进来
    return Promise.resolve(3).then(val => {
      // return一个Promise
      console.log(val); // 3
    });
  })
  .then(val => {
    // 接受的是上一个Promise return出来的值,但是上一个Promise没有return东西出来
    console.log(val); // undefined
    return Promise.reject(4); // 执行Promise.reject(),catch能拿到,then拿不到
  })
  .catch(val => {
    console.log(val); // 4
  })
  .finally(val => {
    // 回调函数不接收入参
    console.log(val); // undefined
    return 10; // 不会对Promise产生影响
  })
  .then(val => {
    console.log(val); // undefined,拿不到finally return出来的,因为它finally不会对promise产生影响,传不进来
  });

zero

25. zeroopen in new window

console.log(1 / 0);
console.log(-1 / 0);
console.log(0 / 0);
console.log(0 === -0);
console.log(Object.is(0, -0));
console.log(Object.is(0, Math.round(-0.5)));
console.log(Object.is(0, Math.round(0.5)));
console.log(0 * Infinity);
console.log(Infinity / Infinity);
console.log(Object.is(0, Math.sign(0)));
console.log(Object.is(0, Math.sign(-0)));
console.log(1 / -0);
console.log(1 / 0);
console.log(1n / 0n);

解析

  • A / B, 被除数 / 除数,0 不能当除数,即 0 不能作为分母。任何数值除以 0,在数学中都会得到错误,这边 js 对以下做了两种情况:

    • 0 / 0, 会返回 NaN,这样不会影响程序的执行。

    • 非零有限值 / 0,返回 Infinity,至于有没有符号看被除数与除数。

  • Object.is()=== 不相同,差别是它们对待有符号的零和 NaN 不同。例如,=== 运算符(也包括 == 运算符)将数字 -0 和 +0 视为相等,而将 Number.NaNNaN 视为不相等。is 则与它们相反。

  • Math.round() 四舍五入,-0.5 向上进变成-0, 0.5 向上变成 1

  • ES 规定看大宝典open in new window:

    • 非零有限值 / 0,返回 Infinity
    • 0 * InfinityInfinity / Infinity, 返回 NaN

    【🔍 ==> 11.5.1 Applying the * Operator】

    • Multiplication of an infinity by a zero results in NaN.(无穷大乘以零会得到 NaN)

    【🔍 ==> 11.5.2 Applying the / Operator】

    • Division of an infinity by an infinity results in NaN. (无穷大除以无穷大导致 NaN)
    • Division of a zero by a zero results in NaN; division of zero by any other finite value results in zero, with the sign determined by the rule already stated above. (零除以零导致 NaN; 零除以任何其他有限值导致零,其符号由上述规则确定)
    • Division of a non-zero finite value by a zero results in a signed infinity. The sign is determined by the rule already stated above.(将非零有限值除以零,得到有符号无穷大)
  • Math.sign(),返回一个数字的符号,有 5 种返回值,分别是 1, -1, 0, -0, NaN. 代表的各是正数,负数,正零,负零,NaN。

  • BigInt类型不能除以 0

Last Updated:
Contributors: kk